Blame view

lib/div64.c 4.26 KB
b24413180   Greg Kroah-Hartman   License cleanup: ...
1
  // SPDX-License-Identifier: GPL-2.0
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  /*
   * Copyright (C) 2003 Bernardo Innocenti <bernie@develer.com>
   *
   * Based on former do_div() implementation from asm-parisc/div64.h:
   *	Copyright (C) 1999 Hewlett-Packard Co
   *	Copyright (C) 1999 David Mosberger-Tang <davidm@hpl.hp.com>
   *
   *
   * Generic C version of 64bit/32bit division and modulo, with
   * 64bit result and 32bit remainder.
   *
   * The fast case for (n>>32 == 0) is handled inline by do_div(). 
   *
   * Code generated for this function might be very inefficient
   * for some CPUs. __div64_32() can be overridden by linking arch-specific
dce1eb93b   Nicolas Pitre   __div64_32(): mak...
17
18
   * assembly versions such as arch/ppc/lib/div64.S and arch/sh/lib/div64.S
   * or by defining a preprocessor macro in arch/include/asm/div64.h.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
   */
8bc3bcc93   Paul Gortmaker   lib: reduce the u...
20
21
  #include <linux/export.h>
  #include <linux/kernel.h>
2418f4f28   Roman Zippel   introduce explici...
22
  #include <linux/math64.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
24
25
  
  /* Not needed on 64bit architectures */
  #if BITS_PER_LONG == 32
dce1eb93b   Nicolas Pitre   __div64_32(): mak...
26
  #ifndef __div64_32
cb8c181f2   David S. Miller   [S390]: Fix build...
27
  uint32_t __attribute__((weak)) __div64_32(uint64_t *n, uint32_t base)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
  {
  	uint64_t rem = *n;
  	uint64_t b = base;
  	uint64_t res, d = 1;
  	uint32_t high = rem >> 32;
  
  	/* Reduce the thing a bit first */
  	res = 0;
  	if (high >= base) {
  		high /= base;
  		res = (uint64_t) high << 32;
  		rem -= (uint64_t) (high*base) << 32;
  	}
  
  	while ((int64_t)b > 0 && b < rem) {
  		b = b+b;
  		d = d+d;
  	}
  
  	do {
  		if (rem >= b) {
  			rem -= b;
  			res += d;
  		}
  		b >>= 1;
  		d >>= 1;
  	} while (d);
  
  	*n = res;
  	return rem;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
59
  EXPORT_SYMBOL(__div64_32);
dce1eb93b   Nicolas Pitre   __div64_32(): mak...
60
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61

6ec72e61c   Randy Dunlap   div64: add missin...
62
63
64
65
66
67
  /**
   * div_s64_rem - signed 64bit divide with 64bit divisor and remainder
   * @dividend:	64bit dividend
   * @divisor:	64bit divisor
   * @remainder:  64bit remainder
   */
2418f4f28   Roman Zippel   introduce explici...
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
  #ifndef div_s64_rem
  s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder)
  {
  	u64 quotient;
  
  	if (dividend < 0) {
  		quotient = div_u64_rem(-dividend, abs(divisor), (u32 *)remainder);
  		*remainder = -*remainder;
  		if (divisor > 0)
  			quotient = -quotient;
  	} else {
  		quotient = div_u64_rem(dividend, abs(divisor), (u32 *)remainder);
  		if (divisor < 0)
  			quotient = -quotient;
  	}
  	return quotient;
  }
  EXPORT_SYMBOL(div_s64_rem);
  #endif
