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

Reply via email to