/* 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 */
