1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/nsprpub/pr/src/misc/prlong.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,239 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "prlong.h" 1.10 + 1.11 +static PRInt64 ll_zero = LL_INIT( 0x00000000,0x00000000 ); 1.12 +static PRInt64 ll_maxint = LL_INIT( 0x7fffffff, 0xffffffff ); 1.13 +static PRInt64 ll_minint = LL_INIT( 0x80000000, 0x00000000 ); 1.14 +static PRUint64 ll_maxuint = LL_INIT( 0xffffffff, 0xffffffff ); 1.15 + 1.16 +PR_IMPLEMENT(PRInt64) LL_Zero(void) { return ll_zero; } 1.17 +PR_IMPLEMENT(PRInt64) LL_MaxInt(void) { return ll_maxint; } 1.18 +PR_IMPLEMENT(PRInt64) LL_MinInt(void) { return ll_minint; } 1.19 +PR_IMPLEMENT(PRUint64) LL_MaxUint(void) { return ll_maxuint; } 1.20 + 1.21 +#ifndef HAVE_LONG_LONG 1.22 +/* 1.23 +** Divide 64-bit a by 32-bit b, which must be normalized so its high bit is 1. 1.24 +*/ 1.25 +static void norm_udivmod32(PRUint32 *qp, PRUint32 *rp, PRUint64 a, PRUint32 b) 1.26 +{ 1.27 + PRUint32 d1, d0, q1, q0; 1.28 + PRUint32 r1, r0, m; 1.29 + 1.30 + d1 = _hi16(b); 1.31 + d0 = _lo16(b); 1.32 + r1 = a.hi % d1; 1.33 + q1 = a.hi / d1; 1.34 + m = q1 * d0; 1.35 + r1 = (r1 << 16) | _hi16(a.lo); 1.36 + if (r1 < m) { 1.37 + q1--, r1 += b; 1.38 + if (r1 >= b /* i.e., we didn't get a carry when adding to r1 */ 1.39 + && r1 < m) { 1.40 + q1--, r1 += b; 1.41 + } 1.42 + } 1.43 + r1 -= m; 1.44 + r0 = r1 % d1; 1.45 + q0 = r1 / d1; 1.46 + m = q0 * d0; 1.47 + r0 = (r0 << 16) | _lo16(a.lo); 1.48 + if (r0 < m) { 1.49 + q0--, r0 += b; 1.50 + if (r0 >= b 1.51 + && r0 < m) { 1.52 + q0--, r0 += b; 1.53 + } 1.54 + } 1.55 + *qp = (q1 << 16) | q0; 1.56 + *rp = r0 - m; 1.57 +} 1.58 + 1.59 +static PRUint32 CountLeadingZeros(PRUint32 a) 1.60 +{ 1.61 + PRUint32 t; 1.62 + PRUint32 r = 32; 1.63 + 1.64 + if ((t = a >> 16) != 0) 1.65 + r -= 16, a = t; 1.66 + if ((t = a >> 8) != 0) 1.67 + r -= 8, a = t; 1.68 + if ((t = a >> 4) != 0) 1.69 + r -= 4, a = t; 1.70 + if ((t = a >> 2) != 0) 1.71 + r -= 2, a = t; 1.72 + if ((t = a >> 1) != 0) 1.73 + r -= 1, a = t; 1.74 + if (a & 1) 1.75 + r--; 1.76 + return r; 1.77 +} 1.78 + 1.79 +PR_IMPLEMENT(void) ll_udivmod(PRUint64 *qp, PRUint64 *rp, PRUint64 a, PRUint64 b) 1.80 +{ 1.81 + PRUint32 n0, n1, n2; 1.82 + PRUint32 q0, q1; 1.83 + PRUint32 rsh, lsh; 1.84 + 1.85 + n0 = a.lo; 1.86 + n1 = a.hi; 1.87 + 1.88 + if (b.hi == 0) { 1.89 + if (b.lo > n1) { 1.90 + /* (0 q0) = (n1 n0) / (0 D0) */ 1.91 + 1.92 + lsh = CountLeadingZeros(b.lo); 1.93 + 1.94 + if (lsh) { 1.95 + /* 1.96 + * Normalize, i.e. make the most significant bit of the 1.97 + * denominator be set. 1.98 + */ 1.99 + b.lo = b.lo << lsh; 1.100 + n1 = (n1 << lsh) | (n0 >> (32 - lsh)); 1.101 + n0 = n0 << lsh; 1.102 + } 1.103 + 1.104 + a.lo = n0, a.hi = n1; 1.105 + norm_udivmod32(&q0, &n0, a, b.lo); 1.106 + q1 = 0; 1.107 + 1.108 + /* remainder is in n0 >> lsh */ 1.109 + } else { 1.110 + /* (q1 q0) = (n1 n0) / (0 d0) */ 1.111 + 1.112 + if (b.lo == 0) /* user wants to divide by zero! */ 1.113 + b.lo = 1 / b.lo; /* so go ahead and crash */ 1.114 + 1.115 + lsh = CountLeadingZeros(b.lo); 1.116 + 1.117 + if (lsh == 0) { 1.118 + /* 1.119 + * From (n1 >= b.lo) 1.120 + * && (the most significant bit of b.lo is set), 1.121 + * conclude that 1.122 + * (the most significant bit of n1 is set) 1.123 + * && (the leading quotient digit q1 = 1). 1.124 + * 1.125 + * This special case is necessary, not an optimization 1.126 + * (Shifts counts of 32 are undefined). 1.127 + */ 1.128 + n1 -= b.lo; 1.129 + q1 = 1; 1.130 + } else { 1.131 + /* 1.132 + * Normalize. 1.133 + */ 1.134 + rsh = 32 - lsh; 1.135 + 1.136 + b.lo = b.lo << lsh; 1.137 + n2 = n1 >> rsh; 1.138 + n1 = (n1 << lsh) | (n0 >> rsh); 1.139 + n0 = n0 << lsh; 1.140 + 1.141 + a.lo = n1, a.hi = n2; 1.142 + norm_udivmod32(&q1, &n1, a, b.lo); 1.143 + } 1.144 + 1.145 + /* n1 != b.lo... */ 1.146 + 1.147 + a.lo = n0, a.hi = n1; 1.148 + norm_udivmod32(&q0, &n0, a, b.lo); 1.149 + 1.150 + /* remainder in n0 >> lsh */ 1.151 + } 1.152 + 1.153 + if (rp) { 1.154 + rp->lo = n0 >> lsh; 1.155 + rp->hi = 0; 1.156 + } 1.157 + } else { 1.158 + if (b.hi > n1) { 1.159 + /* (0 0) = (n1 n0) / (D1 d0) */ 1.160 + 1.161 + q0 = 0; 1.162 + q1 = 0; 1.163 + 1.164 + /* remainder in (n1 n0) */ 1.165 + if (rp) { 1.166 + rp->lo = n0; 1.167 + rp->hi = n1; 1.168 + } 1.169 + } else { 1.170 + /* (0 q0) = (n1 n0) / (d1 d0) */ 1.171 + 1.172 + lsh = CountLeadingZeros(b.hi); 1.173 + if (lsh == 0) { 1.174 + /* 1.175 + * From (n1 >= b.hi) 1.176 + * && (the most significant bit of b.hi is set), 1.177 + * conclude that 1.178 + * (the most significant bit of n1 is set) 1.179 + * && (the quotient digit q0 = 0 or 1). 1.180 + * 1.181 + * This special case is necessary, not an optimization. 1.182 + */ 1.183 + 1.184 + /* 1.185 + * The condition on the next line takes advantage of that 1.186 + * n1 >= b.hi (true due to control flow). 1.187 + */ 1.188 + if (n1 > b.hi || n0 >= b.lo) { 1.189 + q0 = 1; 1.190 + a.lo = n0, a.hi = n1; 1.191 + LL_SUB(a, a, b); 1.192 + } else { 1.193 + q0 = 0; 1.194 + } 1.195 + q1 = 0; 1.196 + 1.197 + if (rp) { 1.198 + rp->lo = n0; 1.199 + rp->hi = n1; 1.200 + } 1.201 + } else { 1.202 + PRInt64 m; 1.203 + 1.204 + /* 1.205 + * Normalize. 1.206 + */ 1.207 + rsh = 32 - lsh; 1.208 + 1.209 + b.hi = (b.hi << lsh) | (b.lo >> rsh); 1.210 + b.lo = b.lo << lsh; 1.211 + n2 = n1 >> rsh; 1.212 + n1 = (n1 << lsh) | (n0 >> rsh); 1.213 + n0 = n0 << lsh; 1.214 + 1.215 + a.lo = n1, a.hi = n2; 1.216 + norm_udivmod32(&q0, &n1, a, b.hi); 1.217 + LL_MUL32(m, q0, b.lo); 1.218 + 1.219 + if ((m.hi > n1) || ((m.hi == n1) && (m.lo > n0))) { 1.220 + q0--; 1.221 + LL_SUB(m, m, b); 1.222 + } 1.223 + 1.224 + q1 = 0; 1.225 + 1.226 + /* Remainder is ((n1 n0) - (m1 m0)) >> lsh */ 1.227 + if (rp) { 1.228 + a.lo = n0, a.hi = n1; 1.229 + LL_SUB(a, a, m); 1.230 + rp->lo = (a.hi << rsh) | (a.lo >> lsh); 1.231 + rp->hi = a.hi >> lsh; 1.232 + } 1.233 + } 1.234 + } 1.235 + } 1.236 + 1.237 + if (qp) { 1.238 + qp->lo = q0; 1.239 + qp->hi = q1; 1.240 + } 1.241 +} 1.242 +#endif /* !HAVE_LONG_LONG */