12c64e9cbSAndy Shevchenko // SPDX-License-Identifier: GPL-2.0
22c64e9cbSAndy Shevchenko /*
32c64e9cbSAndy Shevchenko * Copyright (C) 2003 Bernardo Innocenti <[email protected]>
42c64e9cbSAndy Shevchenko *
52c64e9cbSAndy Shevchenko * Based on former do_div() implementation from asm-parisc/div64.h:
62c64e9cbSAndy Shevchenko * Copyright (C) 1999 Hewlett-Packard Co
72c64e9cbSAndy Shevchenko * Copyright (C) 1999 David Mosberger-Tang <[email protected]>
82c64e9cbSAndy Shevchenko *
92c64e9cbSAndy Shevchenko *
102c64e9cbSAndy Shevchenko * Generic C version of 64bit/32bit division and modulo, with
112c64e9cbSAndy Shevchenko * 64bit result and 32bit remainder.
122c64e9cbSAndy Shevchenko *
132c64e9cbSAndy Shevchenko * The fast case for (n>>32 == 0) is handled inline by do_div().
142c64e9cbSAndy Shevchenko *
152c64e9cbSAndy Shevchenko * Code generated for this function might be very inefficient
162c64e9cbSAndy Shevchenko * for some CPUs. __div64_32() can be overridden by linking arch-specific
172c64e9cbSAndy Shevchenko * assembly versions such as arch/ppc/lib/div64.S and arch/sh/lib/div64.S
182c64e9cbSAndy Shevchenko * or by defining a preprocessor macro in arch/include/asm/div64.h.
192c64e9cbSAndy Shevchenko */
202c64e9cbSAndy Shevchenko
21aa6159abSAndy Shevchenko #include <linux/bitops.h>
222c64e9cbSAndy Shevchenko #include <linux/export.h>
23aa6159abSAndy Shevchenko #include <linux/math.h>
242c64e9cbSAndy Shevchenko #include <linux/math64.h>
258c86fb68SUwe Kleine-König #include <linux/minmax.h>
26aa6159abSAndy Shevchenko #include <linux/log2.h>
272c64e9cbSAndy Shevchenko
282c64e9cbSAndy Shevchenko /* Not needed on 64bit architectures */
292c64e9cbSAndy Shevchenko #if BITS_PER_LONG == 32
302c64e9cbSAndy Shevchenko
312c64e9cbSAndy Shevchenko #ifndef __div64_32
__div64_32(uint64_t * n,uint32_t base)322c64e9cbSAndy Shevchenko uint32_t __attribute__((weak)) __div64_32(uint64_t *n, uint32_t base)
332c64e9cbSAndy Shevchenko {
342c64e9cbSAndy Shevchenko uint64_t rem = *n;
352c64e9cbSAndy Shevchenko uint64_t b = base;
362c64e9cbSAndy Shevchenko uint64_t res, d = 1;
372c64e9cbSAndy Shevchenko uint32_t high = rem >> 32;
382c64e9cbSAndy Shevchenko
392c64e9cbSAndy Shevchenko /* Reduce the thing a bit first */
402c64e9cbSAndy Shevchenko res = 0;
412c64e9cbSAndy Shevchenko if (high >= base) {
422c64e9cbSAndy Shevchenko high /= base;
432c64e9cbSAndy Shevchenko res = (uint64_t) high << 32;
442c64e9cbSAndy Shevchenko rem -= (uint64_t) (high*base) << 32;
452c64e9cbSAndy Shevchenko }
462c64e9cbSAndy Shevchenko
472c64e9cbSAndy Shevchenko while ((int64_t)b > 0 && b < rem) {
482c64e9cbSAndy Shevchenko b = b+b;
492c64e9cbSAndy Shevchenko d = d+d;
502c64e9cbSAndy Shevchenko }
512c64e9cbSAndy Shevchenko
522c64e9cbSAndy Shevchenko do {
532c64e9cbSAndy Shevchenko if (rem >= b) {
542c64e9cbSAndy Shevchenko rem -= b;
552c64e9cbSAndy Shevchenko res += d;
562c64e9cbSAndy Shevchenko }
572c64e9cbSAndy Shevchenko b >>= 1;
582c64e9cbSAndy Shevchenko d >>= 1;
592c64e9cbSAndy Shevchenko } while (d);
602c64e9cbSAndy Shevchenko
612c64e9cbSAndy Shevchenko *n = res;
622c64e9cbSAndy Shevchenko return rem;
632c64e9cbSAndy Shevchenko }
642c64e9cbSAndy Shevchenko EXPORT_SYMBOL(__div64_32);
652c64e9cbSAndy Shevchenko #endif
662c64e9cbSAndy Shevchenko
672c64e9cbSAndy Shevchenko #ifndef div_s64_rem
div_s64_rem(s64 dividend,s32 divisor,s32 * remainder)682c64e9cbSAndy Shevchenko s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder)
692c64e9cbSAndy Shevchenko {
702c64e9cbSAndy Shevchenko u64 quotient;
712c64e9cbSAndy Shevchenko
722c64e9cbSAndy Shevchenko if (dividend < 0) {
732c64e9cbSAndy Shevchenko quotient = div_u64_rem(-dividend, abs(divisor), (u32 *)remainder);
742c64e9cbSAndy Shevchenko *remainder = -*remainder;
752c64e9cbSAndy Shevchenko if (divisor > 0)
762c64e9cbSAndy Shevchenko quotient = -quotient;
772c64e9cbSAndy Shevchenko } else {
782c64e9cbSAndy Shevchenko quotient = div_u64_rem(dividend, abs(divisor), (u32 *)remainder);
792c64e9cbSAndy Shevchenko if (divisor < 0)
802c64e9cbSAndy Shevchenko quotient = -quotient;
812c64e9cbSAndy Shevchenko }
822c64e9cbSAndy Shevchenko return quotient;
832c64e9cbSAndy Shevchenko }
842c64e9cbSAndy Shevchenko EXPORT_SYMBOL(div_s64_rem);
852c64e9cbSAndy Shevchenko #endif
862c64e9cbSAndy Shevchenko
87d28a1de5SLiam Beguin /*
882c64e9cbSAndy Shevchenko * div64_u64_rem - unsigned 64bit divide with 64bit divisor and remainder
892c64e9cbSAndy Shevchenko * @dividend: 64bit dividend
902c64e9cbSAndy Shevchenko * @divisor: 64bit divisor
912c64e9cbSAndy Shevchenko * @remainder: 64bit remainder
922c64e9cbSAndy Shevchenko *
932c64e9cbSAndy Shevchenko * This implementation is a comparable to algorithm used by div64_u64.
942c64e9cbSAndy Shevchenko * But this operation, which includes math for calculating the remainder,
952c64e9cbSAndy Shevchenko * is kept distinct to avoid slowing down the div64_u64 operation on 32bit
962c64e9cbSAndy Shevchenko * systems.
972c64e9cbSAndy Shevchenko */
982c64e9cbSAndy Shevchenko #ifndef div64_u64_rem
div64_u64_rem(u64 dividend,u64 divisor,u64 * remainder)992c64e9cbSAndy Shevchenko u64 div64_u64_rem(u64 dividend, u64 divisor, u64 *remainder)
1002c64e9cbSAndy Shevchenko {
1012c64e9cbSAndy Shevchenko u32 high = divisor >> 32;
1022c64e9cbSAndy Shevchenko u64 quot;
1032c64e9cbSAndy Shevchenko
1042c64e9cbSAndy Shevchenko if (high == 0) {
1052c64e9cbSAndy Shevchenko u32 rem32;
1062c64e9cbSAndy Shevchenko quot = div_u64_rem(dividend, divisor, &rem32);
1072c64e9cbSAndy Shevchenko *remainder = rem32;
1082c64e9cbSAndy Shevchenko } else {
1092c64e9cbSAndy Shevchenko int n = fls(high);
1102c64e9cbSAndy Shevchenko quot = div_u64(dividend >> n, divisor >> n);
1112c64e9cbSAndy Shevchenko
1122c64e9cbSAndy Shevchenko if (quot != 0)
1132c64e9cbSAndy Shevchenko quot--;
1142c64e9cbSAndy Shevchenko
1152c64e9cbSAndy Shevchenko *remainder = dividend - quot * divisor;
1162c64e9cbSAndy Shevchenko if (*remainder >= divisor) {
1172c64e9cbSAndy Shevchenko quot++;
1182c64e9cbSAndy Shevchenko *remainder -= divisor;
1192c64e9cbSAndy Shevchenko }
1202c64e9cbSAndy Shevchenko }
1212c64e9cbSAndy Shevchenko
1222c64e9cbSAndy Shevchenko return quot;
1232c64e9cbSAndy Shevchenko }
1242c64e9cbSAndy Shevchenko EXPORT_SYMBOL(div64_u64_rem);
1252c64e9cbSAndy Shevchenko #endif
1262c64e9cbSAndy Shevchenko
127d28a1de5SLiam Beguin /*
1282c64e9cbSAndy Shevchenko * div64_u64 - unsigned 64bit divide with 64bit divisor
1292c64e9cbSAndy Shevchenko * @dividend: 64bit dividend
1302c64e9cbSAndy Shevchenko * @divisor: 64bit divisor
1312c64e9cbSAndy Shevchenko *
1322c64e9cbSAndy Shevchenko * This implementation is a modified version of the algorithm proposed
1332c64e9cbSAndy Shevchenko * by the book 'Hacker's Delight'. The original source and full proof
1342c64e9cbSAndy Shevchenko * can be found here and is available for use without restriction.
1352c64e9cbSAndy Shevchenko *
1362c64e9cbSAndy Shevchenko * 'http://www.hackersdelight.org/hdcodetxt/divDouble.c.txt'
1372c64e9cbSAndy Shevchenko */
1382c64e9cbSAndy Shevchenko #ifndef div64_u64
div64_u64(u64 dividend,u64 divisor)1392c64e9cbSAndy Shevchenko u64 div64_u64(u64 dividend, u64 divisor)
1402c64e9cbSAndy Shevchenko {
1412c64e9cbSAndy Shevchenko u32 high = divisor >> 32;
1422c64e9cbSAndy Shevchenko u64 quot;
1432c64e9cbSAndy Shevchenko
1442c64e9cbSAndy Shevchenko if (high == 0) {
1452c64e9cbSAndy Shevchenko quot = div_u64(dividend, divisor);
1462c64e9cbSAndy Shevchenko } else {
1472c64e9cbSAndy Shevchenko int n = fls(high);
1482c64e9cbSAndy Shevchenko quot = div_u64(dividend >> n, divisor >> n);
1492c64e9cbSAndy Shevchenko
1502c64e9cbSAndy Shevchenko if (quot != 0)
1512c64e9cbSAndy Shevchenko quot--;
1522c64e9cbSAndy Shevchenko if ((dividend - quot * divisor) >= divisor)
1532c64e9cbSAndy Shevchenko quot++;
1542c64e9cbSAndy Shevchenko }
1552c64e9cbSAndy Shevchenko
1562c64e9cbSAndy Shevchenko return quot;
1572c64e9cbSAndy Shevchenko }
1582c64e9cbSAndy Shevchenko EXPORT_SYMBOL(div64_u64);
1592c64e9cbSAndy Shevchenko #endif
1602c64e9cbSAndy Shevchenko
1612c64e9cbSAndy Shevchenko #ifndef div64_s64
div64_s64(s64 dividend,s64 divisor)1622c64e9cbSAndy Shevchenko s64 div64_s64(s64 dividend, s64 divisor)
1632c64e9cbSAndy Shevchenko {
1642c64e9cbSAndy Shevchenko s64 quot, t;
1652c64e9cbSAndy Shevchenko
1662c64e9cbSAndy Shevchenko quot = div64_u64(abs(dividend), abs(divisor));
1672c64e9cbSAndy Shevchenko t = (dividend ^ divisor) >> 63;
1682c64e9cbSAndy Shevchenko
1692c64e9cbSAndy Shevchenko return (quot ^ t) - t;
1702c64e9cbSAndy Shevchenko }
1712c64e9cbSAndy Shevchenko EXPORT_SYMBOL(div64_s64);
1722c64e9cbSAndy Shevchenko #endif
1732c64e9cbSAndy Shevchenko
1742c64e9cbSAndy Shevchenko #endif /* BITS_PER_LONG == 32 */
1752c64e9cbSAndy Shevchenko
1762c64e9cbSAndy Shevchenko /*
1772c64e9cbSAndy Shevchenko * Iterative div/mod for use when dividend is not expected to be much
1782c64e9cbSAndy Shevchenko * bigger than divisor.
1792c64e9cbSAndy Shevchenko */
iter_div_u64_rem(u64 dividend,u32 divisor,u64 * remainder)1802c64e9cbSAndy Shevchenko u32 iter_div_u64_rem(u64 dividend, u32 divisor, u64 *remainder)
1812c64e9cbSAndy Shevchenko {
1822c64e9cbSAndy Shevchenko return __iter_div_u64_rem(dividend, divisor, remainder);
1832c64e9cbSAndy Shevchenko }
1842c64e9cbSAndy Shevchenko EXPORT_SYMBOL(iter_div_u64_rem);
1853dc167baSOleg Nesterov
1863dc167baSOleg Nesterov #ifndef mul_u64_u64_div_u64
mul_u64_u64_div_u64(u64 a,u64 b,u64 c)1873dc167baSOleg Nesterov u64 mul_u64_u64_div_u64(u64 a, u64 b, u64 c)
1883dc167baSOleg Nesterov {
189b29a62d8SNicolas Pitre if (ilog2(a) + ilog2(b) <= 62)
190b29a62d8SNicolas Pitre return div64_u64(a * b, c);
1913dc167baSOleg Nesterov
192b29a62d8SNicolas Pitre #if defined(__SIZEOF_INT128__)
193b29a62d8SNicolas Pitre
194b29a62d8SNicolas Pitre /* native 64x64=128 bits multiplication */
195b29a62d8SNicolas Pitre u128 prod = (u128)a * b;
196b29a62d8SNicolas Pitre u64 n_lo = prod, n_hi = prod >> 64;
197b29a62d8SNicolas Pitre
198b29a62d8SNicolas Pitre #else
199b29a62d8SNicolas Pitre
200b29a62d8SNicolas Pitre /* perform a 64x64=128 bits multiplication manually */
201b29a62d8SNicolas Pitre u32 a_lo = a, a_hi = a >> 32, b_lo = b, b_hi = b >> 32;
202b29a62d8SNicolas Pitre u64 x, y, z;
203b29a62d8SNicolas Pitre
204b29a62d8SNicolas Pitre x = (u64)a_lo * b_lo;
205b29a62d8SNicolas Pitre y = (u64)a_lo * b_hi + (u32)(x >> 32);
206b29a62d8SNicolas Pitre z = (u64)a_hi * b_hi + (u32)(y >> 32);
207b29a62d8SNicolas Pitre y = (u64)a_hi * b_lo + (u32)y;
208b29a62d8SNicolas Pitre z += (u32)(y >> 32);
209b29a62d8SNicolas Pitre x = (y << 32) + (u32)x;
210b29a62d8SNicolas Pitre
211b29a62d8SNicolas Pitre u64 n_lo = x, n_hi = z;
212b29a62d8SNicolas Pitre
213b29a62d8SNicolas Pitre #endif
214b29a62d8SNicolas Pitre
215*1635e62eSNicolas Pitre /* make sure c is not zero, trigger exception otherwise */
216*1635e62eSNicolas Pitre #pragma GCC diagnostic push
217*1635e62eSNicolas Pitre #pragma GCC diagnostic ignored "-Wdiv-by-zero"
218*1635e62eSNicolas Pitre if (unlikely(c == 0))
219*1635e62eSNicolas Pitre return 1/0;
220*1635e62eSNicolas Pitre #pragma GCC diagnostic pop
221*1635e62eSNicolas Pitre
222b29a62d8SNicolas Pitre int shift = __builtin_ctzll(c);
223b29a62d8SNicolas Pitre
224b29a62d8SNicolas Pitre /* try reducing the fraction in case the dividend becomes <= 64 bits */
225b29a62d8SNicolas Pitre if ((n_hi >> shift) == 0) {
226*1635e62eSNicolas Pitre u64 n = shift ? (n_lo >> shift) | (n_hi << (64 - shift)) : n_lo;
227b29a62d8SNicolas Pitre
228b29a62d8SNicolas Pitre return div64_u64(n, c >> shift);
2293dc167baSOleg Nesterov /*
230b29a62d8SNicolas Pitre * The remainder value if needed would be:
231b29a62d8SNicolas Pitre * res = div64_u64_rem(n, c >> shift, &rem);
232b29a62d8SNicolas Pitre * rem = (rem << shift) + (n_lo - (n << shift));
2338c86fb68SUwe Kleine-König */
234b29a62d8SNicolas Pitre }
2358c86fb68SUwe Kleine-König
236b29a62d8SNicolas Pitre if (n_hi >= c) {
237b29a62d8SNicolas Pitre /* overflow: result is unrepresentable in a u64 */
238b29a62d8SNicolas Pitre return -1;
239b29a62d8SNicolas Pitre }
2403dc167baSOleg Nesterov
241b29a62d8SNicolas Pitre /* Do the full 128 by 64 bits division */
242b29a62d8SNicolas Pitre
243b29a62d8SNicolas Pitre shift = __builtin_clzll(c);
244b29a62d8SNicolas Pitre c <<= shift;
245b29a62d8SNicolas Pitre
246b29a62d8SNicolas Pitre int p = 64 + shift;
247b29a62d8SNicolas Pitre u64 res = 0;
248b29a62d8SNicolas Pitre bool carry;
249b29a62d8SNicolas Pitre
250b29a62d8SNicolas Pitre do {
251b29a62d8SNicolas Pitre carry = n_hi >> 63;
252b29a62d8SNicolas Pitre shift = carry ? 1 : __builtin_clzll(n_hi);
253b29a62d8SNicolas Pitre if (p < shift)
254b29a62d8SNicolas Pitre break;
255b29a62d8SNicolas Pitre p -= shift;
256b29a62d8SNicolas Pitre n_hi <<= shift;
257b29a62d8SNicolas Pitre n_hi |= n_lo >> (64 - shift);
258b29a62d8SNicolas Pitre n_lo <<= shift;
259b29a62d8SNicolas Pitre if (carry || (n_hi >= c)) {
260b29a62d8SNicolas Pitre n_hi -= c;
261b29a62d8SNicolas Pitre res |= 1ULL << p;
262b29a62d8SNicolas Pitre }
263b29a62d8SNicolas Pitre } while (n_hi);
264b29a62d8SNicolas Pitre /* The remainder value if needed would be n_hi << p */
265b29a62d8SNicolas Pitre
2663dc167baSOleg Nesterov return res;
2673dc167baSOleg Nesterov }
268bf459478SDavid S. Miller EXPORT_SYMBOL(mul_u64_u64_div_u64);
2693dc167baSOleg Nesterov #endif
270