2002-01-25 19:35:36

by Momchil Velikov

[permalink] [raw]
Subject: [PATCH] 64-bit divide tweaks

Hi there,

printk, etc. are broken wrt printing 64-bit numbers (%ll, %L).

This patch fixes do_div, which did (on some archs) 32-bit divide.

Regards,
-velco

===== drivers/net/sk98lin/skproc.c 1.1 vs edited =====
--- 1.1/drivers/net/sk98lin/skproc.c Sat Dec 8 02:14:15 2001
+++ edited/drivers/net/sk98lin/skproc.c Fri Jan 25 21:20:06 2002
@@ -339,17 +339,6 @@
return (Rest);
}

-
-#if 0
-#define do_div(n,base) ({ \
-long long __res; \
-__res = ((unsigned long long) n) % (unsigned) base; \
-n = ((unsigned long long) n) / (unsigned) base; \
-__res; })
-
-#endif
-
-
/*****************************************************************************
*
* SkNumber - Print results
===== include/asm-arm/div64.h 1.1 vs edited =====
--- 1.1/include/asm-arm/div64.h Sat Dec 8 02:13:45 2001
+++ edited/include/asm-arm/div64.h Fri Jan 25 21:21:56 2002
@@ -1,12 +1,11 @@
#ifndef __ASM_ARM_DIV64
#define __ASM_ARM_DIV64

-/* We're not 64-bit, but... */
#define do_div(n,base) \
({ \
int __res; \
- __res = ((unsigned long)n) % (unsigned int)base; \
- n = ((unsigned long)n) / (unsigned int)base; \
+ __res = ((unsigned long long)n) % (unsigned int)base; \
+ n = ((unsigned long long)n) / (unsigned int)base; \
__res; \
})

===== include/asm-cris/div64.h 1.1 vs edited =====
--- 1.1/include/asm-cris/div64.h Sat Dec 8 02:13:57 2001
+++ edited/include/asm-cris/div64.h Fri Jan 25 21:22:19 2002
@@ -3,12 +3,11 @@

/* copy from asm-arm */

-/* We're not 64-bit, but... */
#define do_div(n,base) \
({ \
int __res; \
- __res = ((unsigned long)n) % (unsigned int)base; \
- n = ((unsigned long)n) / (unsigned int)base; \
+ __res = ((unsigned long long)n) % (unsigned int)base; \
+ n = ((unsigned long long)n) / (unsigned int)base; \
__res; \
})

===== include/asm-m68k/div64.h 1.1 vs edited =====
--- 1.1/include/asm-m68k/div64.h Sat Dec 8 02:13:35 2001
+++ edited/include/asm-m68k/div64.h Fri Jan 25 21:23:59 2002
@@ -26,8 +26,8 @@
#else
#define do_div(n,base) ({ \
int __res; \
- __res = ((unsigned long) n) % (unsigned) base; \
- n = ((unsigned long) n) / (unsigned) base; \
+ __res = ((unsigned long long) n) % (unsigned) base; \
+ n = ((unsigned long long) n) / (unsigned) base; \
__res; \
})
#endif
===== include/asm-ppc/div64.h 1.1 vs edited =====
--- 1.1/include/asm-ppc/div64.h Sat Dec 8 02:13:37 2001
+++ edited/include/asm-ppc/div64.h Fri Jan 25 21:28:49 2002
@@ -4,10 +4,9 @@
#ifndef __PPC_DIV64
#define __PPC_DIV64

-#define do_div(n,base) ({ \
-int __res; \
-__res = ((unsigned long) n) % (unsigned) base; \
-n = ((unsigned long) n) / (unsigned) base; \
-__res; })
-
+#define do_div(n,base) ({ \
+ int __res; \
+ __res = ((unsigned long long) n) % (unsigned) base; \
+ n = ((unsigned long long) n) / (unsigned) base; \
+ __res; })
#endif
===== include/asm-sh/div64.h 1.1 vs edited =====
--- 1.1/include/asm-sh/div64.h Sat Dec 8 02:13:46 2001
+++ edited/include/asm-sh/div64.h Fri Jan 25 21:29:31 2002
@@ -1,10 +1,9 @@
#ifndef __ASM_SH_DIV64
#define __ASM_SH_DIV64

