This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] soft-fp handling of underflow


Joseph, I'd really appreciate it if you took a look at this.

We need to distinguish two cases for underflow:

1) Merely having a "tiny" result.  This means that we have
   a subnormal (exponent is zero, significand is non-zero)
   but we are able to fully represent the value.

2) The result is "tiny" and we also have a loss of precision.

If underflow exception traps are enabled in the FPU control register,
condition #1 is sufficient for signalling underflow.

If underflow exceptions traps are NOT enabled, we must satisfy #2 in
order to signal underflow.

Also, when underflow or overflow traps are enabled, such conditions
will set one and only one exception condition (the underflow or
overflow) and not signal inexact.  This trap reporting detail seems
very much like it will be chip specific, and therefore I did not
encode this rule into the common code.  I've left it to the
FP_HANDLE_EXCEPTIONS macro, and that's where I take care of this on
sparc.

As you have asked, I've taken care of the semi-RAW packing macro.  I
think I have a handle on this side but I need your help.

It seems like subnormal handling is split between the actual FPU
operations and the packing.  For example, underflowing to subnormal
is handled in the tail of the subtraction code in _FP_ADD_INTERNAL.

I think we can make this work for semiraw if the code doing the FP
calculations sets FP_EX_INEXACT when a loss of precision actually
happens.  Merely ending up with a subnormal should not trigger
FP_EX_INEXACT.

Once that is done correctly, the code I add in the patch below will
set underflow under the correct set of circumstances as detailed
above.

I briefly looked over the calculations that operate on semiraw encoded
values and the only case that pops out at me is the sub3: label code
in _FP_ADD_INTERNAL.  I think we need to detect when bits of precision
are actually lost and signal FP_EX_INEXACT in such cases.  Or is that
never possible here for some reason?

While working on this aspect, I also noticed FP_EX_DENORM.  It's main
usage seems to be to set the "denormal operand" exception on x86 and
ia64 in the libgcc copy.

But in glibc-ports I notice the only user is powerpc which defines
FP_EX_DENORM to FP_EX_UNDERFLOW.  This seems like some kind of crutch
for underflow exception generation in soft-fp.  I suspect that, after
my patch, if this powerpc definition of FP_EX_DENORM is removed and
the port is given a proper definition of FP_TRAPPING_EXCEPTIONS,
underflow signalling will work properly on powerpc.  And, it would
seem, much less code would be generated since all the FP_EX_DENORM
setting code would evaluate to nothing.

diff --git a/soft-fp/op-common.h b/soft-fp/op-common.h
index b70026f..c752c18 100644
--- a/soft-fp/op-common.h
+++ b/soft-fp/op-common.h
@@ -146,7 +146,11 @@ do {								\
   if (!_FP_EXP_NORMAL(fs, wc, X) && !_FP_FRAC_ZEROP_##wc(X))	\
     {								\
       if (X##_e == 0)						\
-	FP_SET_EXCEPTION(FP_EX_UNDERFLOW);			\
+	{							\
+	  if ((FP_CUR_EXCEPTIONS & FP_EX_INEXACT)		\
+	      || (FP_TRAPPING_EXCEPTIONS & FP_EX_UNDERFLOW))	\
+	    FP_SET_EXCEPTION(FP_EX_UNDERFLOW);			\
+	}							\
       else							\
 	{							\
 	  if (!_FP_KEEPNANFRACP)				\
@@ -226,13 +230,16 @@ do {								\
 	      {							\
 	        X##_e = 1;					\
 	        _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc);	\
+		FP_SET_EXCEPTION(FP_EX_INEXACT);		\
 	      }							\
 	    else						\
 	      {							\
 		X##_e = 0;					\
 		_FP_FRAC_SRL_##wc(X, _FP_WORKBITS);		\
-		FP_SET_EXCEPTION(FP_EX_UNDERFLOW);		\
 	      }							\
+	    if ((FP_CUR_EXCEPTIONS & FP_EX_INEXACT)		\
+		|| (FP_TRAPPING_EXCEPTIONS & FP_EX_UNDERFLOW))	\
+	      FP_SET_EXCEPTION(FP_EX_UNDERFLOW);		\
 	  }							\
 	else							\
 	  {							\
diff --git a/soft-fp/soft-fp.h b/soft-fp/soft-fp.h
index 46cb1cf..750c7fe 100644
--- a/soft-fp/soft-fp.h
+++ b/soft-fp/soft-fp.h
@@ -128,6 +128,13 @@
 #define FP_CLEAR_EXCEPTIONS				\
   _fex = 0
 
+#define FP_CUR_EXCEPTIONS				\
+  (_fex)
+
+#ifndef FP_TRAPPING_EXCEPTIONS
+#define FP_TRAPPING_EXCEPTIONS 0
+#endif
+
 #define _FP_ROUND_NEAREST(wc, X)			\
 do {							\
     if ((_FP_FRAC_LOW_##wc(X) & 15) != _FP_WORK_ROUND)	\
diff --git a/sysdeps/sparc/sparc32/soft-fp/sfp-machine.h b/sysdeps/sparc/sparc32/soft-fp/sfp-machine.h
index 4314082..f1fef3e 100644
--- a/sysdeps/sparc/sparc32/soft-fp/sfp-machine.h
+++ b/sysdeps/sparc/sparc32/soft-fp/sfp-machine.h
@@ -192,6 +192,7 @@ do {								\
   _FPU_GETCW(_fcw);						\
 } while (0)
 
+#define FP_TRAPPING_EXCEPTIONS ((_fcw >> 23) & 0x1f)
 #define FP_INHIBIT_RESULTS ((_fcw >> 23) & _fex)
 
 /* Simulate exceptions using double arithmetics. */
diff --git a/sysdeps/sparc/sparc64/soft-fp/sfp-machine.h b/sysdeps/sparc/sparc64/soft-fp/sfp-machine.h
index 36f92d6..ba9e8b9 100644
--- a/sysdeps/sparc/sparc64/soft-fp/sfp-machine.h
+++ b/sysdeps/sparc/sparc64/soft-fp/sfp-machine.h
@@ -100,6 +100,7 @@ do {								\
   _FPU_GETCW(_fcw);						\
 } while (0)
 
+#define FP_TRAPPING_EXCEPTIONS ((_fcw >> 23) & 0x1f)
 #define FP_INHIBIT_RESULTS ((_fcw >> 23) & _fex)
 
 /* Simulate exceptions using double arithmetics. */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]