658716d19   Brian Behlendorf   div64_u64(): impr...
87
  /**
eb18cba78   Mike Snitzer   math64: New separ...
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
   * div64_u64_rem - unsigned 64bit divide with 64bit divisor and remainder
   * @dividend:	64bit dividend
   * @divisor:	64bit divisor
   * @remainder:  64bit remainder
   *
   * This implementation is a comparable to algorithm used by div64_u64.
   * But this operation, which includes math for calculating the remainder,
   * is kept distinct to avoid slowing down the div64_u64 operation on 32bit
   * systems.
   */
  #ifndef div64_u64_rem
  u64 div64_u64_rem(u64 dividend, u64 divisor, u64 *remainder)
  {
  	u32 high = divisor >> 32;
  	u64 quot;
  
  	if (high == 0) {
  		u32 rem32;
  		quot = div_u64_rem(dividend, divisor, &rem32);
  		*remainder = rem32;
  	} else {
  		int n = 1 + fls(high);
  		quot = div_u64(dividend >> n, divisor >> n);
  
  		if (quot != 0)
  			quot--;
  
  		*remainder = dividend - quot * divisor;
  		if (*remainder >= divisor) {
  			quot++;
  			*remainder -= divisor;
  		}
  	}
  
  	return quot;
  }
  EXPORT_SYMBOL(div64_u64_rem);
  #endif
  
  /**
f30021341   Stanislaw Gruszka   Revert "math64: N...
128
   * div64_u64 - unsigned 64bit divide with 64bit divisor
658716d19   Brian Behlendorf   div64_u64(): impr...
129
130
131
132
133
134
135
   * @dividend:	64bit dividend
   * @divisor:	64bit divisor
   *
   * This implementation is a modified version of the algorithm proposed
   * by the book 'Hacker's Delight'.  The original source and full proof
   * can be found here and is available for use without restriction.
   *
28ca84e04   Heinrich Schuchardt   lib: correct link...
136
   * 'http://www.hackersdelight.org/hdcodetxt/divDouble.c.txt'
658716d19   Brian Behlendorf   div64_u64(): impr...
137
   */
f30021341   Stanislaw Gruszka   Revert "math64: N...
138
139
  #ifndef div64_u64
  u64 div64_u64(u64 dividend, u64 divisor)
3927f2e8f   Stephen Hemminger   [NET]: div64_64 c...
140
  {
658716d19   Brian Behlendorf   div64_u64(): impr...
141
142
  	u32 high = divisor >> 32;
  	u64 quot;
3927f2e8f   Stephen Hemminger   [NET]: div64_64 c...
143

658716d19   Brian Behlendorf   div64_u64(): impr...
144
  	if (high == 0) {
f30021341   Stanislaw Gruszka   Revert "math64: N...
145
  		quot = div_u64(dividend, divisor);
658716d19   Brian Behlendorf   div64_u64(): impr...
146
147
148
  	} else {
  		int n = 1 + fls(high);
  		quot = div_u64(dividend >> n, divisor >> n);
3927f2e8f   Stephen Hemminger   [NET]: div64_64 c...
149

658716d19   Brian Behlendorf   div64_u64(): impr...
150
151
  		if (quot != 0)
  			quot--;
f30021341   Stanislaw Gruszka   Revert "math64: N...
152
  		if ((dividend - quot * divisor) >= divisor)
658716d19   Brian Behlendorf   div64_u64(): impr...
153
154
  			quot++;
  	}
3927f2e8f   Stephen Hemminger   [NET]: div64_64 c...
155

658716d19   Brian Behlendorf   div64_u64(): impr...
156
  	return quot;
3927f2e8f   Stephen Hemminger   [NET]: div64_64 c...
157
  }
f30021341   Stanislaw Gruszka   Revert "math64: N...
158
  EXPORT_SYMBOL(div64_u64);
6f6d6a1a6   Roman Zippel   rename div64_64 t...
159
  #endif
3927f2e8f   Stephen Hemminger   [NET]: div64_64 c...
160

658716d19   Brian Behlendorf   div64_u64(): impr...
161
162
163
164
165
166
167
168
169
  /**
   * div64_s64 - signed 64bit divide with 64bit divisor
   * @dividend:	64bit dividend
   * @divisor:	64bit divisor
   */
  #ifndef div64_s64
  s64 div64_s64(s64 dividend, s64 divisor)
  {
  	s64 quot, t;
79211c8ed   Andrew Morton   remove abs64()
170
  	quot = div64_u64(abs(dividend), abs(divisor));
658716d19   Brian Behlendorf   div64_u64(): impr...
171
172
173
174
175
176
  	t = (dividend ^ divisor) >> 63;
  
  	return (quot ^ t) - t;
  }
  EXPORT_SYMBOL(div64_s64);
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
177
  #endif /* BITS_PER_LONG == 32 */
f595ec964   Jeremy Fitzhardinge   common implementa...
178
179
180
181
182
183
184
  
  /*
   * Iterative div/mod for use when dividend is not expected to be much
   * bigger than divisor.
   */
  u32 iter_div_u64_rem(u64 dividend, u32 divisor, u64 *remainder)
  {
d5e181f78   Jeremy Fitzhardinge   add an inlined ve...
185
  	return __iter_div_u64_rem(dividend, divisor, remainder);
f595ec964   Jeremy Fitzhardinge   common implementa...
186
187
  }
  EXPORT_SYMBOL(iter_div_u64_rem);