-#define do_div(n,base) ({ \
-int __res; \
-__res = ((unsigned long) n) % (unsigned) base; \
-n = ((unsigned long) n) / (unsigned) base; \
-__res; })
-
+#define do_div(n,base) ({ \
+ int __res; \
+ __res = ((unsigned long long) n) % (unsigned) base; \
+ n = ((unsigned long long) n) / (unsigned) base; \
+ __res; })
#endif /* __ASM_SH_DIV64 */
===== include/asm-sparc/div64.h 1.1 vs edited =====
--- 1.1/include/asm-sparc/div64.h Sat Dec 8 02:13:36 2001
+++ edited/include/asm-sparc/div64.h Fri Jan 25 21:25:39 2002
@@ -1,11 +1,10 @@
#ifndef __SPARC_DIV64
#define __SPARC_DIV64

-/* We're not 64-bit, but... */
#define do_div(n,base) ({ \
int __res; \
- __res = ((unsigned long) n) % (unsigned) base; \
- n = ((unsigned long) n) / (unsigned) base; \
+ __res = ((unsigned long long) n) % (unsigned) base; \
+ n = ((unsigned long long) n) / (unsigned) base; \
__res; })

#endif /* __SPARC_DIV64 */


2002-01-25 19:40:46

by Jeff Garzik

[permalink] [raw]
Subject: Re: [PATCH] 64-bit divide tweaks

If you are gonna hack them all anyway, why not turn them into static
inlines...
--
Jeff Garzik | "I went through my candy like hot oatmeal
Building 1024 | through an internally-buttered weasel."
MandrakeSoft | - goats.com

2002-01-25 21:50:55

by Tim Schmielau

[permalink] [raw]
Subject: Re: [PATCH] 64-bit divide tweaks

On Fri, 25 Jan 2002, Jeff Garzik wrote:

> If you are gonna hack them all anyway, why not turn them into static
> inlines...

Probably a good idea, but then all user need some change like
do_div(n,base) --> do_div(&n,base)
as do_div currently is not valid C semantics.

Tim

2002-01-27 18:04:41

by Troy Benjegerdes

[permalink] [raw]
Subject: Re: [PATCH] 64-bit divide tweaks

On Fri, Jan 25, 2002 at 09:34:43PM +0200, Momchil Velikov wrote:
> Hi there,
>
> printk, etc. are broken wrt printing 64-bit numbers (%ll, %L).
>
> This patch fixes do_div, which did (on some archs) 32-bit divide.

Have you tried compiling any of these arches?

Anything that doesn't include libgcc will die a link missing symbols for
__udivdi3 and __umoddi3.

