From: Bernardo Innocenti Fix problem introduced by previous do_div() patch: - export the __div64_32 symbol for modules; - add likely() to the fast path (divisor>>32 == 0); - add __attribute__((pure)) to __div64_32() prototype so the compiler knows global memory isn't clobbered; - avoid building __div64_32() on 64bit architectures. 25-akpm/include/asm-generic/div64.h | 5 +++-- 25-akpm/include/linux/compiler.h | 18 ++++++++++++++++++ 25-akpm/lib/div64.c | 9 ++++++++- 3 files changed, 29 insertions(+), 3 deletions(-) diff -puN include/asm-generic/div64.h~div64-fix include/asm-generic/div64.h --- 25/include/asm-generic/div64.h~div64-fix Tue Jul 8 13:54:47 2003 +++ 25-akpm/include/asm-generic/div64.h Tue Jul 8 13:54:47 2003 @@ -18,6 +18,7 @@ */ #include +#include #if BITS_PER_LONG == 64 @@ -31,12 +32,12 @@ #elif BITS_PER_LONG == 32 -extern uint32_t __div64_32(uint64_t *dividend, uint32_t divisor); +extern uint32_t __div64_32(uint64_t *dividend, uint32_t divisor) __attribute_pure__; # define do_div(n,base) ({ \ uint32_t __base = (base); \ uint32_t __rem; \ - if (((n) >> 32) == 0) { \ + if (likely(((n) >> 32) == 0)) { \ __rem = (uint32_t)(n) % __base; \ (n) = (uint32_t)(n) / __base; \ } else \ diff -puN include/linux/compiler.h~div64-fix include/linux/compiler.h --- 25/include/linux/compiler.h~div64-fix Tue Jul 8 13:54:47 2003 +++ 25-akpm/include/linux/compiler.h Tue Jul 8 13:54:47 2003 @@ -56,6 +56,24 @@ #define __attribute_used__ __attribute__((__unused__)) #endif +/* + * From the GCC manual: + * + * Many functions have no effects except the return value and their + * return value depends only on the parameters and/or global + * variables. Such a function can be subject to common subexpression + * elimination and loop optimization just as an arithmetic operator + * would be. + * [...] + * The attribute `pure' is not implemented in GCC versions earlier + * than 2.96. + */ +#if (__GNUC__ == 2 && __GNUC_MINOR >= 96) || __GNUC__ > 2 +#define __attribute_pure__ __attribute__((pure)) +#else +#define __attribute_pure__ /* unimplemented */ +#endif + /* This macro obfuscates arithmetic on a variable address so that gcc shouldn't recognize the original var, and make assumptions about it */ #define RELOC_HIDE(ptr, off) \ diff -puN lib/div64.c~div64-fix lib/div64.c --- 25/lib/div64.c~div64-fix Tue Jul 8 13:54:47 2003 +++ 25-akpm/lib/div64.c Tue Jul 8 13:54:47 2003 @@ -12,13 +12,17 @@ * 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 + * for some CPUs. __div64_32() can be overridden by linking arch-specific * assembly versions such as arch/ppc/lib/div64.S and arch/sh/lib/div64.S. */ #include +#include #include +/* Not needed on 64bit architectures */ +#if BITS_PER_LONG == 32 + uint32_t __div64_32(uint64_t *n, uint32_t base) { uint32_t low, low2, high, rem; @@ -43,3 +47,6 @@ uint32_t __div64_32(uint64_t *n, uint32_ return rem; } +EXPORT_SYMBOL(__div64_32); + +#endif /* BITS_PER_LONG == 32 */ _