home *** CD-ROM | disk | FTP | other *** search
- /* More subroutines needed by GCC output code on some machines. */
- /* Compile this one with gcc. */
- /* Copyright (C) 1989, 1990 Free Software Foundation, Inc.
-
- This file is part of GNU CC.
-
- GNU CC is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 1, or (at your option)
- any later version.
-
- GNU CC is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GNU CC; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
- /* As a special exception, if you link this library with files
- compiled with GCC to produce an executable, this does not cause
- the resulting executable to be covered by the GNU General Public License.
- This exception does not however invalidate any other reasons why
- the executable file might be covered by the GNU General Public License. */
-
- #include "config.h"
- #include <stddef.h>
-
- /* In case config.h defined it. */
- #undef abort
-
- #ifndef LONG_TYPE_SIZE
- #define LONG_TYPE_SIZE (sizeof (long) * BITS_PER_UNIT)
- #endif
-
- #ifndef SItype
- #define SItype long int
- #endif
-
- /* long long ints are pairs of long ints in the order determined by
- WORDS_BIG_ENDIAN. */
-
- #if WORDS_BIG_ENDIAN
- struct longlong {long high, low;};
- #else
- struct longlong {long low, high;};
- #endif
-
- /* We need this union to unpack/pack longlongs, since we don't have
- any arithmetic yet. Incoming long long parameters are stored
- into the `ll' field, and the unpacked result is read from the struct
- longlong. */
-
- typedef union
- {
- struct longlong s;
- long long ll;
- } long_long;
-
- /* Internally, long long ints are strings of unsigned shorts in the
- order determined by BYTES_BIG_ENDIAN. */
-
- #define B (1 << (LONG_TYPE_SIZE / 2))
- #define lowpart(t) ((unsigned long) (t) % B)
- #define highpart(t) ((unsigned long) (t) / B)
-
-
- /* Define auxilliary functions for multiplication and division.
- 1) __umulsidi3(a,b) multiplies two unsigned long integers A and B,
- and returns a long long product.
- 2) div_qrnnd(q,r,n1,n0,d) divides a long long integer, composed by the
- long integers N1 and N0, by D and places the quotient in Q and the
- remainder in R. If N1 >= D the quotient cannot be represented, and
- the result is undefined.
-
- There's a simple machine instruction for these operations on almost
- all CPUs. Use them! */
-
- #if defined (L_udivdi3) || defined (L_muldi3)
-
- #if defined (__mc68020__)
- #define __umulsidi3(u, v) \
- ({long_long __w; \
- asm ("mulul %3,%1:%0" : "=d" (__w.s.low), "=d" (__w.s.high) \
- : "%0" (u), "dmsK" (v)); \
- __w.ll; \
- })
- #define div_qrnnd(q, r, n1, n0, d) \
- asm ("divul %4,%1:%0" : "=d" (q), "=d" (r) : "0" (n0), "1" (n1), "dmsK" (d))
-
- #elif defined (sparc)
- unsigned long long __umulsidi3 () asm (".umul");
-
- #elif defined (ns32000)
- /* Try:
- #define __umulsidi3(u, v) \
- ({long long __w; \
- asm ("meid %2,%0" : "=g" (__w) : "%0" (u), "g" (v)); __w; \
- })
- */
- #define __umulsidi3(u, v) \
- ({long_long __w; \
- asm ("movd %2,r0; meid %3,r0; movd r0,%0; movd r1,%1" \
- : "=g" (__w.s.low), "=g" (__w.s.high) \
- : "g" (u), "g" (v) \
- : "r0", "r1"); __w.ll; \
- })
- #define div_qrnnd(q, r, n1, n0, d) \
- ({ \
- asm ("movd %1,r0; movd %2,r1; deid %3,r0; movd r1,%0" \
- : "=g" (q) : "g" (n0), "g" (n1), "g" (d) : "r0", "r1"); \
- asm ("movd %1,r0; movd %2,r1; deid %3,r0; movd r0,%0" \
- : "=g" (r) : "g" (n0), "g" (n1), "g" (d) : "r0", "r1"); \
- })
-
- #elif defined (__i386__)
- #define __umulsidi3(u, v) \
- ({long_long __w; \
- asm ("mull %3" : "=a" (__w.s.low), "=d" (__w.s.high) \
- : "%0" (u), "rm" (v)); __w.ll; \
- })
- #define div_qrnnd(quo, rem, n1, n0, den) \
- asm ("divl %4" : "=a" (quo), "=d" (rem) : "0" (n0), "1" (n1), "rm" (den))
-
- #endif
-
- /* If this machine has no inline assembler, use the C function. */
- #if !defined (__umulsidi3)
- static inline unsigned long long
- __umulsidi3 (u, v)
- unsigned long u, v;
- {
- unsigned long x0, x1, x2, x3;
- unsigned long ulow, vlow, uhigh, vhigh;
- long_long w;
-
- ulow = lowpart (u);
- uhigh = highpart (u);
- vlow = lowpart (v);
- vhigh = highpart (v);
-
- x0 = ulow * vlow;
- x1 = ulow * vhigh + highpart (x0);
- x2 = uhigh * vlow;
- x3 = uhigh * vhigh;
-
- x1 += x2;
- if (x1 < x2)
- x3 += B;
-
- w.s.high = x3 + highpart (x1);
- w.s.low = lowpart (x1) * B + lowpart (x0);
-
- return w.ll;
- }
- #endif
-
- #if !defined (div_qrnnd)
-
- /* Defined as a macro because of the two output parameters. */
- #define div_qrnnd(q, r, n1, n0, d) \
- ({ \
- unsigned int __d1, __d0, __q1, __q0; \
- unsigned long __r1, __r0, __m; \
- __d1 = highpart (d); \
- __d0 = lowpart (d); \
- __r1 = (n1) % __d1; \
- __q1 = (n1) / __d1; \
- __m = (unsigned long) __q1 * __d0; \
- __r1 = __r1 * B | highpart (n0); \
- while (__r1 < __m) \
- __q1--, __r1 += (d); \
- __r0 = __r1 % __d1; \
- __q0 = __r1 / __d1; \
- __m = (unsigned long) __q0 * __d0; \
- __r0 = __r0 * B | lowpart (n0); \
- while (__r0 < __m) \
- __q0--, __r0 += (d); \
- (q) = (unsigned long) __q1 * B | __q0; \
- (r) = __r0; \
- })
- #endif
- #endif /* udiv or mul */
-