>
> Regards,
> -velco
>
> ===== drivers/net/sk98lin/skproc.c 1.1 vs edited =====
> --- 1.1/drivers/net/sk98lin/skproc.c Sat Dec 8 02:14:15 2001
> +++ edited/drivers/net/sk98lin/skproc.c Fri Jan 25 21:20:06 2002
> @@ -339,17 +339,6 @@
> return (Rest);
> }
>
> -
> -#if 0
> -#define do_div(n,base) ({ \
> -long long __res; \
> -__res = ((unsigned long long) n) % (unsigned) base; \
> -n = ((unsigned long long) n) / (unsigned) base; \
> -__res; })
> -
> -#endif
> -
> -
> /*****************************************************************************
> *
> * SkNumber - Print results
> ===== include/asm-arm/div64.h 1.1 vs edited =====
> --- 1.1/include/asm-arm/div64.h Sat Dec 8 02:13:45 2001
> +++ edited/include/asm-arm/div64.h Fri Jan 25 21:21:56 2002
> @@ -1,12 +1,11 @@
> #ifndef __ASM_ARM_DIV64
> #define __ASM_ARM_DIV64
>
> -/* We're not 64-bit, but... */
> #define do_div(n,base) \
> ({ \
> int __res; \
> - __res = ((unsigned long)n) % (unsigned int)base; \
> - n = ((unsigned long)n) / (unsigned int)base; \
> + __res = ((unsigned long long)n) % (unsigned int)base; \
> + n = ((unsigned long long)n) / (unsigned int)base; \
> __res; \
> })
>
> ===== include/asm-cris/div64.h 1.1 vs edited =====
> --- 1.1/include/asm-cris/div64.h Sat Dec 8 02:13:57 2001
> +++ edited/include/asm-cris/div64.h Fri Jan 25 21:22:19 2002
> @@ -3,12 +3,11 @@
>
> /* copy from asm-arm */
>
> -/* We're not 64-bit, but... */
> #define do_div(n,base) \
> ({ \
> int __res; \
> - __res = ((unsigned long)n) % (unsigned int)base; \
> - n = ((unsigned long)n) / (unsigned int)base; \
> + __res = ((unsigned long long)n) % (unsigned int)base; \
> + n = ((unsigned long long)n) / (unsigned int)base; \
> __res; \
> })
>
> ===== include/asm-m68k/div64.h 1.1 vs edited =====
> --- 1.1/include/asm-m68k/div64.h Sat Dec 8 02:13:35 2001
> +++ edited/include/asm-m68k/div64.h Fri Jan 25 21:23:59 2002
> @@ -26,8 +26,8 @@
> #else
> #define do_div(n,base) ({ \
> int __res; \
> - __res = ((unsigned long) n) % (unsigned) base; \
> - n = ((unsigned long) n) / (unsigned) base; \
> + __res = ((unsigned long long) n) % (unsigned) base; \
> + n = ((unsigned long long) n) / (unsigned) base; \
> __res; \
> })
> #endif
> ===== include/asm-ppc/div64.h 1.1 vs edited =====
> --- 1.1/include/asm-ppc/div64.h Sat Dec 8 02:13:37 2001
> +++ edited/include/asm-ppc/div64.h Fri Jan 25 21:28:49 2002
> @@ -4,10 +4,9 @@
> #ifndef __PPC_DIV64
> #define __PPC_DIV64
>
> -#define do_div(n,base) ({ \
> -int __res; \
> -__res = ((unsigned long) n) % (unsigned) base; \
> -n = ((unsigned long) n) / (unsigned) base; \
> -__res; })
> -
> +#define do_div(n,base) ({ \
> + int __res; \
> + __res = ((unsigned long long) n) % (unsigned) base; \
> + n = ((unsigned long long) n) / (unsigned) base; \
> + __res; })
> #endif
> ===== include/asm-sh/div64.h 1.1 vs edited =====
> --- 1.1/include/asm-sh/div64.h Sat Dec 8 02:13:46 2001
> +++ edited/include/asm-sh/div64.h Fri Jan 25 21:29:31 2002
> @@ -1,10 +1,9 @@
> #ifndef __ASM_SH_DIV64
> #define __ASM_SH_DIV64
>
> -#define do_div(n,base) ({ \
> -int __res; \
> -__res = ((unsigned long) n) % (unsigned) base; \
> -n = ((unsigned long) n) / (unsigned) base; \
> -__res; })
> -
> +#define do_div(n,base) ({ \
> + int __res; \
> + __res = ((unsigned long long) n) % (unsigned) base; \
> + n = ((unsigned long long) n) / (unsigned) base; \
> + __res; })
> #endif /* __ASM_SH_DIV64 */
> ===== include/asm-sparc/div64.h 1.1 vs edited =====
> --- 1.1/include/asm-sparc/div64.h Sat Dec 8 02:13:36 2001
> +++ edited/include/asm-sparc/div64.h Fri Jan 25 21:25:39 2002
> @@ -1,11 +1,10 @@
> #ifndef __SPARC_DIV64
> #define __SPARC_DIV64
>
> -/* We're not 64-bit, but... */
> #define do_div(n,base) ({ \
> int __res; \
> - __res = ((unsigned long) n) % (unsigned) base; \
> - n = ((unsigned long) n) / (unsigned) base; \
> + __res = ((unsigned long long) n) % (unsigned) base; \
> + n = ((unsigned long long) n) / (unsigned) base; \
> __res; })
>
> #endif /* __SPARC_DIV64 */
> -
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
>

