prlong.c (5522B)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #include "prlong.h" 7 8 static PRInt64 ll_zero = PR_INT64(0x0000000000000000); 9 static PRInt64 ll_maxint = PR_INT64(0x7fffffffffffffff); 10 static PRInt64 ll_minint = PR_INT64(0x8000000000000000); 11 static PRUint64 ll_maxuint = PR_UINT64(0xffffffffffffffff); 12 13 PR_IMPLEMENT(PRInt64) LL_Zero(void) { return ll_zero; } 14 PR_IMPLEMENT(PRInt64) LL_MaxInt(void) { return ll_maxint; } 15 PR_IMPLEMENT(PRInt64) LL_MinInt(void) { return ll_minint; } 16 PR_IMPLEMENT(PRUint64) LL_MaxUint(void) { return ll_maxuint; } 17 18 #ifndef HAVE_LONG_LONG 19 /* 20 ** Divide 64-bit a by 32-bit b, which must be normalized so its high bit is 1. 21 */ 22 static void norm_udivmod32(PRUint32* qp, PRUint32* rp, PRUint64 a, PRUint32 b) { 23 PRUint32 d1, d0, q1, q0; 24 PRUint32 r1, r0, m; 25 26 d1 = _hi16(b); 27 d0 = _lo16(b); 28 r1 = a.hi % d1; 29 q1 = a.hi / d1; 30 m = q1 * d0; 31 r1 = (r1 << 16) | _hi16(a.lo); 32 if (r1 < m) { 33 q1--, r1 += b; 34 if (r1 >= b /* i.e., we didn't get a carry when adding to r1 */ 35 && r1 < m) { 36 q1--, r1 += b; 37 } 38 } 39 r1 -= m; 40 r0 = r1 % d1; 41 q0 = r1 / d1; 42 m = q0 * d0; 43 r0 = (r0 << 16) | _lo16(a.lo); 44 if (r0 < m) { 45 q0--, r0 += b; 46 if (r0 >= b && r0 < m) { 47 q0--, r0 += b; 48 } 49 } 50 *qp = (q1 << 16) | q0; 51 *rp = r0 - m; 52 } 53 54 static PRUint32 CountLeadingZeros(PRUint32 a) { 55 PRUint32 t; 56 PRUint32 r = 32; 57 58 if ((t = a >> 16) != 0) { 59 r -= 16, a = t; 60 } 61 if ((t = a >> 8) != 0) { 62 r -= 8, a = t; 63 } 64 if ((t = a >> 4) != 0) { 65 r -= 4, a = t; 66 } 67 if ((t = a >> 2) != 0) { 68 r -= 2, a = t; 69 } 70 if ((t = a >> 1) != 0) { 71 r -= 1, a = t; 72 } 73 if (a & 1) { 74 r--; 75 } 76 return r; 77 } 78 79 PR_IMPLEMENT(void) 80 ll_udivmod(PRUint64* qp, PRUint64* rp, PRUint64 a, PRUint64 b) { 81 PRUint32 n0, n1, n2; 82 PRUint32 q0, q1; 83 PRUint32 rsh, lsh; 84 85 n0 = a.lo; 86 n1 = a.hi; 87 88 if (b.hi == 0) { 89 if (b.lo > n1) { 90 /* (0 q0) = (n1 n0) / (0 D0) */ 91 92 lsh = CountLeadingZeros(b.lo); 93 94 if (lsh) { 95 /* 96 * Normalize, i.e. make the most significant bit of the 97 * denominator be set. 98 */ 99 b.lo = b.lo << lsh; 100 n1 = (n1 << lsh) | (n0 >> (32 - lsh)); 101 n0 = n0 << lsh; 102 } 103 104 a.lo = n0, a.hi = n1; 105 norm_udivmod32(&q0, &n0, a, b.lo); 106 q1 = 0; 107 108 /* remainder is in n0 >> lsh */ 109 } else { 110 /* (q1 q0) = (n1 n0) / (0 d0) */ 111 112 if (b.lo == 0) { /* user wants to divide by zero! */ 113 b.lo = 1 / b.lo; /* so go ahead and crash */ 114 } 115 116 lsh = CountLeadingZeros(b.lo); 117 118 if (lsh == 0) { 119 /* 120 * From (n1 >= b.lo) 121 * && (the most significant bit of b.lo is set), 122 * conclude that 123 * (the most significant bit of n1 is set) 124 * && (the leading quotient digit q1 = 1). 125 * 126 * This special case is necessary, not an optimization 127 * (Shifts counts of 32 are undefined). 128 */ 129 n1 -= b.lo; 130 q1 = 1; 131 } else { 132 /* 133 * Normalize. 134 */ 135 rsh = 32 - lsh; 136 137 b.lo = b.lo << lsh; 138 n2 = n1 >> rsh; 139 n1 = (n1 << lsh) | (n0 >> rsh); 140 n0 = n0 << lsh; 141 142 a.lo = n1, a.hi = n2; 143 norm_udivmod32(&q1, &n1, a, b.lo); 144 } 145 146 /* n1 != b.lo... */ 147 148 a.lo = n0, a.hi = n1; 149 norm_udivmod32(&q0, &n0, a, b.lo); 150 151 /* remainder in n0 >> lsh */ 152 } 153 154 if (rp) { 155 rp->lo = n0 >> lsh; 156 rp->hi = 0; 157 } 158 } else { 159 if (b.hi > n1) { 160 /* (0 0) = (n1 n0) / (D1 d0) */ 161 162 q0 = 0; 163 q1 = 0; 164 165 /* remainder in (n1 n0) */ 166 if (rp) { 167 rp->lo = n0; 168 rp->hi = n1; 169 } 170 } else { 171 /* (0 q0) = (n1 n0) / (d1 d0) */ 172 173 lsh = CountLeadingZeros(b.hi); 174 if (lsh == 0) { 175 /* 176 * From (n1 >= b.hi) 177 * && (the most significant bit of b.hi is set), 178 * conclude that 179 * (the most significant bit of n1 is set) 180 * && (the quotient digit q0 = 0 or 1). 181 * 182 * This special case is necessary, not an optimization. 183 */ 184 185 /* 186 * The condition on the next line takes advantage of that 187 * n1 >= b.hi (true due to control flow). 188 */ 189 if (n1 > b.hi || n0 >= b.lo) { 190 q0 = 1; 191 a.lo = n0, a.hi = n1; 192 LL_SUB(a, a, b); 193 } else { 194 q0 = 0; 195 } 196 q1 = 0; 197 198 if (rp) { 199 rp->lo = n0; 200 rp->hi = n1; 201 } 202 } else { 203 PRInt64 m; 204 205 /* 206 * Normalize. 207 */ 208 rsh = 32 - lsh; 209 210 b.hi = (b.hi << lsh) | (b.lo >> rsh); 211 b.lo = b.lo << lsh; 212 n2 = n1 >> rsh; 213 n1 = (n1 << lsh) | (n0 >> rsh); 214 n0 = n0 << lsh; 215 216 a.lo = n1, a.hi = n2; 217 norm_udivmod32(&q0, &n1, a, b.hi); 218 LL_MUL32(m, q0, b.lo); 219 220 if ((m.hi > n1) || ((m.hi == n1) && (m.lo > n0))) { 221 q0--; 222 LL_SUB(m, m, b); 223 } 224 225 q1 = 0; 226 227 /* Remainder is ((n1 n0) - (m1 m0)) >> lsh */ 228 if (rp) { 229 a.lo = n0, a.hi = n1; 230 LL_SUB(a, a, m); 231 rp->lo = (a.hi << rsh) | (a.lo >> lsh); 232 rp->hi = a.hi >> lsh; 233 } 234 } 235 } 236 } 237 238 if (qp) { 239 qp->lo = q0; 240 qp->hi = q1; 241 } 242 } 243 #endif /* !HAVE_LONG_LONG */