aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorRoman Zippel <zippel@linux-m68k.org>2008-05-01 07:34:25 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-05-01 11:03:58 -0400
commit2418f4f28f8467b92a6177af32d05737ebf6206c (patch)
treecd35f4feef2ed3078ebb7ce6dcaf5f627299944e /include
parentadafbedf0c31ae1cde62035c82857f5e376af553 (diff)
introduce explicit signed/unsigned 64bit divide
The current do_div doesn't explicitly say that it's unsigned and the signed counterpart is missing, which is e.g. needed when dealing with time values. This introduces 64bit signed/unsigned divide functions which also attempts to cleanup the somewhat awkward calling API, which often requires the use of temporary variables for the dividend. To avoid the need for temporary variables everywhere for the remainder, each divide variant also provides a version which doesn't return the remainder. Each architecture can now provide optimized versions of these function, otherwise generic fallback implementations will be used. As an example I provided an alternative for the current x86 divide, which avoids the asm casts and using an union allows gcc to generate better code. It also avoids the upper divde in a few more cases, where the result is known (i.e. upper quotient is zero). Signed-off-by: Roman Zippel <zippel@linux-m68k.org> Cc: john stultz <johnstul@us.ibm.com> Cc: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'include')
-rw-r--r--include/asm-x86/div64.h20
-rw-r--r--include/linux/math64.h72
2 files changed, 92 insertions, 0 deletions
diff --git a/include/asm-x86/div64.h b/include/asm-x86/div64.h
index 0dbf8bf3ef0a..c7892cfe9ce6 100644
--- a/include/asm-x86/div64.h
+++ b/include/asm-x86/div64.h
@@ -51,6 +51,26 @@ static inline long div_ll_X_l_rem(long long divs, long div, long *rem)
51 51
52} 52}
53 53
54static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder)
55{
56 union {
57 u64 v64;
58 u32 v32[2];
59 } d = { dividend };
60 u32 upper;
61
62 upper = d.v32[1];
63 d.v32[1] = 0;
64 if (upper >= divisor) {
65 d.v32[1] = upper / divisor;
66 upper %= divisor;
67 }
68 asm ("divl %2" : "=a" (d.v32[0]), "=d" (*remainder) :
69 "rm" (divisor), "0" (d.v32[0]), "1" (upper));
70 return d.v64;
71}
72#define div_u64_rem div_u64_rem
73
54extern uint64_t div64_64(uint64_t dividend, uint64_t divisor); 74extern uint64_t div64_64(uint64_t dividend, uint64_t divisor);
55 75
56#else 76#else
diff --git a/include/linux/math64.h b/include/linux/math64.h
new file mode 100644
index 000000000000..6d1716641008
--- /dev/null
+++ b/include/linux/math64.h
@@ -0,0 +1,72 @@
1#ifndef _LINUX_MATH64_H
2#define _LINUX_MATH64_H
3
4#include <linux/types.h>
5#include <asm/div64.h>
6
7#if BITS_PER_LONG == 64
8
9/**
10 * div_u64_rem - unsigned 64bit divide with 32bit divisor with remainder
11 *
12 * This is commonly provided by 32bit archs to provide an optimized 64bit
13 * divide.
14 */
15static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder)
16{
17 *remainder = dividend % divisor;
18 return dividend / divisor;
19}
20
21/**
22 * div_s64_rem - signed 64bit divide with 32bit divisor with remainder
23 */
24static inline s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder)
25{
26 *remainder = dividend % divisor;
27 return dividend / divisor;
28}
29
30#elif BITS_PER_LONG == 32
31
32#ifndef div_u64_rem
33static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder)
34{
35 *remainder = do_div(dividend, divisor);
36 return dividend;
37}
38#endif
39
40#ifndef div_s64_rem
41extern s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder);
42#endif
43
44#endif /* BITS_PER_LONG */
45
46/**
47 * div_u64 - unsigned 64bit divide with 32bit divisor
48 *
49 * This is the most common 64bit divide and should be used if possible,
50 * as many 32bit archs can optimize this variant better than a full 64bit
51 * divide.
52 */
53#ifndef div_u64
54static inline u64 div_u64(u64 dividend, u32 divisor)
55{
56 u32 remainder;
57 return div_u64_rem(dividend, divisor, &remainder);
58}
59#endif
60
61/**
62 * div_s64 - signed 64bit divide with 32bit divisor
63 */
64#ifndef div_s64
65static inline s64 div_s64(s64 dividend, s32 divisor)
66{
67 s32 remainder;
68 return div_s64_rem(dividend, divisor, &remainder);
69}
70#endif
71
72#endif /* _LINUX_MATH64_H */