--
Troy Benjegerdes | master of mispeeling | 'da hozer' | [email protected]
-----"If this message isn't misspelled, I didn't write it" -- Me -----
"Why do musicians compose symphonies and poets write poems? They do it
because life wouldn't have any meaning for them if they didn't. That's
why I draw cartoons. It's my life." -- Charles Schulz

2002-01-27 18:52:21

by Matti Aarnio

[permalink] [raw]
Subject: Re: [PATCH] 64-bit divide tweaks

On Fri, Jan 25, 2002 at 09:34:43PM +0200, Momchil Velikov wrote:
> Hi there,
> printk, etc. are broken wrt printing 64-bit numbers (%ll, %L).
> This patch fixes do_div, which did (on some archs) 32-bit divide.

Wrong.

Correct one is to supply each arch with their native way to handle
the division. Remember, the base (divisor) is SMALLISH (2 to 16).

Where you are unable to do it, the C code that is still present in
include/asm-parisc/div64.h alternate code branch will do it.

This code is needed because the Linux kernel DOES NOT WANT TO
use gcc builtin functions normally available via libgcc.
This is primarily to detect when 32-bit machine does arbitrary
(and expensive) divisions on 64-bit values. E.g. stupid code
slipped into fast-paths.

> Regards,
> -velco

/Matti Aarnio (who originally created this %Ld printing code,
and which others have mutated since then..)


