Blame sysdeps/wordsize-32/divdi3.c

Packit Service 82fcde
/* 64-bit multiplication and division
Packit Service 82fcde
   Copyright (C) 1989, 1992-2018 Free Software Foundation, Inc.
Packit Service 82fcde
   This file is part of the GNU C Library.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is free software; you can redistribute it and/or
Packit Service 82fcde
   modify it under the terms of the GNU Lesser General Public
Packit Service 82fcde
   License as published by the Free Software Foundation; either
Packit Service 82fcde
   version 2.1 of the License, or (at your option) any later version.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is distributed in the hope that it will be useful,
Packit Service 82fcde
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 82fcde
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 82fcde
   Lesser General Public License for more details.
Packit Service 82fcde
Packit Service 82fcde
   You should have received a copy of the GNU Lesser General Public
Packit Service 82fcde
   License along with the GNU C Library; if not, see
Packit Service 82fcde
   <http://www.gnu.org/licenses/>.  */
Packit Service 82fcde
Packit Service 82fcde
#include <endian.h>
Packit Service 82fcde
#include <stdlib.h>
Packit Service 82fcde
#include <bits/wordsize.h>
Packit Service 82fcde
Packit Service 82fcde
#if __WORDSIZE != 32
Packit Service 82fcde
#error This is for 32-bit targets only
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
typedef unsigned int UQItype	__attribute__ ((mode (QI)));
Packit Service 82fcde
typedef          int SItype	__attribute__ ((mode (SI)));
Packit Service 82fcde
typedef unsigned int USItype	__attribute__ ((mode (SI)));
Packit Service 82fcde
typedef          int DItype	__attribute__ ((mode (DI)));
Packit Service 82fcde
typedef unsigned int UDItype	__attribute__ ((mode (DI)));
Packit Service 82fcde
#define Wtype SItype
Packit Service 82fcde
#define HWtype SItype
Packit Service 82fcde
#define DWtype DItype
Packit Service 82fcde
#define UWtype USItype
Packit Service 82fcde
#define UHWtype USItype
Packit Service 82fcde
#define UDWtype UDItype
Packit Service 82fcde
#define W_TYPE_SIZE 32
Packit Service 82fcde
Packit Service 82fcde
#include <stdlib/longlong.h>
Packit Service 82fcde
Packit Service 82fcde
#if __BYTE_ORDER == __BIG_ENDIAN
Packit Service 82fcde
struct DWstruct { Wtype high, low;};
Packit Service 82fcde
#elif __BYTE_ORDER == __LITTLE_ENDIAN
Packit Service 82fcde
struct DWstruct { Wtype low, high;};
Packit Service 82fcde
#else
Packit Service 82fcde
#error Unhandled endianity
Packit Service 82fcde
#endif
Packit Service 82fcde
typedef union { struct DWstruct s; DWtype ll; } DWunion;
Packit Service 82fcde
Packit Service 82fcde
/* Prototypes of exported functions.  */
Packit Service 82fcde
extern DWtype __divdi3 (DWtype u, DWtype v);
Packit Service 82fcde
extern DWtype __moddi3 (DWtype u, DWtype v);
Packit Service 82fcde
extern UDWtype __udivdi3 (UDWtype u, UDWtype v);
Packit Service 82fcde
extern UDWtype __umoddi3 (UDWtype u, UDWtype v);
Packit Service 82fcde
Packit Service 82fcde
static UDWtype
Packit Service 82fcde
__udivmoddi4 (UDWtype n, UDWtype d, UDWtype *rp)
Packit Service 82fcde
{
Packit Service 82fcde
  DWunion ww;
Packit Service 82fcde
  DWunion nn, dd;
Packit Service 82fcde
  DWunion rr;
Packit Service 82fcde
  UWtype d0, d1, n0, n1, n2;
Packit Service 82fcde
  UWtype q0, q1;
Packit Service 82fcde
  UWtype b, bm;
Packit Service 82fcde
Packit Service 82fcde
  nn.ll = n;
Packit Service 82fcde
  dd.ll = d;
Packit Service 82fcde
Packit Service 82fcde
  d0 = dd.s.low;
Packit Service 82fcde
  d1 = dd.s.high;
Packit Service 82fcde
  n0 = nn.s.low;
Packit Service 82fcde
  n1 = nn.s.high;
Packit Service 82fcde
Packit Service 82fcde
#if !UDIV_NEEDS_NORMALIZATION
Packit Service 82fcde
  if (d1 == 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      if (d0 > n1)
Packit Service 82fcde
	{
Packit Service 82fcde
	  /* 0q = nn / 0D */
Packit Service 82fcde
Packit Service 82fcde
	  udiv_qrnnd (q0, n0, n1, n0, d0);
Packit Service 82fcde
	  q1 = 0;
Packit Service 82fcde
Packit Service 82fcde
	  /* Remainder in n0.  */
Packit Service 82fcde
	}
Packit Service 82fcde
      else
Packit Service 82fcde
	{
Packit Service 82fcde
	  /* qq = NN / 0d */
Packit Service 82fcde
Packit Service 82fcde
	  if (d0 == 0)
Packit Service 82fcde
	    d0 = 1 / d0;	/* Divide intentionally by zero.  */
Packit Service 82fcde
Packit Service 82fcde
	  udiv_qrnnd (q1, n1, 0, n1, d0);
Packit Service 82fcde
	  udiv_qrnnd (q0, n0, n1, n0, d0);
Packit Service 82fcde
Packit Service 82fcde
	  /* Remainder in n0.  */
Packit Service 82fcde
	}
Packit Service 82fcde
Packit Service 82fcde
      if (rp != 0)
Packit Service 82fcde
	{
Packit Service 82fcde
	  rr.s.low = n0;
Packit Service 82fcde
	  rr.s.high = 0;
Packit Service 82fcde
	  *rp = rr.ll;
Packit Service 82fcde
	}
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
#else /* UDIV_NEEDS_NORMALIZATION */
Packit Service 82fcde
Packit Service 82fcde
  if (d1 == 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      if (d0 > n1)
Packit Service 82fcde
	{
Packit Service 82fcde
	  /* 0q = nn / 0D */
Packit Service 82fcde
Packit Service 82fcde
	  count_leading_zeros (bm, d0);
Packit Service 82fcde
Packit Service 82fcde
	  if (bm != 0)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      /* Normalize, i.e. make the most significant bit of the
Packit Service 82fcde
		 denominator set.  */
Packit Service 82fcde
Packit Service 82fcde
	      d0 = d0 << bm;
Packit Service 82fcde
	      n1 = (n1 << bm) | (n0 >> (W_TYPE_SIZE - bm));
Packit Service 82fcde
	      n0 = n0 << bm;
Packit Service 82fcde
	    }
Packit Service 82fcde
Packit Service 82fcde
	  udiv_qrnnd (q0, n0, n1, n0, d0);
Packit Service 82fcde
	  q1 = 0;
Packit Service 82fcde
Packit Service 82fcde
	  /* Remainder in n0 >> bm.  */
Packit Service 82fcde
	}
Packit Service 82fcde
      else
Packit Service 82fcde
	{
Packit Service 82fcde
	  /* qq = NN / 0d */
Packit Service 82fcde
Packit Service 82fcde
	  if (d0 == 0)
Packit Service 82fcde
	    d0 = 1 / d0;	/* Divide intentionally by zero.  */
Packit Service 82fcde
Packit Service 82fcde
	  count_leading_zeros (bm, d0);
Packit Service 82fcde
Packit Service 82fcde
	  if (bm == 0)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      /* From (n1 >= d0) /\ (the most significant bit of d0 is set),
Packit Service 82fcde
		 conclude (the most significant bit of n1 is set) /\ (the
Packit Service 82fcde
		 leading quotient digit q1 = 1).
Packit Service 82fcde
Packit Service 82fcde
		 This special case is necessary, not an optimization.
Packit Service 82fcde
		 (Shifts counts of W_TYPE_SIZE are undefined.)  */
Packit Service 82fcde
Packit Service 82fcde
	      n1 -= d0;
Packit Service 82fcde
	      q1 = 1;
Packit Service 82fcde
	    }
Packit Service 82fcde
	  else
Packit Service 82fcde
	    {
Packit Service 82fcde
	      /* Normalize.  */
Packit Service 82fcde
Packit Service 82fcde
	      b = W_TYPE_SIZE - bm;
Packit Service 82fcde
Packit Service 82fcde
	      d0 = d0 << bm;
Packit Service 82fcde
	      n2 = n1 >> b;
Packit Service 82fcde
	      n1 = (n1 << bm) | (n0 >> b);
Packit Service 82fcde
	      n0 = n0 << bm;
Packit Service 82fcde
Packit Service 82fcde
	      udiv_qrnnd (q1, n1, n2, n1, d0);
Packit Service 82fcde
	    }
Packit Service 82fcde
Packit Service 82fcde
	  /* n1 != d0...  */
Packit Service 82fcde
Packit Service 82fcde
	  udiv_qrnnd (q0, n0, n1, n0, d0);
Packit Service 82fcde
Packit Service 82fcde
	  /* Remainder in n0 >> bm.  */
Packit Service 82fcde
	}
Packit Service 82fcde
Packit Service 82fcde
      if (rp != 0)
Packit Service 82fcde
	{
Packit Service 82fcde
	  rr.s.low = n0 >> bm;
Packit Service 82fcde
	  rr.s.high = 0;
Packit Service 82fcde
	  *rp = rr.ll;
Packit Service 82fcde
	}
Packit Service 82fcde
    }
