Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/arch/powerpc/fpu Further fix for fcti{w,d}{,z}.
details: https://anonhg.NetBSD.org/src/rev/89e042ecf777
branches: trunk
changeset: 369786:89e042ecf777
user: rin <rin%NetBSD.org@localhost>
date: Thu Sep 01 05:56:52 2022 +0000
description:
Further fix for fcti{w,d}{,z}.
- Treat {Q,S}NaN correctly.
- Set exception bits appropriately.
- Introduce round_int().
diffstat:
sys/arch/powerpc/fpu/fpu_implode.c | 111 ++++++++++++++++++++----------------
1 files changed, 61 insertions(+), 50 deletions(-)
diffs (183 lines):
diff -r b4fbd12af1e6 -r 89e042ecf777 sys/arch/powerpc/fpu/fpu_implode.c
--- a/sys/arch/powerpc/fpu/fpu_implode.c Thu Sep 01 05:51:51 2022 +0000
+++ b/sys/arch/powerpc/fpu/fpu_implode.c Thu Sep 01 05:56:52 2022 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: fpu_implode.c,v 1.11 2022/09/01 05:51:51 rin Exp $ */
+/* $NetBSD: fpu_implode.c,v 1.12 2022/09/01 05:56:52 rin Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -46,7 +46,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: fpu_implode.c,v 1.11 2022/09/01 05:51:51 rin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: fpu_implode.c,v 1.12 2022/09/01 05:56:52 rin Exp $");
#include <sys/types.h>
#include <sys/systm.h>
@@ -62,6 +62,7 @@
static int round(struct fpemu *, struct fpn *);
static int toinf(struct fpemu *, int);
+static int round_int(struct fpn *, int *, int, int, int);
/*
* Round a number (algorithm from Motorola MC68882 manual, modified for
@@ -189,6 +190,40 @@
return (inf);
}
+static int
+round_int(struct fpn *fp, int *cx, int rn, int sign, int odd)
+{
+ int g, rs;
+
+ g = fp->fp_mant[3] & 0x80000000;
+ rs = (fp->fp_mant[3] & 0x7fffffff) | fp->fp_sticky;
+
+ if ((g | rs) == 0)
+ return 0; /* exact */
+
+ *cx |= FPSCR_XX | FPSCR_FI;
+
+ switch (rn) {
+ case FSR_RD_RN:
+ if (g && (rs | odd))
+ break;
+ return 0;
+ case FSR_RD_RZ:
+ return 0;
+ case FSR_RD_RP:
+ if (!sign)
+ break;
+ return 0;
+ case FSR_RD_RM:
+ if (sign)
+ break;
+ return 0;
+ }
+
+ *cx |= FPSCR_FR;
+ return 1;
+}
+
/*
* fpn -> int (int value returned as return value).
*/
@@ -196,10 +231,17 @@
fpu_ftoi(struct fpemu *fe, struct fpn *fp, int rn)
{
u_int i;
- int sign, exp, g, rs;
+ int sign, exp, cx;
sign = fp->fp_sign;
+ cx = 0;
switch (fp->fp_class) {
+ case FPC_SNAN:
+ fe->fe_cx |= FPSCR_VXSNAN;
+ /* FALLTHROUGH */
+ case FPC_QNAN:
+ sign = 1;
+ break;
case FPC_ZERO:
return (0);
@@ -218,34 +260,15 @@
if ((exp = fp->fp_exp) >= 32)
break;
/* NB: the following includes exp < 0 cases */
- if (fpu_shr(fp, FP_NMANT - 32 - 1 - exp) != 0)
- fe->fe_cx |= FPSCR_UX;
+ (void)fpu_shr(fp, FP_NMANT - 32 - 1 - exp);
i = fp->fp_mant[2];
-
- g = fp->fp_mant[3] & 0x80000000;
- rs = (fp->fp_mant[3] & 0x7fffffff) | fp->fp_sticky;
- switch (rn) {
- case FSR_RD_RN:
- if (g && (rs | (i & 1)))
- i++;
- break;
- case FSR_RD_RZ:
- break;
- case FSR_RD_RP:
- if (!sign && (g | rs))
- i++;
- break;
- case FSR_RD_RM:
- if (sign && (g | rs))
- i++;
- break;
- }
-
+ i += round_int(fp, &cx, rn, sign, i & 1);
if (i >= ((u_int)0x80000000 + sign))
break;
+ fe->fe_cx |= cx;
return (sign ? -i : i);
- default: /* Inf, qNaN, sNaN */
+ case FPC_INF:
break;
}
/* overflow: replace any inexact exception with invalid */
@@ -260,10 +283,17 @@
fpu_ftox(struct fpemu *fe, struct fpn *fp, int rn)
{
uint64_t i;
- int sign, exp, g, rs;
+ int sign, exp, cx;
sign = fp->fp_sign;
+ cx = 0;
switch (fp->fp_class) {
+ case FPC_SNAN:
+ fe->fe_cx |= FPSCR_VXSNAN;
+ /* FALLTHROUGH */
+ case FPC_QNAN:
+ sign = 1;
+ break;
case FPC_ZERO:
return (0);
@@ -282,34 +312,15 @@
if ((exp = fp->fp_exp) >= 64)
break;
/* NB: the following includes exp < 0 cases */
- if (fpu_shr(fp, FP_NMANT - 32 - 1 - exp) != 0)
- fe->fe_cx |= FPSCR_UX;
+ (void)fpu_shr(fp, FP_NMANT - 32 - 1 - exp);
i = ((uint64_t)fp->fp_mant[1] << 32) | fp->fp_mant[2];
-
- g = fp->fp_mant[3] & 0x80000000;
- rs = (fp->fp_mant[3] & 0x7fffffff) | fp->fp_sticky;
- switch (rn) {
- case FSR_RD_RN:
- if (g && (rs | (i & 1)))
- i++;
- break;
- case FSR_RD_RZ:
- break;
- case FSR_RD_RP:
- if (!sign && (g | rs))
- i++;
- break;
- case FSR_RD_RM:
- if (sign && (g | rs))
- i++;
- break;
- }
-
+ i += round_int(fp, &cx, rn, sign, i & 1);
if (i >= ((uint64_t)0x8000000000000000LL + sign))
break;
+ fe->fe_cx |= cx;
return (sign ? -i : i);
- default: /* Inf, qNaN, sNaN */
+ case FPC_INF:
break;
}
/* overflow: replace any inexact exception with invalid */
Home |
Main Index |
Thread Index |
Old Index