18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/* This has so very few changes over libgcc2's __udivmoddi4 it isn't funny.  */
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci#include <math-emu/soft-fp.h>
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#undef count_leading_zeros
78c2ecf20Sopenharmony_ci#define count_leading_zeros  __FP_CLZ
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_civoid
108c2ecf20Sopenharmony_ci_fp_udivmodti4(_FP_W_TYPE q[2], _FP_W_TYPE r[2],
118c2ecf20Sopenharmony_ci	       _FP_W_TYPE n1, _FP_W_TYPE n0,
128c2ecf20Sopenharmony_ci	       _FP_W_TYPE d1, _FP_W_TYPE d0)
138c2ecf20Sopenharmony_ci{
148c2ecf20Sopenharmony_ci  _FP_W_TYPE q0, q1, r0, r1;
158c2ecf20Sopenharmony_ci  _FP_I_TYPE b, bm;
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci  if (d1 == 0)
188c2ecf20Sopenharmony_ci    {
198c2ecf20Sopenharmony_ci#if !UDIV_NEEDS_NORMALIZATION
208c2ecf20Sopenharmony_ci      if (d0 > n1)
218c2ecf20Sopenharmony_ci	{
228c2ecf20Sopenharmony_ci	  /* 0q = nn / 0D */
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci	  udiv_qrnnd (q0, n0, n1, n0, d0);
258c2ecf20Sopenharmony_ci	  q1 = 0;
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci	  /* Remainder in n0.  */
288c2ecf20Sopenharmony_ci	}
298c2ecf20Sopenharmony_ci      else
308c2ecf20Sopenharmony_ci	{
318c2ecf20Sopenharmony_ci	  /* qq = NN / 0d */
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	  if (d0 == 0)
348c2ecf20Sopenharmony_ci	    d0 = 1 / d0;	/* Divide intentionally by zero.  */
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	  udiv_qrnnd (q1, n1, 0, n1, d0);
378c2ecf20Sopenharmony_ci	  udiv_qrnnd (q0, n0, n1, n0, d0);
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	  /* Remainder in n0.  */
408c2ecf20Sopenharmony_ci	}
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci      r0 = n0;
438c2ecf20Sopenharmony_ci      r1 = 0;
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci#else /* UDIV_NEEDS_NORMALIZATION */
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci      if (d0 > n1)
488c2ecf20Sopenharmony_ci	{
498c2ecf20Sopenharmony_ci	  /* 0q = nn / 0D */
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	  count_leading_zeros (bm, d0);
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	  if (bm != 0)
548c2ecf20Sopenharmony_ci	    {
558c2ecf20Sopenharmony_ci	      /* Normalize, i.e. make the most significant bit of the
568c2ecf20Sopenharmony_ci		 denominator set.  */
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	      d0 = d0 << bm;
598c2ecf20Sopenharmony_ci	      n1 = (n1 << bm) | (n0 >> (_FP_W_TYPE_SIZE - bm));
608c2ecf20Sopenharmony_ci	      n0 = n0 << bm;
618c2ecf20Sopenharmony_ci	    }
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	  udiv_qrnnd (q0, n0, n1, n0, d0);
648c2ecf20Sopenharmony_ci	  q1 = 0;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	  /* Remainder in n0 >> bm.  */
678c2ecf20Sopenharmony_ci	}
688c2ecf20Sopenharmony_ci      else
698c2ecf20Sopenharmony_ci	{
708c2ecf20Sopenharmony_ci	  /* qq = NN / 0d */
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	  if (d0 == 0)
738c2ecf20Sopenharmony_ci	    d0 = 1 / d0;	/* Divide intentionally by zero.  */
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	  count_leading_zeros (bm, d0);
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	  if (bm == 0)
788c2ecf20Sopenharmony_ci	    {
798c2ecf20Sopenharmony_ci	      /* From (n1 >= d0) /\ (the most significant bit of d0 is set),
808c2ecf20Sopenharmony_ci		 conclude (the most significant bit of n1 is set) /\ (the
818c2ecf20Sopenharmony_ci		 leading quotient digit q1 = 1).
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci		 This special case is necessary, not an optimization.
848c2ecf20Sopenharmony_ci		 (Shifts counts of SI_TYPE_SIZE are undefined.)  */
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	      n1 -= d0;
878c2ecf20Sopenharmony_ci	      q1 = 1;
888c2ecf20Sopenharmony_ci	    }
898c2ecf20Sopenharmony_ci	  else
908c2ecf20Sopenharmony_ci	    {
918c2ecf20Sopenharmony_ci	      _FP_W_TYPE n2;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	      /* Normalize.  */
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	      b = _FP_W_TYPE_SIZE - bm;
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	      d0 = d0 << bm;
988c2ecf20Sopenharmony_ci	      n2 = n1 >> b;
998c2ecf20Sopenharmony_ci	      n1 = (n1 << bm) | (n0 >> b);
1008c2ecf20Sopenharmony_ci	      n0 = n0 << bm;
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	      udiv_qrnnd (q1, n1, n2, n1, d0);
1038c2ecf20Sopenharmony_ci	    }
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	  /* n1 != d0...  */
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	  udiv_qrnnd (q0, n0, n1, n0, d0);
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	  /* Remainder in n0 >> bm.  */
1108c2ecf20Sopenharmony_ci	}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci      r0 = n0 >> bm;
1138c2ecf20Sopenharmony_ci      r1 = 0;
1148c2ecf20Sopenharmony_ci#endif /* UDIV_NEEDS_NORMALIZATION */
1158c2ecf20Sopenharmony_ci    }
1168c2ecf20Sopenharmony_ci  else
1178c2ecf20Sopenharmony_ci    {
1188c2ecf20Sopenharmony_ci      if (d1 > n1)
1198c2ecf20Sopenharmony_ci	{
1208c2ecf20Sopenharmony_ci	  /* 00 = nn / DD */
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	  q0 = 0;
1238c2ecf20Sopenharmony_ci	  q1 = 0;
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	  /* Remainder in n1n0.  */
1268c2ecf20Sopenharmony_ci	  r0 = n0;
1278c2ecf20Sopenharmony_ci	  r1 = n1;
1288c2ecf20Sopenharmony_ci	}
1298c2ecf20Sopenharmony_ci      else
1308c2ecf20Sopenharmony_ci	{
1318c2ecf20Sopenharmony_ci	  /* 0q = NN / dd */
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	  count_leading_zeros (bm, d1);
1348c2ecf20Sopenharmony_ci	  if (bm == 0)
1358c2ecf20Sopenharmony_ci	    {
1368c2ecf20Sopenharmony_ci	      /* From (n1 >= d1) /\ (the most significant bit of d1 is set),
1378c2ecf20Sopenharmony_ci		 conclude (the most significant bit of n1 is set) /\ (the
1388c2ecf20Sopenharmony_ci		 quotient digit q0 = 0 or 1).
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci		 This special case is necessary, not an optimization.  */
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	      /* The condition on the next line takes advantage of that
1438c2ecf20Sopenharmony_ci		 n1 >= d1 (true due to program flow).  */
1448c2ecf20Sopenharmony_ci	      if (n1 > d1 || n0 >= d0)
1458c2ecf20Sopenharmony_ci		{
1468c2ecf20Sopenharmony_ci		  q0 = 1;
1478c2ecf20Sopenharmony_ci		  sub_ddmmss (n1, n0, n1, n0, d1, d0);
1488c2ecf20Sopenharmony_ci		}
1498c2ecf20Sopenharmony_ci	      else
1508c2ecf20Sopenharmony_ci		q0 = 0;
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	      q1 = 0;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	      r0 = n0;
1558c2ecf20Sopenharmony_ci	      r1 = n1;
1568c2ecf20Sopenharmony_ci	    }
1578c2ecf20Sopenharmony_ci	  else
1588c2ecf20Sopenharmony_ci	    {
1598c2ecf20Sopenharmony_ci	      _FP_W_TYPE m1, m0, n2;
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	      /* Normalize.  */
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	      b = _FP_W_TYPE_SIZE - bm;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	      d1 = (d1 << bm) | (d0 >> b);
1668c2ecf20Sopenharmony_ci	      d0 = d0 << bm;
1678c2ecf20Sopenharmony_ci	      n2 = n1 >> b;
1688c2ecf20Sopenharmony_ci	      n1 = (n1 << bm) | (n0 >> b);
1698c2ecf20Sopenharmony_ci	      n0 = n0 << bm;
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	      udiv_qrnnd (q0, n1, n2, n1, d1);
1728c2ecf20Sopenharmony_ci	      umul_ppmm (m1, m0, q0, d0);
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	      if (m1 > n1 || (m1 == n1 && m0 > n0))
1758c2ecf20Sopenharmony_ci		{
1768c2ecf20Sopenharmony_ci		  q0--;
1778c2ecf20Sopenharmony_ci		  sub_ddmmss (m1, m0, m1, m0, d1, d0);
1788c2ecf20Sopenharmony_ci		}
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	      q1 = 0;
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	      /* Remainder in (n1n0 - m1m0) >> bm.  */
1838c2ecf20Sopenharmony_ci	      sub_ddmmss (n1, n0, n1, n0, m1, m0);
1848c2ecf20Sopenharmony_ci	      r0 = (n1 << b) | (n0 >> bm);
1858c2ecf20Sopenharmony_ci	      r1 = n1 >> bm;
1868c2ecf20Sopenharmony_ci	    }
1878c2ecf20Sopenharmony_ci	}
1888c2ecf20Sopenharmony_ci    }
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci  q[0] = q0; q[1] = q1;
1918c2ecf20Sopenharmony_ci  r[0] = r0, r[1] = r1;
1928c2ecf20Sopenharmony_ci}
193