nsprpub/pr/src/misc/prlong.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial