On Fri, Nov 10, 2023 at 09:19:14AM +0000, Richard Biener wrote:
> > Only not promoting the argument will make it directly usable in the
> > stdc_leading_zeros, stdc_leading_ones, stdc_trailing_zeros, 
> > stdc_trailing_ones,
> > stdc_first_leading_zero, ..., stdc_count_zeros, stdc_count_ones, ...
> > C23 stdbit.h type-generic macros, otherwise one would need to play with
> > _Generic and special-case there unsigned char and unsigned short (which
> > normally promote to int), but e.g. unsigned _BitInt(8) doesn't.
> 
> googling doesn't find me stdc_leading_zeros - are those supposed to work
> for non-_BitInt types as well and don't promote the argument in that
> case?

https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3096.pdf
is the C23 draft the C23 wiki points at.

E.g.

#include <stdbit.h>
unsigned int stdc_leading_zeros_uc(unsigned char value);
unsigned int stdc_leading_zeros_us(unsigned short value);
unsigned int stdc_leading_zeros_ui(unsigned int value);
unsigned int stdc_leading_zeros_ul(unsigned long value);
unsigned int stdc_leading_zeros_ull(unsigned long long value);
generic_return_type stdc_leading_zeros(generic_value_type value);

Returns
Returns the number of consecutive 0 bits in value, starting from
the most significant bit.
The type-generic function (marked by its generic_value_type argument)
returns the appropriate value based on the type of the input value,
so long as it is a:
— standard unsigned integer type, excluding bool;
— extended unsigned integer type;
— or, bit-precise unsigned integer type whose width matches a standard
  or extended integer type, excluding bool.
The generic_return_type type shall be a suitable large unsigned integer
type capable of representing the computed result.

My understanding is that because unsigned char and unsigned short
are standard unsigned integer types, it ought to support those too,
not diagnose them as invalid, and shall return number of consecutive 0 bits
in them (which is something different between value for unsigned char
and int unless unsigned char has the same precision as int).

> If we are spcificially targeting those I wonder why we don't name
> the builtins after those?  But yes, if promotion is undesirable
> for implementing them then I agree.  IIRC _BitInt(n) is not subject
> to integer promotions.

Because the builtins are just something matching in behavior to existing
builtins which can be used for those macros, not exact implementation of
those.  E.g. while
#define stdc_leading_zeros(value) \
((unsigned int) __builtin_clzg (value, __builtin_popcountg ((__typeof (value)) 
~(__typeof (value)) 0)))
implements (I believe) stdc_leading_zeros above, the second argument to the
builtin could be something different needed for other cases, e.g. -1 if one
wants to implement ffs-like behavior on unsigned argument, and e.g.
stdc_leading_ones would be implemented probably like:
#define stdc_leading_ones(value) \
((unsigned int) __builtin_clzg ((__typeof (value)) ~(value), 
__builtin_popcountg ((__typeof (value)) ~(__typeof (value)) 0)))
Or
#define stdc_first_trailing_one(value) \
((unsigned int) (__builtin_ctzg (value, -1) + 1))
vs.
#define stdc_trailing_zeros(value) \
((unsigned int) __builtin_ctzg (value, __builtin_popcountg ((__typeof (value)) 
~(__typeof (value)) 0)))
No need to add 14 new type-generic builtins, we can just add the building
blocks to implement those.

        Jakub

Reply via email to