> ===== drivers/net/sk98lin/skproc.c 1.1 vs edited =====
> --- 1.1/drivers/net/sk98lin/skproc.c Sat Dec 8 02:14:15 2001
> +++ edited/drivers/net/sk98lin/skproc.c Fri Jan 25 21:20:06 2002
> @@ -339,17 +339,6 @@
> return (Rest);
> }
>
> -
> -#if 0
> -#define do_div(n,base) ({ \
> -long long __res; \
> -__res = ((unsigned long long) n) % (unsigned) base; \
> -n = ((unsigned long long) n) / (unsigned) base; \
> -__res; })
> -
> -#endif
> -
> -
> /*****************************************************************************
> *
> * SkNumber - Print results
> ===== include/asm-arm/div64.h 1.1 vs edited =====
> --- 1.1/include/asm-arm/div64.h Sat Dec 8 02:13:45 2001
> +++ edited/include/asm-arm/div64.h Fri Jan 25 21:21:56 2002
> @@ -1,12 +1,11 @@
> #ifndef __ASM_ARM_DIV64
> #define __ASM_ARM_DIV64
>
> -/* We're not 64-bit, but... */
> #define do_div(n,base) \
> ({ \
> int __res; \
> - __res = ((unsigned long)n) % (unsigned int)base; \
> - n = ((unsigned long)n) / (unsigned int)base; \
> + __res = ((unsigned long long)n) % (unsigned int)base; \
> + n = ((unsigned long long)n) / (unsigned int)base; \
> __res; \
> })
>
> ===== include/asm-cris/div64.h 1.1 vs edited =====
> --- 1.1/include/asm-cris/div64.h Sat Dec 8 02:13:57 2001
> +++ edited/include/asm-cris/div64.h Fri Jan 25 21:22:19 2002
> @@ -3,12 +3,11 @@
>
> /* copy from asm-arm */
>
> -/* We're not 64-bit, but... */
> #define do_div(n,base) \
> ({ \
> int __res; \
> - __res = ((unsigned long)n) % (unsigned int)base; \
> - n = ((unsigned long)n) / (unsigned int)base; \
> + __res = ((unsigned long long)n) % (unsigned int)base; \
> + n = ((unsigned long long)n) / (unsigned int)base; \
> __res; \
> })
>
> ===== include/asm-m68k/div64.h 1.1 vs edited =====
> --- 1.1/include/asm-m68k/div64.h Sat Dec 8 02:13:35 2001
> +++ edited/include/asm-m68k/div64.h Fri Jan 25 21:23:59 2002
> @@ -26,8 +26,8 @@
> #else
> #define do_div(n,base) ({ \
> int __res; \
> - __res = ((unsigned long) n) % (unsigned) base; \
> - n = ((unsigned long) n) / (unsigned) base; \
> + __res = ((unsigned long long) n) % (unsigned) base; \
> + n = ((unsigned long long) n) / (unsigned) base; \
> __res; \
> })
> #endif
> ===== include/asm-ppc/div64.h 1.1 vs edited =====
> --- 1.1/include/asm-ppc/div64.h Sat Dec 8 02:13:37 2001
> +++ edited/include/asm-ppc/div64.h Fri Jan 25 21:28:49 2002
> @@ -4,10 +4,9 @@
> #ifndef __PPC_DIV64
> #define __PPC_DIV64
>
> -#define do_div(n,base) ({ \
> -int __res; \
> -__res = ((unsigned long) n) % (unsigned) base; \
> -n = ((unsigned long) n) / (unsigned) base; \
> -__res; })
> -
> +#define do_div(n,base) ({ \
> + int __res; \
> + __res = ((unsigned long long) n) % (unsigned) base; \
> + n = ((unsigned long long) n) / (unsigned) base; \
> + __res; })
> #endif
> ===== include/asm-sh/div64.h 1.1 vs edited =====
> --- 1.1/include/asm-sh/div64.h Sat Dec 8 02:13:46 2001
> +++ edited/include/asm-sh/div64.h Fri Jan 25 21:29:31 2002
> @@ -1,10 +1,9 @@
> #ifndef __ASM_SH_DIV64
> #define __ASM_SH_DIV64
>
> -#define do_div(n,base) ({ \
> -int __res; \
> -__res = ((unsigned long) n) % (unsigned) base; \
> -n = ((unsigned long) n) / (unsigned) base; \
> -__res; })
> -
> +#define do_div(n,base) ({ \
> + int __res; \
> + __res = ((unsigned long long) n) % (unsigned) base; \
> + n = ((unsigned long long) n) / (unsigned) base; \
> + __res; })
> #endif /* __ASM_SH_DIV64 */
> ===== include/asm-sparc/div64.h 1.1 vs edited =====
> --- 1.1/include/asm-sparc/div64.h Sat Dec 8 02:13:36 2001
> +++ edited/include/asm-sparc/div64.h Fri Jan 25 21:25:39 2002
> @@ -1,11 +1,10 @@
> #ifndef __SPARC_DIV64
> #define __SPARC_DIV64
>
> -/* We're not 64-bit, but... */
> #define do_div(n,base) ({ \
> int __res; \
> - __res = ((unsigned long) n) % (unsigned) base; \
> - n = ((unsigned long) n) / (unsigned) base; \
> + __res = ((unsigned long long) n) % (unsigned) base; \
> + n = ((unsigned long long) n) / (unsigned) base; \
> __res; })
>
> #endif /* __SPARC_DIV64 */
> -
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/

2002-01-29 00:00:37

by Troy Benjegerdes

[permalink] [raw]
Subject: 64-bit divide cleanup (tested on ppc)

Attached is a patch to get rid of asm/div64.h on arches that don't have
optimized asm routines.

I didn't include removeing the various arch/div64.h file yet, since I want
some comments on this.



Attachments:
(No filename) (199.00 B)
div64-patch (9.90 kB)
Download all attachments

2002-02-07 16:12:14

by Gabriel Paubert

[permalink] [raw]
Subject: Re: 64-bit divide cleanup (tested on ppc)

Hi Troy,

