1// SPDX-License-Identifier: GPL-2.0
2/* This has so very few changes over libgcc2's __udivmoddi4 it isn't funny.  */
3
4#include <math-emu/soft-fp.h>
5
6#undef count_leading_zeros
7#define count_leading_zeros  __FP_CLZ
8
9void
10_fp_udivmodti4(_FP_W_TYPE q[2], _FP_W_TYPE r[2],
11	       _FP_W_TYPE n1, _FP_W_TYPE n0,
12	       _FP_W_TYPE d1, _FP_W_TYPE d0)
13{
14  _FP_W_TYPE q0, q1, r0, r1;
15  _FP_I_TYPE b, bm;
16
17  if (d1 == 0)
18    {
19#if !UDIV_NEEDS_NORMALIZATION
20      if (d0 > n1)
21	{
22	  /* 0q = nn / 0D */
23
24	  udiv_qrnnd (q0, n0, n1, n0, d0);
25	  q1 = 0;
26
27	  /* Remainder in n0.  */
28	}
29      else
30	{
31	  /* qq = NN / 0d */
32
33	  if (d0 == 0)
34	    d0 = 1 / d0;	/* Divide intentionally by zero.  */
35
36	  udiv_qrnnd (q1, n1, 0, n1, d0);
37	  udiv_qrnnd (q0, n0, n1, n0, d0);
38
39	  /* Remainder in n0.  */
40	}
41
42      r0 = n0;
43      r1 = 0;
44
45#else /* UDIV_NEEDS_NORMALIZATION */
46
47      if (d0 > n1)
48	{
49	  /* 0q = nn / 0D */
50
51	  count_leading_zeros (bm, d0);
52
53	  if (bm != 0)
54	    {
55	      /* Normalize, i.e. make the most significant bit of the
56		 denominator set.  */
57
58	      d0 = d0 << bm;
59	      n1 = (n1 << bm) | (n0 >> (_FP_W_TYPE_SIZE - bm));
60	      n0 = n0 << bm;
61	    }
62
63	  udiv_qrnnd (q0, n0, n1, n0, d0);
64	  q1 = 0;
65
66	  /* Remainder in n0 >> bm.  */
67	}
68      else
69	{
70	  /* qq = NN / 0d */
71
72	  if (d0 == 0)
73	    d0 = 1 / d0;	/* Divide intentionally by zero.  */
74
75	  count_leading_zeros (bm, d0);
76
77	  if (bm == 0)
78	    {
79	      /* From (n1 >= d0) /\ (the most significant bit of d0 is set),
80		 conclude (the most significant bit of n1 is set) /\ (the
81		 leading quotient digit q1 = 1).
82
83		 This special case is necessary, not an optimization.
84		 (Shifts counts of SI_TYPE_SIZE are undefined.)  */
85
86	      n1 -= d0;
87	      q1 = 1;
88	    }
89	  else
90	    {
91	      _FP_W_TYPE n2;
92
93	      /* Normalize.  */
94
95	      b = _FP_W_TYPE_SIZE - bm;
96
97	      d0 = d0 << bm;
98	      n2 = n1 >> b;
99	      n1 = (n1 << bm) | (n0 >> b);
100	      n0 = n0 << bm;
101
102	      udiv_qrnnd (q1, n1, n2, n1, d0);
103	    }
104
105	  /* n1 != d0...  */
106
107	  udiv_qrnnd (q0, n0, n1, n0, d0);
108
109	  /* Remainder in n0 >> bm.  */
110	}
111
112      r0 = n0 >> bm;
113      r1 = 0;
114#endif /* UDIV_NEEDS_NORMALIZATION */
115    }
116  else
117    {
118      if (d1 > n1)
119	{
120	  /* 00 = nn / DD */
121
122	  q0 = 0;
123	  q1 = 0;
124
125	  /* Remainder in n1n0.  */
126	  r0 = n0;
127	  r1 = n1;
128	}
129      else
130	{
131	  /* 0q = NN / dd */
132
133	  count_leading_zeros (bm, d1);
134	  if (bm == 0)
135	    {
136	      /* From (n1 >= d1) /\ (the most significant bit of d1 is set),
137		 conclude (the most significant bit of n1 is set) /\ (the
138		 quotient digit q0 = 0 or 1).
139
140		 This special case is necessary, not an optimization.  */
141
142	      /* The condition on the next line takes advantage of that
143		 n1 >= d1 (true due to program flow).  */
144	      if (n1 > d1 || n0 >= d0)
145		{
146		  q0 = 1;
147		  sub_ddmmss (n1, n0, n1, n0, d1, d0);
148		}
149	      else
150		q0 = 0;
151
152	      q1 = 0;
153
154	      r0 = n0;
155	      r1 = n1;
156	    }
157	  else
158	    {
159	      _FP_W_TYPE m1, m0, n2;
160
161	      /* Normalize.  */
162
163	      b = _FP_W_TYPE_SIZE - bm;
164
165	      d1 = (d1 << bm) | (d0 >> b);
166	      d0 = d0 << bm;
167	      n2 = n1 >> b;
168	      n1 = (n1 << bm) | (n0 >> b);
169	      n0 = n0 << bm;
170
171	      udiv_qrnnd (q0, n1, n2, n1, d1);
172	      umul_ppmm (m1, m0, q0, d0);
173
174	      if (m1 > n1 || (m1 == n1 && m0 > n0))
175		{
176		  q0--;
177		  sub_ddmmss (m1, m0, m1, m0, d1, d0);
178		}
179
180	      q1 = 0;
181
182	      /* Remainder in (n1n0 - m1m0) >> bm.  */
183	      sub_ddmmss (n1, n0, n1, n0, m1, m0);
184	      r0 = (n1 << b) | (n0 >> bm);
185	      r1 = n1 >> bm;
186	    }
187	}
188    }
189
190  q[0] = q0; q[1] = q1;
191  r[0] = r0, r[1] = r1;
192}
193