Article View: gnu.gcc.bug
Article #250gmp 1.2 bug report and fix
From: Lon Willett
Date: Mon, 03 Aug 1992 17:42
Date: Mon, 03 Aug 1992 17:42
199 lines
8119 bytes
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!lonShow 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