sorry for the delay, I was sick :-(

Troy Benjegerdes wrote:

> Attached is a patch to get rid of asm/div64.h on arches that don't have
> optimized asm routines.
>
> I didn't include removeing the various arch/div64.h file yet, since I want
> some comments on this.
>
[snipped]
> ===================================================================
> RCS file: /cvsdev/hhl-2.4.17/linux/fs/ntfs/util.c,v
> retrieving revision 1.1
> diff -u -r1.1 util.c
> --- fs/ntfs/util.c 2001/11/30 22:28:59 1.1
> +++ fs/ntfs/util.c 2002/01/29 00:40:14
> @@ -13,7 +13,8 @@
> #include "util.h"
> #include <linux/string.h>
> #include <linux/errno.h>
> -#include <asm/div64.h> /* For do_div(). */
> +#define USE_SLOW_64BIT_DIVIDES
> +#include <linux/div64.h> /* For do_div(). */
> #include "support.h"
>
> /*
> @@ -233,7 +234,7 @@
> {
> /* Subtract the NTFS time offset, then convert to 1s intervals. */
> ntfs_time64_t t = ntutc - NTFS_TIME_OFFSET;
> - do_div(t, 10000000);
> + do_div(&t, 10000000);
> return (ntfs_time_t)t;
> }

>
> Index: fs/smbfs/proc.c
> ===================================================================
> RCS file: /cvsdev/hhl-2.4.17/linux/fs/smbfs/proc.c,v
> retrieving revision 1.1
> diff -u -r1.1 proc.c
> --- fs/smbfs/proc.c 2001/11/30 22:28:58 1.1
> +++ fs/smbfs/proc.c 2002/01/29 00:40:17
> @@ -18,12 +18,14 @@
> #include <linux/dirent.h>
> #include <linux/nls.h>
>
> +#define USE_SLOW_64BIT_DIVIDES
> +#include <linux/div64.h>
> +
> #include <linux/smb_fs.h>
> #include <linux/smbno.h>
> #include <linux/smb_mount.h>
>
> #include <asm/string.h>
> -#include <asm/div64.h>
>
> #include "smb_debug.h"
> #include "proto.h"
> @@ -375,7 +377,7 @@
> /* FIXME: what about the timezone difference? */
> /* Subtract the NTFS time offset, then convert to 1s intervals. */
> u64 t = ntutc - NTFS_TIME_OFFSET;
> - do_div(t, 10000000);
> + do_div(&t, 10000000);
> return (time_t)t;
> }


At least for these 2, your patch is wrong. 10000000 is not especially
small and the algorithm you propose does not work for these. It is
limited to about 65536 actually.