Packit Service 82fcde
#endif /* UDIV_NEEDS_NORMALIZATION */
Packit Service 82fcde
Packit Service 82fcde
  else
Packit Service 82fcde
    {
Packit Service 82fcde
      if (d1 > n1)
Packit Service 82fcde
	{
Packit Service 82fcde
	  /* 00 = nn / DD */
Packit Service 82fcde
Packit Service 82fcde
	  q0 = 0;
Packit Service 82fcde
	  q1 = 0;
Packit Service 82fcde
Packit Service 82fcde
	  /* Remainder in n1n0.  */
Packit Service 82fcde
	  if (rp != 0)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      rr.s.low = n0;
Packit Service 82fcde
	      rr.s.high = n1;
Packit Service 82fcde
	      *rp = rr.ll;
Packit Service 82fcde
	    }
Packit Service 82fcde
	}
Packit Service 82fcde
      else
Packit Service 82fcde
	{
Packit Service 82fcde
	  /* 0q = NN / dd */
Packit Service 82fcde
Packit Service 82fcde
	  count_leading_zeros (bm, d1);
Packit Service 82fcde
	  if (bm == 0)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      /* From (n1 >= d1) /\ (the most significant bit of d1 is set),
Packit Service 82fcde
		 conclude (the most significant bit of n1 is set) /\ (the
Packit Service 82fcde
		 quotient digit q0 = 0 or 1).
Packit Service 82fcde
Packit Service 82fcde
		 This special case is necessary, not an optimization.  */
Packit Service 82fcde
Packit Service 82fcde
	      /* The condition on the next line takes advantage of that
Packit Service 82fcde
		 n1 >= d1 (true due to program flow).  */
Packit Service 82fcde
	      if (n1 > d1 || n0 >= d0)
Packit Service 82fcde
		{
Packit Service 82fcde
		  q0 = 1;
Packit Service 82fcde
		  sub_ddmmss (n1, n0, n1, n0, d1, d0);
Packit Service 82fcde
		}
Packit Service 82fcde
	      else
Packit Service 82fcde
		q0 = 0;
Packit Service 82fcde
Packit Service 82fcde
	      q1 = 0;
Packit Service 82fcde
Packit Service 82fcde
	      if (rp != 0)
Packit Service 82fcde
		{
Packit Service 82fcde
		  rr.s.low = n0;
Packit Service 82fcde
		  rr.s.high = n1;
Packit Service 82fcde
		  *rp = rr.ll;
Packit Service 82fcde
		}
Packit Service 82fcde
	    }
