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