1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is the Netscape Portable Runtime (NSPR).
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998-2000
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either the GNU General Public License Version 2 or later (the "GPL"), or
26 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : #include "primpl.h"
39 :
40 : static PRInt64 ll_zero = LL_INIT( 0x00000000,0x00000000 );
41 : static PRInt64 ll_maxint = LL_INIT( 0x7fffffff, 0xffffffff );
42 : static PRInt64 ll_minint = LL_INIT( 0x80000000, 0x00000000 );
43 : static PRUint64 ll_maxuint = LL_INIT( 0xffffffff, 0xffffffff );
44 :
45 32 : PR_IMPLEMENT(PRInt64) LL_Zero(void) { return ll_zero; }
46 0 : PR_IMPLEMENT(PRInt64) LL_MaxInt(void) { return ll_maxint; }
47 0 : PR_IMPLEMENT(PRInt64) LL_MinInt(void) { return ll_minint; }
48 3499 : PR_IMPLEMENT(PRUint64) LL_MaxUint(void) { return ll_maxuint; }
49 :
50 : #ifndef HAVE_LONG_LONG
51 : /*
52 : ** Divide 64-bit a by 32-bit b, which must be normalized so its high bit is 1.
53 : */
54 : static void norm_udivmod32(PRUint32 *qp, PRUint32 *rp, PRUint64 a, PRUint32 b)
55 : {
56 : PRUint32 d1, d0, q1, q0;
57 : PRUint32 r1, r0, m;
58 :
59 : d1 = _hi16(b);
60 : d0 = _lo16(b);
61 : r1 = a.hi % d1;
62 : q1 = a.hi / d1;
63 : m = q1 * d0;
64 : r1 = (r1 << 16) | _hi16(a.lo);
65 : if (r1 < m) {
66 : q1--, r1 += b;
67 : if (r1 >= b /* i.e., we didn't get a carry when adding to r1 */
68 : && r1 < m) {
69 : q1--, r1 += b;
70 : }
71 : }
72 : r1 -= m;
73 : r0 = r1 % d1;
74 : q0 = r1 / d1;
75 : m = q0 * d0;
76 : r0 = (r0 << 16) | _lo16(a.lo);
77 : if (r0 < m) {
78 : q0--, r0 += b;
79 : if (r0 >= b
80 : && r0 < m) {
81 : q0--, r0 += b;
82 : }
83 : }
84 : *qp = (q1 << 16) | q0;
85 : *rp = r0 - m;
86 : }
87 :
88 : static PRUint32 CountLeadingZeros(PRUint32 a)
89 : {
90 : PRUint32 t;
91 : PRUint32 r = 32;
92 :
93 : if ((t = a >> 16) != 0)
94 : r -= 16, a = t;
95 : if ((t = a >> 8) != 0)
96 : r -= 8, a = t;
97 : if ((t = a >> 4) != 0)
98 : r -= 4, a = t;
99 : if ((t = a >> 2) != 0)
100 : r -= 2, a = t;
101 : if ((t = a >> 1) != 0)
102 : r -= 1, a = t;
103 : if (a & 1)
104 : r--;
105 : return r;
106 : }
107 :
108 : PR_IMPLEMENT(void) ll_udivmod(PRUint64 *qp, PRUint64 *rp, PRUint64 a, PRUint64 b)
109 : {
110 : PRUint32 n0, n1, n2;
111 : PRUint32 q0, q1;
112 : PRUint32 rsh, lsh;
113 :
114 : n0 = a.lo;
115 : n1 = a.hi;
116 :
117 : if (b.hi == 0) {
118 : if (b.lo > n1) {
119 : /* (0 q0) = (n1 n0) / (0 D0) */
120 :
121 : lsh = CountLeadingZeros(b.lo);
122 :
123 : if (lsh) {
124 : /*
125 : * Normalize, i.e. make the most significant bit of the
126 : * denominator be set.
127 : */
128 : b.lo = b.lo << lsh;
129 : n1 = (n1 << lsh) | (n0 >> (32 - lsh));
130 : n0 = n0 << lsh;
131 : }
132 :
133 : a.lo = n0, a.hi = n1;
134 : norm_udivmod32(&q0, &n0, a, b.lo);
135 : q1 = 0;
136 :
137 : /* remainder is in n0 >> lsh */
138 : } else {
139 : /* (q1 q0) = (n1 n0) / (0 d0) */
140 :
141 : if (b.lo == 0) /* user wants to divide by zero! */
142 : b.lo = 1 / b.lo; /* so go ahead and crash */
143 :
144 : lsh = CountLeadingZeros(b.lo);
145 :
146 : if (lsh == 0) {
147 : /*
148 : * From (n1 >= b.lo)
149 : * && (the most significant bit of b.lo is set),
150 : * conclude that
151 : * (the most significant bit of n1 is set)
152 : * && (the leading quotient digit q1 = 1).
153 : *
154 : * This special case is necessary, not an optimization
155 : * (Shifts counts of 32 are undefined).
156 : */
157 : n1 -= b.lo;
158 : q1 = 1;
159 : } else {
160 : /*
161 : * Normalize.
162 : */
163 : rsh = 32 - lsh;
164 :
165 : b.lo = b.lo << lsh;
166 : n2 = n1 >> rsh;
167 : n1 = (n1 << lsh) | (n0 >> rsh);
168 : n0 = n0 << lsh;
169 :
170 : a.lo = n1, a.hi = n2;
171 : norm_udivmod32(&q1, &n1, a, b.lo);
172 : }
173 :
174 : /* n1 != b.lo... */
175 :
176 : a.lo = n0, a.hi = n1;
177 : norm_udivmod32(&q0, &n0, a, b.lo);
178 :
179 : /* remainder in n0 >> lsh */
180 : }
181 :
182 : if (rp) {
183 : rp->lo = n0 >> lsh;
184 : rp->hi = 0;
185 : }
186 : } else {
187 : if (b.hi > n1) {
188 : /* (0 0) = (n1 n0) / (D1 d0) */
189 :
190 : q0 = 0;
191 : q1 = 0;
192 :
193 : /* remainder in (n1 n0) */
194 : if (rp) {
195 : rp->lo = n0;
196 : rp->hi = n1;
197 : }
198 : } else {
199 : /* (0 q0) = (n1 n0) / (d1 d0) */
200 :
201 : lsh = CountLeadingZeros(b.hi);
202 : if (lsh == 0) {
203 : /*
204 : * From (n1 >= b.hi)
205 : * && (the most significant bit of b.hi is set),
206 : * conclude that
207 : * (the most significant bit of n1 is set)
208 : * && (the quotient digit q0 = 0 or 1).
209 : *
210 : * This special case is necessary, not an optimization.
211 : */
212 :
213 : /*
214 : * The condition on the next line takes advantage of that
215 : * n1 >= b.hi (true due to control flow).
216 : */
217 : if (n1 > b.hi || n0 >= b.lo) {
218 : q0 = 1;
219 : a.lo = n0, a.hi = n1;
220 : LL_SUB(a, a, b);
221 : } else {
222 : q0 = 0;
223 : }
224 : q1 = 0;
225 :
226 : if (rp) {
227 : rp->lo = n0;
228 : rp->hi = n1;
229 : }
230 : } else {
231 : PRInt64 m;
232 :
233 : /*
234 : * Normalize.
235 : */
236 : rsh = 32 - lsh;
237 :
238 : b.hi = (b.hi << lsh) | (b.lo >> rsh);
239 : b.lo = b.lo << lsh;
240 : n2 = n1 >> rsh;
241 : n1 = (n1 << lsh) | (n0 >> rsh);
242 : n0 = n0 << lsh;
243 :
244 : a.lo = n1, a.hi = n2;
245 : norm_udivmod32(&q0, &n1, a, b.hi);
246 : LL_MUL32(m, q0, b.lo);
247 :
248 : if ((m.hi > n1) || ((m.hi == n1) && (m.lo > n0))) {
249 : q0--;
250 : LL_SUB(m, m, b);
251 : }
252 :
253 : q1 = 0;
254 :
255 : /* Remainder is ((n1 n0) - (m1 m0)) >> lsh */
256 : if (rp) {
257 : a.lo = n0, a.hi = n1;
258 : LL_SUB(a, a, m);
259 : rp->lo = (a.hi << rsh) | (a.lo >> lsh);
260 : rp->hi = a.hi >> lsh;
261 : }
262 : }
263 : }
264 : }
265 :
266 : if (qp) {
267 : qp->lo = q0;
268 : qp->hi = q1;
269 : }
270 : }
271 : #endif /* !HAVE_LONG_LONG */
|