xref: /linux-6.15/lib/math/div64.c (revision 1635e62e)
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