Packit Service 82fcde
	  else
Packit Service 82fcde
	    {
Packit Service 82fcde
	      UWtype m1, m0;
Packit Service 82fcde
	      /* Normalize.  */
Packit Service 82fcde
Packit Service 82fcde
	      b = W_TYPE_SIZE - bm;
Packit Service 82fcde
Packit Service 82fcde
	      d1 = (d1 << bm) | (d0 >> b);
Packit Service 82fcde
	      d0 = d0 << bm;
Packit Service 82fcde
	      n2 = n1 >> b;
Packit Service 82fcde
	      n1 = (n1 << bm) | (n0 >> b);
Packit Service 82fcde
	      n0 = n0 << bm;
Packit Service 82fcde
Packit Service 82fcde
	      udiv_qrnnd (q0, n1, n2, n1, d1);
Packit Service 82fcde
	      umul_ppmm (m1, m0, q0, d0);
Packit Service 82fcde
Packit Service 82fcde
	      if (m1 > n1 || (m1 == n1 && m0 > n0))
Packit Service 82fcde
		{
Packit Service 82fcde
		  q0--;
Packit Service 82fcde
		  sub_ddmmss (m1, m0, m1, m0, d1, d0);
Packit Service 82fcde
		}
Packit Service 82fcde
Packit Service 82fcde
	      q1 = 0;
Packit Service 82fcde
Packit Service 82fcde
	      /* Remainder in (n1n0 - m1m0) >> bm.  */
Packit Service 82fcde
	      if (rp != 0)
Packit Service 82fcde
		{
Packit Service 82fcde
		  sub_ddmmss (n1, n0, n1, n0, m1, m0);
Packit Service 82fcde
		  rr.s.low = (n1 << b) | (n0 >> bm);
Packit Service 82fcde
		  rr.s.high = n1 >> bm;
Packit Service 82fcde
		  *rp = rr.ll;
Packit Service 82fcde
		}
Packit Service 82fcde
	    }
