Bug 49595 - on amd64, sizeof(__int128_t) > sizeof(intmax_t)
Summary: on amd64, sizeof(__int128_t) > sizeof(intmax_t)
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: c (show other bugs)
Version: 4.6.1
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2011-06-30 17:19 UTC by brian m. carlson
Modified: 2011-07-01 07:11 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments
Trivial testcase (553 bytes, application/octet-stream)
2011-06-30 17:19 UTC, brian m. carlson
Details
Unpreprocessed testcase (135 bytes, text/x-csrc)
2011-06-30 17:26 UTC, brian m. carlson
Details

Note You need to log in before you can comment on or make changes to this bug.
Description brian m. carlson 2011-06-30 17:19:51 UTC
Created attachment 24647 [details]
Trivial testcase

The C standard (as well as POSIX) requires that intmax_t "designates a signed integer type capable of representing any value of any signed integer type" and likewise for uintmax_t. However, on amd64, intmax_t is long, which is not big enough to hold a 128-bit quantity.

A trivial preprocessed testcase is attached, not that you need one. I see this behavior on 4.6 and 4.7:

lakeview ok % gcc -v 
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/x86_64-linux-gnu/gcc/x86_64-linux-gnu/4.6.1/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 4.6.1-1' --with-bugurl=file:///usr/share/doc/gcc-4.6/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++,go --prefix=/usr --program-suffix=-4.6 --enable-shared --enable-multiarch --with-multiarch-defaults=x86_64-linux-gnu --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib/x86_64-linux-gnu --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.6 --libdir=/usr/lib/x86_64-linux-gnu --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-plugin --enable-objc-gc --with-arch-32=i586 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.6.1 (Debian 4.6.1-1) 

lakeview ok % /usr/lib/gcc-snapshot/bin/gcc -v 
Using built-in specs.
COLLECT_GCC=/usr/lib/gcc-snapshot/bin/gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc-snapshot/libexec/gcc/x86_64-linux-gnu/4.7.0/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 20110624-1' --with-bugurl=file:///usr/share/doc/gcc-snapshot/README.Bugs --enable-languages=c,ada,c++,java,fortran,objc,obj-c++,go --prefix=/usr/lib/gcc-snapshot --enable-shared --enable-multiarch --with-multiarch-defaults=x86_64-linux-gnu --enable-linker-build-id --with-system-zlib --disable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-plugin --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.7-snap/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.7-snap --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.7-snap --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --with-arch-32=i586 --with-tune=generic --disable-werror --enable-checking=yes --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.7.0 20110624 (experimental) [trunk revision 175388] (Debian 20110624-1) 

This is Debian bug #629137.
Comment 1 brian m. carlson 2011-06-30 17:26:35 UTC
Created attachment 24648 [details]
Unpreprocessed testcase

The preprocessed testcase hardcodes long int and so doesn't test the presence of the bug correctly. In this case, only an unpreprocessed testcase will demonstrate the problem.
Comment 2 Jonathan Wakely 2011-06-30 17:42:59 UTC
sizeof(intmax_t) is fixed by various LP64 ABIs and cannot be changed

