diff options
author | Roman Zippel <zippel@linux-m68k.org> | 2008-05-01 15:34:25 +0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-05-01 19:03:58 +0400 |
commit | 2418f4f28f8467b92a6177af32d05737ebf6206c (patch) | |
tree | cd35f4feef2ed3078ebb7ce6dcaf5f627299944e /include/asm-x86 | |
parent | adafbedf0c31ae1cde62035c82857f5e376af553 (diff) | |
download | linux-2418f4f28f8467b92a6177af32d05737ebf6206c.tar.xz |
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/asm-x86')
-rw-r--r-- | include/asm-x86/div64.h | 20 |
1 files changed, 20 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) } +static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder) +{ + union { + u64 v64; + u32 v32[2]; + } d = { dividend }; + u32 upper; + + upper = d.v32[1]; + d.v32[1] = 0; + if (upper >= divisor) { + d.v32[1] = upper / divisor; + upper %= divisor; + } + asm ("divl %2" : "=a" (d.v32[0]), "=d" (*remainder) : + "rm" (divisor), "0" (d.v32[0]), "1" (upper)); + return d.v64; +} +#define div_u64_rem div_u64_rem + extern uint64_t div64_64(uint64_t dividend, uint64_t divisor); #else |