LWN.net Logo

64-bit division on 32-bit arch - where's the compiler error?

64-bit division on 32-bit arch - where's the compiler error?

Posted Aug 29, 2011 13:44 UTC (Mon) by blitzkrieg3 (subscriber, #57873)
In reply to: 64-bit division on 32-bit arch - where's the compiler error? by giraffedata
Parent article: Quotes of the week

It's not a call to the library, it's statically linked with the "real time function" __udivdi3. I'm not sure what real time functions are, but it sounds like they're sort of like inline functions for normal C operations.

Here's the error they were trying to fix:

> "ERROR: "__udivdi3" [fs/btrfs/btrfs.ko] undefined!

From what I can tell, the compiler can't translate: min_free /= 2; to a single operation on 32 bit, so it's replaced with the __udivdi3 call. In userspace, since it's a division by two, you get two bit shifts. In other cases, it would be two divl operations. The kernel can do a double divide by using do_div.

By not including __udiv in the 32-bit libraries, Linus is essentially forcing the programmer to:

A) realize that integer division is costly
B) Manually decide whether to bitshift, or do two divisions with do_div.

http://gcc.gnu.org/onlinedocs/gccint/Integer-library-rout...


(Log in to post comments)

64-bit division on 32-bit arch - where's the compiler error?

Posted Aug 30, 2011 2:34 UTC (Tue) by giraffedata (subscriber, #1954) [Link]

It's not a call to the library, it's statically linked with the "real time function" __udivdi3.

It's a statically linked call to the library. I think you mean "run time function" -- that's what the GCC manual page you point to calls it." It means a function in the GCC runtime library, i.e. libgcc.

__udivdi3() is for use when compiling for a CPU that doesn't have a divide instruction (that used to be pretty common -- divide is a pretty complex instruction; I don't know if it is common now. x86 has always had divide). But if the compiler is smart enough to recognize a divide by two and know you can do that by shifting, I would expect it not to use __udivdi3() on any CPU.

But the error message makes it clear that the compiler in this case generated a call to __udivdi3() when it created btrfs.ko. I assume, then, that this is not x86 because as we've seen, the compiler generates shift instructions instead on x86 (and even if it didn't, it would just generate a divide instruction). I also have to believe the divide-by-shifting cleverness is in a platform-dependent part of GCC and is absent for whatever platform this is.

One other thing to note: we've been saying this is problem with 64 bit numbers on a 32 bit CPU. But __udivdi3() is the divide function for "unsigned long" operands, i.e. on a 32 bit machine it is a 32 bit divide. The compiler would use __udivti3() instead if it wanted to divide 64 bit numbers.

64-bit division on 32-bit arch - where's the compiler error?

Posted Aug 30, 2011 3:34 UTC (Tue) by nybble41 (subscriber, #55106) [Link]

> ... we've been saying this is problem with 64 bit numbers on a 32 bit CPU. But __udivdi3() is the divide function for "unsigned long" operands, i.e. on a 32 bit machine it is a 32 bit divide. The compiler would use __udivti3() instead if it wanted to divide 64 bit numbers.

That's not quite correct. The preface to the runtime library section[1] of the GCC Internals manual states that the C types are "for illustrative purposes", and that "these routines take arguments and return values of a specific machine mode, not a specific C type." The Machine Modes section[2] defines SImode, DImode, and TImode as a four-byte integer, an eight-byte integer, and a 16-byte integer, respectively. In other words, in the hypothetical architecture invented to illustrate these library routines, the "int" in __udivsi3() is 32-bit, the "long" in __udivdi3() is 64-bit, and the "long long" in __udivti3() is 128-bit.

A simple test program confirms that 64-bit division generates a call to __udivdi3() in 32-bit mode. Similarly, division of unsigned __int128 values in 64-bit mode generates a call to __udivti3().

[1] http://gcc.gnu.org/onlinedocs/gccint/Libgcc.html
[2] http://gcc.gnu.org/onlinedocs/gccint/Machine-Modes.html

Copyright © 2013, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds