Thread View: gnu.gcc.bug
1 messages
1 total messages
Started by Lon Willett
Mon, 03 Aug 1992 17:42
gmp 1.2 bug report and fix
Author: 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++;
}
------------------------------------------------------------------------
Thread Navigation
This is a paginated view of messages in the thread with full content displayed inline.
Messages are displayed in chronological order, with the original post highlighted in green.
Use pagination controls to navigate through all messages in large threads.
Back to All Threads