I believe the stock answer is that __int128 is not a C99 extended integer type, so isn't one of the types that intmax_t can represent the value of
Comment 3 brian m. carlson 2011-06-30 18:12:39 UTC
(In reply to comment #2)
> sizeof(intmax_t) is fixed by various LP64 ABIs and cannot be changed

That does sound potentially problematic.  I don't see how that solves the
standard conformance issue, though.  If intmax_t cannot be changed, then I
suppose the only appropriate behavior is not to provide any integer types larger
than intmax_t with -std=c99.

> I believe the stock answer is that __int128 is not a C99 extended integer type,
> so isn't one of the types that intmax_t can represent the value of

There are five *standard signed integer types*.... There may also be
*implementation-defined extended signed integer types*. The standard and
extended signed integer types are collectively called *signed integer types*.

Since the standard specifies intmax_t in terms of a "signed integer type", it
therefore includes any implementation-defined extended signed integer types,
including __int128_t.
Comment 4 Jonathan Wakely 2011-06-30 18:29:02 UTC
(In reply to comment #3)
> Since the standard specifies intmax_t in terms of a "signed integer type", it
> therefore includes any implementation-defined extended signed integer types,

Yes.

> including __int128_t.

You're assuming __int128 is an implementation-defined extended integer type.
If GCC chooses to call __int128 some other type that doesn't fall under the C99 definition of "implementation defined integer type" then intmax_t doesn't have to be able to represent its values.

Of course this is cheating by playing wordgames, but sizeof(intmax_t) can't change and people want to be able to use __int128
Comment 5 Jonathan Wakely 2011-06-30 18:33:27 UTC
(In reply to comment #3)
> suppose the only appropriate behavior is not to provide any integer types
> larger
> than intmax_t with -std=c99.

Use -pedantic-errors if you want to reject programs using __int128
Comment 6 Andreas Schwab 2011-06-30 19:33:55 UTC
By (directly) using an identifier starting with two underscores you are leaving the territory of the C standard.
Comment 7 brian m. carlson 2011-06-30 20:16:50 UTC
(In reply to comment #5)
> (In reply to comment #3)
> > suppose the only appropriate behavior is not to provide any integer types
> > larger
> > than intmax_t with -std=c99.
> 
> Use -pedantic-errors if you want to reject programs using __int128

I don't.  I want to compile using C99 mode (I use scoped for) on a variety of different compilers, taking advantage of 128-bit integers whenever possible (for performance reasons).  The portable way to do this with the preprocessor is to see if UINTMAX_MAX is set to the proper value.  In fact, GCC as it is currently provides no way to determine whether 128-bit integers are in fact supported at all on the current hardware, which leads to compilation failures on, say, 32-bit SPARC.

The conformance issue, while important, is secondary.  I do expect GCC to comply with the standard in standards mode, and I do expect any deviation from the standards behavior in standards mode to be considered a bug worth fixing.  But it isn't the primary goal here.

I also see no mention of intmax_t in the SysV ABI for x86-64. Can you be more specific about what specifically would cause ABI breakage if intmax_t were to become 128-bit on x86_64-pc-linux-gnu?  According to <http://gcc.gnu.org/ml/gcc/2011-03/msg00095.html>, as long as libc behaves appropriately, it shouldn't be a problem.
Comment 8 brian m. carlson 2011-06-30 20:22:37 UTC
(In reply to comment #6)
> By (directly) using an identifier starting with two underscores you are leaving
> the territory of the C standard.

I don't agree.  The footnote to the text that I quoted states: "Implementation-defined keywords shall have the form of an identifier reserved for any use as
described in 7.1.3."  So the standard specifies that such implementation-defined signed integer types (which it has just instructed implementors must be implemented using double underscores) are part of the signed integer types. I don't see another legitimate interpretation here.

As I said previously, I want to use 128-bit integers where possible. If intmax_t were correctly and appropriately defined as to use 128-bit integers, then the behavior would not only be standards-conforming with regard to C99, but it would also be practically useful and I wouldn't have to use double-underscored types at all.
Comment 9 Jonathan Wakely 2011-06-30 21:23:55 UTC
(In reply to comment #7)
> The conformance issue, while important, is secondary.  I do expect GCC to
> comply with the standard in standards mode, and I do expect any deviation from
> the standards behavior in standards mode to be considered a bug worth fixing. 

What do you mean by standards mode?
It's clearly documented in the manual that -std=c99 does NOT mean non-standard extensions are rejected, for that you need to use -pedantic-errors, and that rejects __int128.
Comment 10 brian m. carlson 2011-06-30 21:47:15 UTC
(In reply to comment #9)
> What do you mean by standards mode?
> It's clearly documented in the manual that -std=c99 does NOT mean non-standard
> extensions are rejected, for that you need to use -pedantic-errors, and that
> rejects __int128.

My complaint is not even about __int128.  My complaint is about intmax_t.  With -std=c99, intmax_t is not capable of representing all the values of all implementation-defined signed integer types.  The C standard requires that it is so capable.  If the implementation provides a type (however named (or unnamed) or specified) that is an implementation-defined signed integer type, intmax_t must be capable of expressing all the values that such a type may hold.

I don't care how the type is specified or named.  It exists.  It happens to be named in the standard-specified manner; that is convenient, but ultimately irrelevant. It exists, therefore, intmax_t's behavior is specified in terms of that type. Period.

Your only out here is if you claim that the type in question (however named, unnamed, or specified) is not an implementation-defined signed integer type, and in that case, you'll need to specify that in the documentation and specify what it *is*.  You should probably document that it is a) not implementation-defined, b) not signed (or unsigned, as appropriate), c) not integral, or d) not a type.
Comment 11 jsm-csl@polyomino.org.uk 2011-06-30 22:27:57 UTC
On Thu, 30 Jun 2011, sandals at crustytoothpaste dot net wrote:

> Your only out here is if you claim that the type in question (however named,
> unnamed, or specified) is not an implementation-defined signed integer type,
> and in that case, you'll need to specify that in the documentation and specify
> what it *is*.  You should probably document that it is a) not
> implementation-defined, b) not signed (or unsigned, as appropriate), c) not
> integral, or d) not a type.

The implementation-defined extended integer types are documented alongside 
the other implementation-defined behavior in implement-c.texi: "GCC does 
not support any extended integer types.".

Note that "char" is a standard integer type that is not a signed or 
unsigned integer type although it behaves like one or the other; you could 
think of it as a "sui generis integer type".  And the right way to think 
of __int128 is as a "sui generis extended type", that is not an integer 
type although it shares some properties with them.  Maybe the __fpreg type 
supported on IA64 is more obviously a "sui generis extended type" given 
the restrictions on how it can be used - but the same category contains 
both those types (and ARM __fp16, for another example).
Comment 12 Richard Biener 2011-07-01 07:11:00 UTC
Invalid then.