>
> Index: lib/vsprintf.c
> ===================================================================
> RCS file: /cvsdev/hhl-2.4.17/linux/lib/vsprintf.c,v
> retrieving revision 1.1
> diff -u -r1.1 vsprintf.c
> --- lib/vsprintf.c 2001/11/30 22:28:59 1.1
> +++ lib/vsprintf.c 2002/01/29 00:40:24
> @@ -19,9 +19,9 @@
> #include <linux/string.h>
> #include <linux/ctype.h>
> #include <linux/kernel.h>
> +/* #define USE_SLOW_64BIT_DIVIDE */
> +#include <linux/div64.h>
>
> -#include <asm/div64.h>
> -
> /**
> * simple_strtoul - convert a string to an unsigned long
> * @cp: The start of the string
> @@ -165,7 +165,7 @@
> if (num == 0)
> tmp[i++]='0';
> else while (num != 0)
> - tmp[i++] = digits[do_div(num,base)];
> + tmp[i++] = digits[do_div(&num,base)];



Forcing to use slow do_div version even when base is 8 or 16 is not
nice. Heck I believe that seperating it into several cases and having a
different 2 or 3 distinct loops (one for base 10, the other or 2 others
for shifts by 3 or 4) could actually result in smaller code. On PPC and
Alpha at lesat the compiler knows how to do a divide by 10 with a
multiply high or however it's called instruction.

Oh, and what abour removing the if and doing a do {...} while(num!=0)
instead ?


> if (i > precision)
> precision = i;
> size -= precision;
> @@ -426,22 +426,31 @@
> }
> continue;
> }
> - if (qualifier == 'L')
> +
> + switch (qualifier) {
> + case 'L':
> num = va_arg(args, long long);
> - else if (qualifier == 'l') {
> - num = va_arg(args, unsigned long);
> + break;
> + case 'l':
> if (flags & SIGN)
> - num = (signed long) num;
> - } else if (qualifier == 'Z') {
> + num = (signed long long) va_arg(args, long);
> + else
> + num = va_arg(args, unsigned long);
> + break;
> + case 'Z':
> num = va_arg(args, size_t);
> - } else if (qualifier == 'h') {
> - num = (unsigned short) va_arg(args, int);
> + break;
> + case 'h':
> if (flags & SIGN)
> - num = (signed short) num;
> - } else {
> - num = va_arg(args, unsigned int);
> + num = (signed long long) va_arg(args, int);
> + else
> + num = va_arg(args, unsigned int);
> + break;
> + default:
> if (flags & SIGN)
> - num = (signed int) num;
> + num = (signed long long) va_arg(args, int);
> + else
> + num = va_arg(args, unsigned int);
> }
> str = number(str, end, num, base,
> field_width, precision, flags);
> Index: include/linux/div64.h
> ===================================================================
> RCS file: /cvsdev/hhl-2.4.17/linux/include/linux/div64.h
> diff -N div64.h
> --- /dev/null Tue May 5 13:32:27 1998
> +++ include/linux/div64.h Mon Jan 28 16:59:28 2002
> @@ -0,0 +1,85 @@
> +/*
> + * include/linux/div64.h
> + *
> + * Primarily used by vsprintf to divide a 64 bit int N by a small integer base

^^^^^
Read the comments, here goes you 10000000 factor. The modulo once
shifted left by 16 bits can easily overflow.... Perhaps you should patch
it s/small/_small_/ to better see it.



> + * We really do NOT want to encourage people to do slow 64 bit divides in
> + * the kernel, so the 'default' version of this function panics if you
> + * try and divide a 64 bit number by anything other than 8 or 16.
> + *
> + * If you really *really* need this, and are prepared to be flamed by
> + * lkml, #define USE_SLOW_64BIT_DIVIDES before including this file.
> + */
> +#ifndef __DIV64
> +#define __DIV64
> +
> +#include <linux/config.h>
> +
> +/* configurable */
> +#undef __USE_ASM
> +
> +
> +#ifdef __USE_ASM
> +/* yeah, this is a mess, and leaves out m68k.... */
> +# if defined(CONFIG_X86) || define(CONFIG_ARCH_S390) || defined(CONFIG_MIPS)
> +# define __USE_ASM__
> +# endif
> +#endif
> +
> +#ifdef __USE_ASM__
> +#include <asm/div64.h>
> +#else /* __USE_ASM__ */
> +static inline int do_div(unsigned long long * n, unsigned long base)
> +{
> + int res = 0;
> + unsigned long long t = *n;
> + if ( t == (unsigned long)t ){ /* this should handle 64 bit platforms */
> + res = ((unsigned long) t) % base;
> + t = ((unsigned long) t) / base;
> + } else {
> +#ifndef USE_SLOW_64BIT_DIVIDES
> + switch (base) {
> + case 8:
> + res = ((unsigned long) t & 0x7);
> + t = t >> 3;
> + break;
> + case 16:
> + res = ((unsigned long) t & 0xf);
> + t = t >> 4;
> + break;
> + default:
> + panic("do_div called with 64 bit arg and unsupported base\n", base);
> + }
> +#else /* USE_SLOW_64BIT_DIVIDES */
> + /* this was stolen from the old asm-parisc/div64.h */
> + /*
> + * Copyright (C) 1999 Hewlett-Packard Co
> + * Copyright (C) 1999 David Mosberger-Tang <[email protected]>
> + *
> + * vsprintf uses this to divide a 64-bit integer N by a small


s/small/_small_/ just to be sure that the comment is understood.

For the 10000000 case, I believe a simple stupid looping algorithm is
the only solution which does not result in code size explosion.

Regards,
Gabriel.