🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: gnu.gcc.bug
Article #250

gmp 1.2 bug report and fix

#250
From: Lon Willett
Date: Mon, 03 Aug 1992 17:42
199 lines
8119 bytes
I just ported gmp 1.2 to my machine (relevant info: SparcStation ELC,
Sun OS 4.1.1, compiled with gcc 2.2.2, optimization -O2).

It failed its tests.  I tracked down the bug; a patch follows.

(BTW, I saw this reported as a compiler bug; thus the CC to bug-gcc).

The major problem is that the __asm__ macros in longlong.h don't
indicate that they modify the condition codes.  So when compiling with
"-fschedule-insns2" (or -O2), the classical multiply code in mpn_mul
comes out messed up.

I didn't look at the macros for any other machines; they may need
fixing too.

While debugging this, I noticed that the inner loop of the classical
multiply could be improved.  If you do a little arithmetic, you can
see that there is no need for the two (carry, no carry) versions of
the loop.  I believe my version (in the patch below) probably compiles
into faster code, and that it is easier to understand.

An erroneous (but harmless) type-cast in gmp-impl.h is also fixed.

--Lon Willett	(willett@math.utah.edu)
------------------------------------------------------------------------
*** gmp-impl.h.orig	Mon Dec  9 14:02:36 1991
--- gmp-impl.h	Mon Aug  3 01:56:08 1992
***************
*** 94,100 ****
  #define MPZ_TMP_INIT(X, NLIMBS) \
    do {									\
      (X)->alloc = (NLIMBS);						\
!     (X)->d = (mp_limb) alloca ((NLIMBS) * BYTES_PER_MP_LIMB);		\
    } while (0)
  
  /* Structure for conversion between internal binary format and
--- 94,100 ----
  #define MPZ_TMP_INIT(X, NLIMBS) \
    do {									\
      (X)->alloc = (NLIMBS);						\
!     (X)->d = (mp_limb *) alloca ((NLIMBS) * BYTES_PER_MP_LIMB);		\
    } while (0)
  
  /* Structure for conversion between internal binary format and
*** longlong.h.orig	Mon Dec  9 09:46:08 1991
--- longlong.h	Mon Aug  3 07:07:25 1992
***************
*** 511,533 ****
  	addx %2,%3,%0"							\
  	: "=r" ((unsigned long int)(sh)), "=&r" ((unsigned long int)(sl))\
  	: "%r" ((unsigned long int)(ah)), "rI" ((unsigned long int)(bh)),\
! 	  "%r" ((unsigned long int)(al)), "rI" ((unsigned long int)(bl)))
  #define sub_ddmmss(sh, sl, ah, al, bh, bl) \
    __asm__ ("subcc %4,%5,%1
  	subx %2,%3,%0"							\
  	: "=r" ((unsigned long int)(sh)), "=&r" ((unsigned long int)(sl))\
  	: "r" ((unsigned long int)(ah)), "rI" ((unsigned long int)(bh)),\
! 	  "r" ((unsigned long int)(al)), "rI" ((unsigned long int)(bl)))
  #if defined (__sparc8__)	/* How do we recog. version 8 SPARC?  */
  #define umul_ppmm(w1, w0, u, v) \
    __asm__ ("umul %2,%3,%1;rd %%y,%0"					\
  	: "=r" ((unsigned long int)(w1)), "=r" ((unsigned long int)(w0))\
! 	: "r" ((unsigned long int)(u)), "r" ((unsigned long int)(v)))
  #define udiv_qrnnd(q, r, n1, n0, d) \
    __asm__ ("mov %2,%%y;nop;nop;nop;udiv %3,%4,%0;umul %0,%4,%1;sub %3,%1,%1"\
  	: "=&r" ((unsigned long int)(q)), "=&r" ((unsigned long int)(r))\
  	: "r" ((unsigned long int)(n1)), "r" ((unsigned long int)(n0)),	\
! 	  "r" ((unsigned long int)(d)))
  #else
  /* SPARC without integer multiplication and divide instructions.
     (i.e. at least Sun4/20,40,60,65,75,110,260,280,330,360,380,470,490) */
