This is the mail archive of the libc-alpha@sources.redhat.com 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]

soft-fp fixes


Hi Guys.

I have been working on hacking glibc to provide a completely
soft-float implementation (exceptions, rounding, and all) for the
PowerPC port.

I'm submitting the patches today.  However, I'd like to post the patch
below independently since it affects other targets, and since it was
writted by Richard Henderson, not me.

Richard was kind enough to fix two bugs I found while implementing the
completely soft-float patches.  One relates to soft multiplication
loosing the carry bit.  The other is an iterative implementation of
division, since gcc's longlong.h udiv_qrnnd(?) is broken.

I have tested this patch, along with the upcoming ones on ppc32 linux
with:

	1. glibc's make check
	2. paranoia
	3. spec2000 C floating point benchmarks

Is this ok?

2002-10-08  Richard Henderson  <rth@redhat.com>

	* soft-fp/op-4.h: Handle carry correctly in
	__FP_FRAC_ADD_3, __FP_FRAC_ADD_4, __FP_FRAC_SUB_3,
	__FP_FRAC_SUB_4, __FP_FRAC_DEC_3, __FP_FRAC_DEC_4.
	* soft-fp/op-common.h: New macros _FP_DIV_MEAT_N_loop,

Index: soft-fp/op-4.h
===================================================================
RCS file: /cvs/glibc/libc/soft-fp/op-4.h,v
retrieving revision 1.4
diff -c -p -r1.4 op-4.h
*** soft-fp/op-4.h	11 Jul 2002 03:12:31 -0000	1.4
--- soft-fp/op-4.h	8 Oct 2002 18:04:42 -0000
***************
*** 510,567 ****
    (X##_f[3] = I3, X##_f[2] = I2, X##_f[1] = I1, X##_f[0] = I0)
  
  #ifndef __FP_FRAC_ADD_3
! #define __FP_FRAC_ADD_3(r2,r1,r0,x2,x1,x0,y2,y1,y0)			\
!   (r0 = x0 + y0,							\
!    r1 = x1 + y1 + (r0 < x0),						\
!    r2 = x2 + y2 + (r1 < x1))
  #endif
  
  #ifndef __FP_FRAC_ADD_4
! #define __FP_FRAC_ADD_4(r3,r2,r1,r0,x3,x2,x1,x0,y3,y2,y1,y0)		\
!   (r0 = x0 + y0,							\
!    r1 = x1 + y1 + (r0 < x0),						\
!    r2 = x2 + y2 + (r1 < x1),						\
!    r3 = x3 + y3 + (r2 < x2))
  #endif
  
  #ifndef __FP_FRAC_SUB_3
! #define __FP_FRAC_SUB_3(r2,r1,r0,x2,x1,x0,y2,y1,y0)			\
!   (r0 = x0 - y0,							\
!    r1 = x1 - y1 - (r0 > x0),						\
!    r2 = x2 - y2 - (r1 > x1))
  #endif
  
  #ifndef __FP_FRAC_SUB_4
! #define __FP_FRAC_SUB_4(r3,r2,r1,r0,x3,x2,x1,x0,y3,y2,y1,y0)		\
!   (r0 = x0 - y0,							\
!    r1 = x1 - y1 - (r0 > x0),						\
!    r2 = x2 - y2 - (r1 > x1),						\
!    r3 = x3 - y3 - (r2 > x2))
  #endif
  
  #ifndef __FP_FRAC_DEC_3
  #define __FP_FRAC_DEC_3(x2,x1,x0,y2,y1,y0)				\
    do {									\
!     UWtype _t0, _t1;							\
!     _t0 = x0;								\
!     x0 -= y0;								\
!     _t1 = x1;								\
!     x1 -= y1 + (x0 > _t0);						\
!     x2 -= y2 + (x1 > _t1);						\
    } while (0)
  #endif
  
  #ifndef __FP_FRAC_DEC_4
  #define __FP_FRAC_DEC_4(x3,x2,x1,x0,y3,y2,y1,y0)			\
    do {									\
!     UWtype _t0, _t1;							\
!     _t0 = x0;								\
!     x0 -= y0;								\
!     _t1 = x1;								\
!     x1 -= y1 + (x0 > _t0);						\
!     _t0 = x2;								\
!     x2 -= y2 + (x1 > _t1);						\
!     x3 -= y3 + (x2 > _t0);						\
    } while (0)
  #endif
  
--- 510,593 ----
    (X##_f[3] = I3, X##_f[2] = I2, X##_f[1] = I1, X##_f[0] = I0)
  
  #ifndef __FP_FRAC_ADD_3
! #define __FP_FRAC_ADD_3(r2,r1,r0,x2,x1,x0,y2,y1,y0)		\
!   do {								\
!     int _c1, _c2;							\
!     r0 = x0 + y0;						\
!     _c1 = r0 < x0;						\
!     r1 = x1 + y1;						\
!     _c2 = r1 < x1;						\
!     r1 += _c1;							\
!     _c2 |= r1 < _c1;						\
!     r2 = x2 + y2 + _c2;						\
!   } while (0)
  #endif
  
  #ifndef __FP_FRAC_ADD_4
! #define __FP_FRAC_ADD_4(r3,r2,r1,r0,x3,x2,x1,x0,y3,y2,y1,y0)	\
!   do {								\
!     int _c1, _c2, _c3;						\
!     r0 = x0 + y0;						\
!     _c1 = r0 < x0;						\
!     r1 = x1 + y1;						\
!     _c2 = r1 < x1;						\
!     r1 += _c1;							\
!     _c2 |= r1 < _c1;						\
!     r2 = x2 + y2;						\
!     _c3 = r2 < x2;						\
!     r2 += _c2;							\
!     _c3 |= r2 < _c2;						\
!     r3 = x3 + y3 + _c3;						\
!   } while (0)
  #endif
  
  #ifndef __FP_FRAC_SUB_3
! #define __FP_FRAC_SUB_3(r2,r1,r0,x2,x1,x0,y2,y1,y0)		\
!   do {								\
!     int _c1, _c2;							\
!     r0 = x0 - y0;						\
!     _c1 = r0 > x0;						\
!     r1 = x1 - y1;						\
!     _c2 = r1 > x1;						\
!     r1 -= _c1;							\
!     _c2 |= r1 > _c1;						\
!     r2 = x2 - y2 - _c2;						\
!   } while (0)
  #endif
  
  #ifndef __FP_FRAC_SUB_4
! #define __FP_FRAC_SUB_4(r3,r2,r1,r0,x3,x2,x1,x0,y3,y2,y1,y0)	\
!   do {								\
!     int _c1, _c2, _c3;						\
!     r0 = x0 - y0;						\
!     _c1 = r0 > x0;						\
!     r1 = x1 - y1;						\
!     _c2 = r1 > x1;						\
!     r1 -= _c1;							\
!     _c2 |= r1 > _c1;						\
!     r2 = x2 - y2;						\
!     _c3 = r2 > x2;						\
!     r2 -= _c2;							\
!     _c3 |= r2 > _c2;						\
!     r3 = x3 - y3 - _c3;						\
!   } while (0)
  #endif
  
  #ifndef __FP_FRAC_DEC_3
  #define __FP_FRAC_DEC_3(x2,x1,x0,y2,y1,y0)				\
    do {									\
!     UWtype _t0, _t1, _t2;						\
!     _t0 = x0, _t1 = x1, _t2 = x2;					\
!     __FP_FRAC_SUB_3 (x2, x1, x0, _t2, _t1, _t0, y2, y1, y0);		\
    } while (0)
  #endif
  
  #ifndef __FP_FRAC_DEC_4
  #define __FP_FRAC_DEC_4(x3,x2,x1,x0,y3,y2,y1,y0)			\
    do {									\
!     UWtype _t0, _t1, _t2, _t3;						\
!     _t0 = x0, _t1 = x1, _t2 = x2, _t3 = x3;				\
!     __FP_FRAC_SUB_4 (x3,x2,x1,x0,_t3,_t2,_t1,_t0, y3,y2,y1,y0);		\
    } while (0)
  #endif
  
Index: soft-fp/op-common.h
===================================================================
RCS file: /cvs/glibc/libc/soft-fp/op-common.h,v
retrieving revision 1.3
diff -c -p -r1.3 op-common.h
*** soft-fp/op-common.h	21 May 2002 02:13:43 -0000	1.3
--- soft-fp/op-common.h	8 Oct 2002 18:04:45 -0000
*************** do {									\
*** 766,768 ****
--- 766,812 ----
      q = n / d, r = n % d;			\
    } while (0)
  
+ 
+ /* A restoring bit-by-bit division primitive.  */
+ 
+ #define _FP_DIV_MEAT_N_loop(fs, wc, R, X, Y)				\
+   do {									\
+     int count = _FP_WFRACBITS_##fs;					\
+     _FP_FRAC_DECL_##wc (u);						\
+     _FP_FRAC_DECL_##wc (v);						\
+     _FP_FRAC_COPY_##wc (u, X);						\
+     _FP_FRAC_COPY_##wc (v, Y);						\
+     _FP_FRAC_SET_##wc (R, _FP_ZEROFRAC_##wc);				\
+     /* Normalize U and V.  */						\
+     _FP_FRAC_SLL_##wc (u, _FP_WFRACXBITS_##fs);				\
+     _FP_FRAC_SLL_##wc (v, _FP_WFRACXBITS_##fs);				\
+     /* First round.  Since the operands are normalized, either the	\
+        first or second bit will be set in the fraction.  Produce a	\
+        normalized result by checking which and adjusting the loop	\
+        count and exponent accordingly.  */				\
+     if (_FP_FRAC_GE_1 (u, v))						\
+       {									\
+ 	_FP_FRAC_SUB_##wc (u, u, v);					\
+ 	_FP_FRAC_LOW_##wc (R) |= 1;					\
+ 	count--;							\
+       }									\
+     else								\
+       R##_e--;								\
+     /* Subsequent rounds.  */						\
+     do {								\
+       int msb = (_FP_WS_TYPE) _FP_FRAC_HIGH_##wc (u) < 0;		\
+       _FP_FRAC_SLL_##wc (u, 1);						\
+       _FP_FRAC_SLL_##wc (R, 1);						\
+       if (msb || _FP_FRAC_GE_1 (u, v))					\
+ 	{								\
+ 	  _FP_FRAC_SUB_##wc (u, u, v);					\
+ 	  _FP_FRAC_LOW_##wc (R) |= 1;					\
+ 	}								\
+     } while (--count > 0);						\
+     /* If there's anything left in U, the result is inexact.  */	\
+     _FP_FRAC_LOW_##wc (R) |= !_FP_FRAC_ZEROP_##wc (u);			\
+   } while (0)
+ 
+ #define _FP_DIV_MEAT_1_loop(fs, R, X, Y)  _FP_DIV_MEAT_N_loop (fs, 1, R, X, Y)
+ #define _FP_DIV_MEAT_2_loop(fs, R, X, Y)  _FP_DIV_MEAT_N_loop (fs, 2, R, X, Y)
+ #define _FP_DIV_MEAT_4_loop(fs, R, X, Y)  _FP_DIV_MEAT_N_loop (fs, 4, R, X, Y)


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