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 | |
9 | void |
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 | |