--- 511,536 ----
  	addx %2,%3,%0"							\
  	: "=r" ((unsigned long int)(sh)), "=&r" ((unsigned long int)(sl))\
  	: "%r" ((unsigned long int)(ah)), "rI" ((unsigned long int)(bh)),\
! 	  "%r" ((unsigned long int)(al)), "rI" ((unsigned long int)(bl)) \
! 	: "cc")
  #define sub_ddmmss(sh, sl, ah, al, bh, bl) \
    __asm__ ("subcc %4,%5,%1
  	subx %2,%3,%0"							\
  	: "=r" ((unsigned long int)(sh)), "=&r" ((unsigned long int)(sl))\
  	: "r" ((unsigned long int)(ah)), "rI" ((unsigned long int)(bh)),\
! 	  "r" ((unsigned long int)(al)), "rI" ((unsigned long int)(bl)) \
! 	: "cc")
  #if defined (__sparc8__)	/* How do we recog. version 8 SPARC?  */
  #define umul_ppmm(w1, w0, u, v) \
    __asm__ ("umul %2,%3,%1;rd %%y,%0"					\
  	: "=r" ((unsigned long int)(w1)), "=r" ((unsigned long int)(w0))\
! 	: "r" ((unsigned long int)(u)), "r" ((unsigned long int)(v)) \
! 	: "cc")
  #define udiv_qrnnd(q, r, n1, n0, d) \
    __asm__ ("mov %2,%%y;nop;nop;nop;udiv %3,%4,%0;umul %0,%4,%1;sub %3,%1,%1"\
  	: "=&r" ((unsigned long int)(q)), "=&r" ((unsigned long int)(r))\
  	: "r" ((unsigned long int)(n1)), "r" ((unsigned long int)(n0)),	\
! 	  "r" ((unsigned long int)(d)) : "cc")
  #else
  /* SPARC without integer multiplication and divide instructions.
     (i.e. at least Sun4/20,40,60,65,75,110,260,280,330,360,380,470,490) */
***************
*** 574,580 ****
  	rd	%%y,%1"							\
  	: "=r" ((unsigned long int)(w1)), "=r" ((unsigned long int)(w0))\
  	: "%rI" ((unsigned long int)(u)), "r" ((unsigned long int)(v))	\
!        : "%g1", "%g2")
  #define UMUL_TIME 39		/* 39 instructions */
  /* It's quite necessary to add this much assembler for the sparc.
     The default udiv_qrnnd (in C) is more than 10 times slower!  */
--- 577,583 ----
  	rd	%%y,%1"							\
  	: "=r" ((unsigned long int)(w1)), "=r" ((unsigned long int)(w0))\
  	: "%rI" ((unsigned long int)(u)), "r" ((unsigned long int)(v))	\
!        : "%g1", "%g2", "cc")
  #define UMUL_TIME 39		/* 39 instructions */
  /* It's quite necessary to add this much assembler for the sparc.
     The default udiv_qrnnd (in C) is more than 10 times slower!  */
***************
*** 605,611 ****
  	! End of inline udiv_qrnnd"					\
  	: "=r&" ((unsigned long int)(q)), "=r&" ((unsigned long int)(r))\
  	: "r" ((unsigned long int)(d)), "1" ((unsigned long int)(n1)),	\
! 	  "0" ((unsigned long int)(n0)) : "%g1")
  #define UDIV_TIME (3+7*32)	/* 7 instructions/iteration. 32 iterations. */
  #endif
  #endif /* __sparc8__ */
--- 608,614 ----
  	! End of inline udiv_qrnnd"					\
  	: "=r&" ((unsigned long int)(q)), "=r&" ((unsigned long int)(r))\
  	: "r" ((unsigned long int)(d)), "1" ((unsigned long int)(n1)),	\
! 	  "0" ((unsigned long int)(n0)) : "%g1", "cc")
  #define UDIV_TIME (3+7*32)	/* 7 instructions/iteration. 32 iterations. */
  #endif
  #endif /* __sparc8__ */
*** mpn_mul.c.orig	Mon Nov  4 10:50:52 1991
--- mpn_mul.c	Mon Aug  3 07:15:01 1992
***************
*** 150,192 ****
  	  cy_limb = 0;
  	  j = -usize;
  
! 	  /* Inner loops.  Simulate the carry flag by jumping between
! 	     these loops.  The first is used when there was no carry
! 	     in the previois iteration; the second when there was carry.  */
! 
! 	  do
! 	    {
! 	      umul_ppmm (prod_high, prod_low, up[j], v_limb);
! 	      add_ssaaaa (cy_limb, prod_low, prod_high, prod_low, 0, cy_limb);
! 	      c = prodp[j];
! 	      prod_low += c;
! 	      prodp[j] = prod_low;
! 	      if (prod_low < c)
! 		goto cy_loop;
! 	    ncy_loop:
! 	      j++;
! 	    }
! 	  while (j < 0);
! 
! 	  prodp[j] = cy_limb;
! 	  prodp++;
! 	  continue;
! 
  	  do
  	    {
  	      umul_ppmm (prod_high, prod_low, up[j], v_limb);
  	      add_ssaaaa (cy_limb, prod_low, prod_high, prod_low, 0, cy_limb);
  	      c = prodp[j];
! 	      prod_low += c + 1;
! 	      prodp[j] = prod_low;
! 	      if (prod_low > c)
! 		goto ncy_loop;
! 	    cy_loop:
  	      j++;
  	    }
  	  while (j < 0);
  
- 	  cy_limb += 1;
  	  prodp[j] = cy_limb;
  	  prodp++;
  	}
--- 150,167 ----
  	  cy_limb = 0;
  	  j = -usize;
  
! 	  /* Inner loop */
  	  do
  	    {
  	      umul_ppmm (prod_high, prod_low, up[j], v_limb);
  	      add_ssaaaa (cy_limb, prod_low, prod_high, prod_low, 0, cy_limb);
  	      c = prodp[j];
! 	      if ((prodp[j] += prod_low) < c)
! 		cy_limb++;	/* NB: can't overflow */
  	      j++;
  	    }
  	  while (j < 0);
  
  	  prodp[j] = cy_limb;
  	  prodp++;
  	}
------------------------------------------------------------------------
Technical Details
Message-ID: <9208031742.AA14191@holly>
Path: arc1-ca.pugleaf.net!sparky!uunet!cis.ohio-state.edu!softt.UUCP!lon

Show Full Headers
Complete Article Headers
Newsgroups: gnu.gcc.bug
Path: arc1-ca.pugleaf.net!sparky!uunet!cis.ohio-state.edu!softt.UUCP!lon
From: lon@softt.UUCP (Lon Willett)
Subject: gmp 1.2 bug report and fix
Message-ID: <9208031742.AA14191@holly>
Sender: gnulists@ai.mit.edu
Organization: GNUs Not Usenet
Distribution: gnu
Date: Mon, 3 Aug 1992 17:42:24 GMT
Approved: bug-gcc@prep.ai.mit.edu
Lines: 200