This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Re: __builtin_clzll and uintmax_t
On Sun, Mar 06, 2011 at 09:56:52AM +0100, Marc Glisse wrote:
> >uintmax_t is the largest of the standard unsigned C types, so it cannot be larger than unsigned long long.
>
> That's a gcc property then. The C99 standard only guarantees that
> uintmax_t is at least as large as unsigned long long, but it is
> allowed to be some other larger type:
Yeah, it could be larger than unsigned long long.
On no target GCC supports currently it is larger than long long though currently.
Just
grep INTMAX_TYPE gcc/{,config/,config/*/}*.h
to see it.
> >On x86_64, for example:
> >
> >>#include <stdio.h>
> >>#include <stdint.h>
> >>
> >>int main (void)
> >>{
> >> printf ("%lu ", sizeof (uintmax_t));
> >> printf ("%lu ", sizeof (int));
> >> printf ("%lu ", sizeof (long int));
> >> printf ("%lu ", sizeof (long long int));
> >> printf ("%lu\n", sizeof (__int128));
> >>}
> >
> >gives : 8 4 8 8 16
>
> I am not sure how legal that is. __int128 is an extended signed
> integer type, and thus the statement about intmax_t should apply to
> it as well. So gcc is just pretending that __int128 is not really
> there.
It is also an ABI issue, you can't change what uintmax_t was
once you use some particular type in an ABI.
What you could do is use __builtin_clzll if sizeof (uintmax_t) == sizeof (unsigned long long),
for sizeof (uintmax_t) == 2 * sizeof (unsigned long long) perhaps use
int
clzmax (uintmax_t x)
{
const union
{
uintmax_t ll;
#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__
struct { unsigned long long high, low; } s;
#else
struct { unsigned long long low, high; } s;
#endif
} uu = { .ll = x };
uintmax_t word;
unsigned long long add;
if (uu.s.high)
word = uu.s.high, add = 0;
else
word = uu.s.low, add = sizeof (unsigned long long) * __CHAR_BIT__;
return __builtin_clzll (word) + add;
}
and give up for other cases.
Jakub