Packit Service 82fcde
	}
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  ww.s.low = q0;
Packit Service 82fcde
  ww.s.high = q1;
Packit Service 82fcde
  return ww.ll;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
DWtype
Packit Service 82fcde
__divdi3 (DWtype u, DWtype v)
Packit Service 82fcde
{
Packit Service 82fcde
  Wtype c = 0;
Packit Service 82fcde
  DWtype w;
Packit Service 82fcde
Packit Service 82fcde
  if (u < 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      c = ~c;
Packit Service 82fcde
      u = -u;
Packit Service 82fcde
    }
Packit Service 82fcde
  if (v < 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      c = ~c;
Packit Service 82fcde
      v = -v;
Packit Service 82fcde
    }
Packit Service 82fcde
  w = __udivmoddi4 (u, v, NULL);
Packit Service 82fcde
  if (c)
Packit Service 82fcde
    w = -w;
Packit Service 82fcde
  return w;
Packit Service 82fcde
}
Packit Service 82fcde
strong_alias (__divdi3, __divdi3_internal)
Packit Service 82fcde
Packit Service 82fcde
DWtype
Packit Service 82fcde
__moddi3 (DWtype u, DWtype v)
Packit Service 82fcde
{
Packit Service 82fcde
  Wtype c = 0;
Packit Service 82fcde
  DWtype w;
Packit Service 82fcde
Packit Service 82fcde
  if (u < 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      c = ~c;
Packit Service 82fcde
      u = -u;
Packit Service 82fcde
    }
Packit Service 82fcde
  if (v < 0)
Packit Service 82fcde
    v = -v;
Packit Service 82fcde
  __udivmoddi4 (u, v, (UDWtype *) &w);
Packit Service 82fcde
  if (c)
Packit Service 82fcde
    w = -w;
Packit Service 82fcde
  return w;
Packit Service 82fcde
}
Packit Service 82fcde
strong_alias (__moddi3, __moddi3_internal)
Packit Service 82fcde
Packit Service 82fcde
UDWtype
Packit Service 82fcde
__udivdi3 (UDWtype u, UDWtype v)
Packit Service 82fcde
{
Packit Service 82fcde
  return __udivmoddi4 (u, v, NULL);
Packit Service 82fcde
}
Packit Service 82fcde
strong_alias (__udivdi3, __udivdi3_internal)
Packit Service 82fcde
Packit Service 82fcde
UDWtype
Packit Service 82fcde
__umoddi3 (UDWtype u, UDWtype v)
Packit Service 82fcde
{
Packit Service 82fcde
  UDWtype w;
Packit Service 82fcde
Packit Service 82fcde
  __udivmoddi4 (u, v, &w);
Packit Service 82fcde
  return w;
Packit Service 82fcde
}
Packit Service 82fcde
strong_alias (__umoddi3, __umoddi3_internal)
Packit Service 82fcde
Packit Service 82fcde
/* We declare these with compat_symbol so that they are not visible at
Packit Service 82fcde
   link time.  Programs must use the functions from libgcc.  */
Packit Service 82fcde
#ifdef SHARED
Packit Service 82fcde
# include <shlib-compat.h>
Packit Service 82fcde
compat_symbol (libc, __divdi3, __divdi3, GLIBC_2_0);
Packit Service 82fcde
compat_symbol (libc, __moddi3, __moddi3, GLIBC_2_0);
Packit Service 82fcde
compat_symbol (libc, __udivdi3, __udivdi3, GLIBC_2_0);
Packit Service 82fcde
compat_symbol (libc, __umoddi3, __umoddi3, GLIBC_2_0);
Packit Service 82fcde
#endif