LCOV - code coverage report
Current view: top level - util/bits - fd_bits_tg.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 8 0.0 %
Date: 2025-09-18 04:41:32 Functions: 0 0 -

          Line data    Source code
       1             : /* Included by fd_bits.h */
       2             : /* DO NOT INCLUDE DIRECTLY */
       3             : 
       4             : /* fd_bits_tg.h provides type generic versions of the most of the
       5             :    functionality in fd_bits in that they infer the type from the
       6             :    argument).  E.g. Unless otherwise explicitly noted, fd_foo( expr )
       7             :    will behave functionally and linguistically identical to fd_int_foo(
       8             :    expr ) if expr returns an int, fd_ulong_foo( expr ) if x returns a
       9             :    ulong and so forth.  These macros are robust and should compile to to
      10             :    comparably fast O(1) assembly as the type explicit equivalents. */
      11             : 
      12             : /* fd_tg_* are implement various bit and arithmetic operators that patch
      13             :    over various linguistic faults.  These are meant for internal use to
      14             :    implement the actual bits tg functionality below.
      15             : 
      16             :    These are necessary because, as ranted about elsewhere, C and C++
      17             :    don't _meaningfully_ have char, short, uchar and ushort types.
      18             :    Operations on these are dubiously silently promoted to int.  There is
      19             :    _almost_ a reasonable historical argument for this behavior for char
      20             :    and short.  And this argument would be valid for uchar and ushort if
      21             :    those were promoted to uint.  But, in a fit of complete utter
      22             :    linguistic insanity, uchar and ushort are promoted to a _signed_ int.
      23             : 
      24             :    This is a subtle underappreciated and all too common source of
      25             :    security bugs, data corruption and portability issues.  As an
      26             :    example, this can cause great surprise and many a lost weekend
      27             :    debugging when things like ~(ulong)0 produce the ulong value
      28             :    ULONG_MAX and ~(uint)0 produce the uint value UINT_MAX but ~(uchar)0
      29             :    produces the 32-bit signed integer value -1.
      30             : 
      31             :    This (plus the lexical irregularities introduced by dubiously
      32             :    treating char's sign as implementation defined), makes writing robust
      33             :    code much harder than it should be and makes writing robust fast
      34             :    portable type generic code even more obtuse.  Sigh ... */
      35             : 
      36             : #define fd_tg_neg(x)              ((__typeof__((x)))-(x)       ) /* -x    with type of x guaranteed */
      37             : #define fd_tg_add(x,y)            ((__typeof__((x)))((x) + (y))) /* x + y " */
      38             : #define fd_tg_sub(x,y)            ((__typeof__((x)))((x) - (y))) /* x - y " */
      39             : #define fd_tg_not(x)              ((__typeof__((x)))~(x)       ) /* ~x    "  */
      40             : #define fd_tg_and(x,y)            ((__typeof__((x)))((x) & (y))) /* x & y " */
      41             : #define fd_tg_or(x,y)             ((__typeof__((x)))((x) | (y))) /* x | y " */
      42             : #define fd_tg_xor(x,y)            ((__typeof__((x)))((x) ^ (y))) /* x ^ y " */
      43             : 
      44             : #define fd_tg_msb_idx(T)          (8UL*sizeof(T)-1UL)            /* Returns the index of the most significant bit for type T */
      45             : #define fd_tg_is_unsigned_type(T) (((T)-(T)1)>(T)0)              /* Returns 1 if T is an unsigned type, 0 otherwise */
      46             : 
      47             : /* fd_tg_select will emit the expression e8, e16, e32, e64, or e128
      48             :    as appropriate for the width the integral type Tin (Tin can be a
      49             :    signed or unsigned type).  The output will have the type Tout.  This
      50             :    expression is selected at compile time (hopefully).  This is to brute
      51             :    force cases where the low level language faults are just too great to
      52             :    workaround with the above.
      53             : 
      54             :    Two implementations are provided.  One implementation uses the
      55             :    (widely supported) compiler extension __builtin_choose_expr.  If we
      56             :    don't want to use a compiler extension (e.g. portability concerns /
      57             :    auditing tool chain support concerns / etc), there is a second
      58             :    implementation based on the ternary operator.
      59             : 
      60             :    In both implementations, the compiler will parse all the expressions
      61             :    before it selects the matching expression.  Thus all the expressions
      62             :    have to be valid expressions for all x but only the matching
      63             :    expression has to be functionally correct for a particular x.  (This
      64             :    is an inherent limitation for the ternary implementation.
      65             :    Unfortunately, this limitation also exists for the builtin
      66             :    implementation for current compilers.)
      67             : 
      68             :    That is, while this makes it possible to write truly type generic
      69             :    implementations for a much broader range of cases, we still need to
      70             :    jump through hoops.  One hoop is that we only emit the 128-bit wide
      71             :    expression on targets with FD_HAS_INT128.
      72             : 
      73             :    Another hoop is due to the subtle difference between the builtin and
      74             :    the ternary operator: the builtin gives stronger guarantees that the
      75             :    selection will be done at compile time and it doesn't do type
      76             :    promotions of the individual expressions.  So we cast the expressions
      77             :    to Tout to keep both implementations of fd_tg_select functionally
      78             :    identical. */
      79             : 
      80             : #ifndef FD_BITS_TG_USE_BUILTIN
      81             : #ifdef __cplusplus
      82             : #define FD_BITS_TG_USE_BUILTIN 0
      83             : #else
      84             : #define FD_BITS_TG_USE_BUILTIN 1
      85             : #endif
      86             : #endif
      87             : 
      88             : #if FD_BITS_TG_USE_BUILTIN
      89             : #if FD_HAS_INT128
      90             : #define fd_tg_select(Tin,Tout,e8,e16,e32,e64,e128) __builtin_choose_expr( sizeof(Tin)==1UL, (Tout)(e8),  \
      91             :                                                    __builtin_choose_expr( sizeof(Tin)==2UL, (Tout)(e16), \
      92             :                                                    __builtin_choose_expr( sizeof(Tin)==4UL, (Tout)(e32), \
      93             :                                                    __builtin_choose_expr( sizeof(Tin)==8UL, (Tout)(e64), \
      94             :                                                                                             (Tout)(e128) ) ) ) )
      95             : #else
      96             : #define fd_tg_select(Tin,Tout,e8,e16,e32,e64,e128) __builtin_choose_expr( sizeof(Tin)==1UL, (Tout)(e8),  \
      97             :                                                    __builtin_choose_expr( sizeof(Tin)==2UL, (Tout)(e16), \
      98             :                                                    __builtin_choose_expr( sizeof(Tin)==4UL, (Tout)(e32), \
      99             :                                                                                             (Tout)(e64)  ) ) )
     100             : #endif
     101             : #else
     102             : #if FD_HAS_INT128
     103             : #define fd_tg_select(Tin,Tout,e8,e16,e32,e64,e128) ( ((sizeof(Tin)==1UL) ? (Tout)(e8)   : \
     104             :                                                      ((sizeof(Tin)==2UL) ? (Tout)(e16)  : \
     105             :                                                      ((sizeof(Tin)==4UL) ? (Tout)(e32)  : \
     106             :                                                      ((sizeof(Tin)==8UL) ? (Tout)(e64)  : \
     107             :                                                                            (Tout)(e128) ) ) ) ) )
     108             : #else
     109             : #define fd_tg_select(Tin,Tout,e8,e16,e32,e64,e128) ( ((sizeof(Tin)==1UL) ? (Tout)(e8)   : \
     110             :                                                      ((sizeof(Tin)==2UL) ? (Tout)(e16)  : \
     111             :                                                      ((sizeof(Tin)==4UL) ? (Tout)(e32)  : \
     112             :                                                                            (Tout)(e64)  ) ) ) )
     113             : #endif
     114             : #endif
     115             : 
     116             : /* Actual type generic bits implementations. */
     117             : 
     118             : #define fd_is_pow2( x ) (__extension__({                                                      \
     119             :     __typeof__((x)) _fd_bits_x = (x);                                                         \
     120             :     ((!!_fd_bits_x) & !fd_tg_and( _fd_bits_x, fd_tg_sub( _fd_bits_x, (__typeof__((x)))1 ) )); \
     121             :   }))
     122             : 
     123             : #define fd_pow2(        T, b       ) fd_shift_left( (T)1, (b) )
     124             : 
     125             : #define fd_mask_bit(    T, b       ) fd_shift_left( (T)1, (b) )
     126             : #define fd_clear_bit(   x, b       ) fd_tg_and( (x), fd_tg_not( fd_mask_bit( __typeof__((x)), (b) ) ) )
     127             : #define fd_set_bit(     x, b       ) fd_tg_or ( (x),            fd_mask_bit( __typeof__((x)), (b) )   )
     128             : #define fd_flip_bit(    x, b       ) fd_tg_xor( (x),            fd_mask_bit( __typeof__((x)), (b) )   )
     129             : #define fd_extract_bit( x, b       ) (((int)fd_shift_right( (x), (b) )) & 1)
     130             : #define fd_insert_bit(  x, b, y    ) (__extension__({                                                 \
     131             :     int _fd_bits_b = (b);                                                                             \
     132             :     fd_tg_or( fd_clear_bit( (x), _fd_bits_b ), fd_shift_left( (__typeof__((x)))!!(y), _fd_bits_b ) ); \
     133             :   }))
     134             : 
     135             : #define fd_mask_lsb(    T, n       ) fd_tg_sub( fd_shift_left( (T)1, (n) ), (T)1 )
     136             : #define fd_clear_lsb(   x, n       ) fd_tg_and( (x), fd_tg_not( fd_mask_lsb( __typeof__((x)), (n) ) ) )
     137             : #define fd_set_lsb(     x, n       ) fd_tg_or ( (x),            fd_mask_lsb( __typeof__((x)), (n) )   )
     138             : #define fd_flip_lsb(    x, n       ) fd_tg_xor( (x),            fd_mask_lsb( __typeof__((x)), (n) )   )
     139             : #define fd_extract_lsb( x, n       ) fd_tg_and( (x),            fd_mask_lsb( __typeof__((x)), (n) )   )
     140             : #define fd_insert_lsb(  x, n, y    ) fd_tg_or ( fd_clear_lsb( (x), (n) ), (y) )
     141             : 
     142             : #define fd_mask(        T, l, h    ) fd_tg_sub( fd_shift_left( (T)1, (h)+1 ), fd_shift_left( (T)1, (l) ) )
     143             : #define fd_clear(       x, l, h    ) fd_tg_and( (x), fd_tg_not( fd_mask( __typeof__((x)), (l), (h) ) ) )
     144             : #define fd_set(         x, l, h    ) fd_tg_or(  (x),            fd_mask( __typeof__((x)), (l), (h) )   )
     145             : #define fd_flip(        x, l, h    ) fd_tg_xor( (x),            fd_mask( __typeof__((x)), (l), (h) )   )
     146             : #define fd_extract(     x, l, h    ) (__extension__({                                                 \
     147             :     int _fd_bits_l = (l);                                                                             \
     148             :     fd_tg_and( fd_shift_right( (x), _fd_bits_l ), fd_mask_lsb( __typeof__((x)), (h)-_fd_bits_l+1 ) ); \
     149             :   }))
     150             : #define fd_insert(      x, l, h, y ) (__extension__({                               \
     151             :     int _fd_bits_l = (l);                                                           \
     152             :     fd_tg_or( fd_clear( (x), _fd_bits_l, (h) ), fd_shift_left( (y), _fd_bits_l ) ); \
     153             :   }))
     154             : 
     155             : #define fd_lsb( x ) (__extension__({                                                               \
     156             :     __typeof__((x)) _fd_bits_x = (x);                                                              \
     157             :     fd_tg_xor( _fd_bits_x, fd_tg_and( _fd_bits_x, fd_tg_sub( _fd_bits_x, (__typeof__((x)))1 ) ) ); \
     158             :   }))
     159             : 
     160             : #define fd_pop_lsb( x ) (__extension__({                                  \
     161             :     __typeof__((x)) _fd_bits_x = (x);                                     \
     162             :     fd_tg_and( _fd_bits_x, fd_tg_sub( _fd_bits_x, (__typeof__((x)))1 ) ); \
     163             :   }))
     164             : 
     165             : #define fd_mask_align(  T, a       ) fd_tg_sub( (T)(a), (T)1 )
     166             : #define fd_is_aligned(  x, a       ) (!fd_tg_and( (x),            fd_mask_align( __typeof__((x)), (a) )   ))
     167             : #define fd_alignment(   x, a       )   fd_tg_and( (x),            fd_mask_align( __typeof__((x)), (a) )   )
     168             : #define fd_align_dn(    x, a       )   fd_tg_and( (x), fd_tg_not( fd_mask_align( __typeof__((x)), (a) ) ) )
     169             : #define fd_align_up(    x, a       ) (__extension__({                   \
     170             :     __typeof__((x)) _fd_bits_m = fd_mask_align( __typeof__((x)), (a) ); \
     171             :     fd_tg_and( fd_tg_add( (x), _fd_bits_m ), fd_tg_not( _fd_bits_m ) ); \
     172             :   }))
     173             : 
     174             : #define fd_blend( m, x, y ) (__extension__({                                             \
     175             :     __typeof__((x)) _fd_bits_m = (m);                                                    \
     176             :     fd_tg_or( fd_tg_and( _fd_bits_m, (x) ), fd_tg_and( fd_tg_not( _fd_bits_m ), (y) ) ); \
     177             :   }))
     178             : 
     179             : #define fd_if(c,x,y) (__extension__({                                                                      \
     180             :     __typeof__((x)) _fd_bits_x = (x), _fd_bits_y = (y); /* Note: critical to eval first and then select */ \
     181             :     (c) ? _fd_bits_x : _fd_bits_y; /* cmov */                                                              \
     182             :   }))
     183             : 
     184             : #define fd_store_if(c,p,x) do {                     \
     185             :     __typeof__((x)) _fd_bits_dummy[1];              \
     186             :     *((c) ? (p) : _fd_bits_dummy) /* cmov */ = (x); \
     187             :   } while(0)
     188             : 
     189             : /* Note: fd_int_abs has a return type of uint.  This allows the edge
     190             :    case fd_int_abs(INT_MIN) to produce value of |INT_MIN| (which is not
     191             :    representable in an int but is in a uint).  Similarly for the other
     192             :    signed integer types.
     193             : 
     194             :    For the type general implementation below, the return type is the
     195             :    same as the input type.  As a result, the edge case has
     196             :    fd_abs(INT_MIN) == INT_MIN.  But, if we cast the result to a uint, we
     197             :    have the desired (uint)fd_abs(INT_MIN) == |INT_MIN|.
     198             : 
     199             :    Unfortunately, compilers don't support constructs like "unsigned
     200             :    __typeof__((x))" to get this to output the unsigned version of the
     201             :    input type in a straightforward way.  It would be possible to have
     202             :    fd_abs produce the correct unsigned variant of the input type by
     203             :    using __builtin_choose_expr.  Unfortunately, this will not work with
     204             :    the ternary type promotion rules.  Until we are willing to require
     205             :    toolchain support for __builtin_choose_expr, we stick with fd_abs
     206             :    returning the same type as the input. */
     207             : 
     208             : #define fd_abs( x ) (__extension__({                                                                        \
     209             :     __typeof__((x)) _fd_bits_x = (x), _fd_bits_nx = fd_tg_neg( _fd_bits_x );                                \
     210             :     (fd_tg_is_unsigned_type(__typeof__((x))) | (_fd_bits_x>((__typeof__(x))0))) ? _fd_bits_x : _fd_bits_nx; \
     211             :   }))
     212             : 
     213           0 : #define fd_min(x,y)  (__extension__({                              \
     214           0 :     __typeof__((x)) _fd_bits_x = (x), _fd_bits_y = (y);            \
     215           0 :     _fd_bits_x <= _fd_bits_y ? _fd_bits_x : _fd_bits_y; /* cmov */ \
     216           0 :   }))
     217             : 
     218           0 : #define fd_max(x,y)  (__extension__({                              \
     219           0 :     __typeof__((x)) _fd_bits_x = (x), _fd_bits_y = (y);            \
     220           0 :     _fd_bits_x >= _fd_bits_y ? _fd_bits_x : _fd_bits_y; /* cmov */ \
     221           0 :   }))
     222             : 
     223             : /* Note: this implementation assumes zero padding left shift behavior on
     224             :    target. */
     225             : 
     226             : #define fd_shift_left(x,n) (__extension__({                                                                       \
     227             :     int _fd_bits_m = (int)fd_tg_msb_idx( __typeof__((x)) );                           /* compile time */          \
     228             :     int _fd_bits_n = (n);                                                             /* compile time (mostly) */ \
     229             :     int _fd_bits_c = _fd_bits_n>_fd_bits_m;                                           /* compile time (mostly) */ \
     230             :     (__typeof__((x)))(((x) << (_fd_bits_c ? _fd_bits_m : _fd_bits_n)) << _fd_bits_c); /* compile time (mostly) */ \
     231             :   }))
     232             : 
     233             : /* Note: assumes zero padding unsigned / sign extending signed right
     234             :    shift behavior on target. */
     235             : 
     236             : #define fd_shift_right(x,n) (__extension__({                                                                      \
     237             :     int _fd_bits_m = (int)fd_tg_msb_idx( __typeof__((x)) );                           /* compile time */          \
     238             :     int _fd_bits_n = (n);                                                             /* compile time (mostly) */ \
     239             :     int _fd_bits_c = _fd_bits_n>_fd_bits_m;                                           /* compile time (mostly) */ \
     240             :     (__typeof__((x)))(((x) >> (_fd_bits_c ? _fd_bits_m : _fd_bits_n)) >> _fd_bits_c); /* compile time (mostly) */ \
     241             :   }))
     242             : 
     243             : /* Note: rotates use fd_tg_select because the implementation requires
     244             :    a zero padding signed right shift when operating on a signed type.
     245             :    If we are willing to restrict rotates to unsigned types only, these
     246             :    can be implemented type generic without fd_tg_select. */
     247             : 
     248             : #define fd_rotate_left(x,n) (__extension__({                                                              \
     249             :     __typeof__((x)) _fd_bits_x = (x);                                                                     \
     250             :     int             _fd_bits_n = (n);                                                                     \
     251             :     fd_tg_select( __typeof__((x)), __typeof__((x)),                                                       \
     252             :       (((uchar  )_fd_bits_x) << (_fd_bits_n &   7)) | (((uchar  )_fd_bits_x) >> ((-_fd_bits_n) &   7)),   \
     253             :       (((ushort )_fd_bits_x) << (_fd_bits_n &  15)) | (((ushort )_fd_bits_x) >> ((-_fd_bits_n) &  15)),   \
     254             :       (((uint   )_fd_bits_x) << (_fd_bits_n &  31)) | (((uint   )_fd_bits_x) >> ((-_fd_bits_n) &  31)),   \
     255             :       (((ulong  )_fd_bits_x) << (_fd_bits_n &  63)) | (((ulong  )_fd_bits_x) >> ((-_fd_bits_n) &  63)),   \
     256             :       (((uint128)_fd_bits_x) << (_fd_bits_n & 127)) | (((uint128)_fd_bits_x) >> ((-_fd_bits_n) & 127)) ); \
     257             :   }))
     258             : 
     259             : #define fd_rotate_right(x,n) (__extension__({                                                             \
     260             :     __typeof__((x)) _fd_bits_x = (x);                                                                     \
     261             :     int             _fd_bits_n = (n);                                                                     \
     262             :     fd_tg_select( __typeof__((x)), __typeof__((x)),                                                       \
     263             :       (((uchar  )_fd_bits_x) >> (_fd_bits_n &   7)) | (((uchar  )_fd_bits_x) << ((-_fd_bits_n) &   7)),   \
     264             :       (((ushort )_fd_bits_x) >> (_fd_bits_n &  15)) | (((ushort )_fd_bits_x) << ((-_fd_bits_n) &  15)),   \
     265             :       (((uint   )_fd_bits_x) >> (_fd_bits_n &  31)) | (((uint   )_fd_bits_x) << ((-_fd_bits_n) &  31)),   \
     266             :       (((ulong  )_fd_bits_x) >> (_fd_bits_n &  63)) | (((ulong  )_fd_bits_x) << ((-_fd_bits_n) &  63)),   \
     267             :       (((uint128)_fd_bits_x) >> (_fd_bits_n & 127)) | (((uint128)_fd_bits_x) << ((-_fd_bits_n) & 127)) ); \
     268             :   }))
     269             : 
     270             : /* Note: we use 4UL*sizeof(T) to avoid spurious compiler warnings of
     271             :    shifts wider than type when popcnt is used on narrower types. */
     272             : 
     273             : #define fd_popcnt( x ) (__extension__({                \
     274             :     __typeof__((x)) _fd_bits_x = (x);                  \
     275             :     fd_tg_select( __typeof__((x)), int,                \
     276             :       __builtin_popcount ( (uint)(uchar) _fd_bits_x ), \
     277             :       __builtin_popcount ( (uint)(ushort)_fd_bits_x ), \
     278             :       __builtin_popcount ( (uint)        _fd_bits_x ), \
     279             :       __builtin_popcountl( (ulong)       _fd_bits_x ), \
     280             :       __builtin_popcountl( (ulong)_fd_bits_x ) + __builtin_popcountl( (ulong)(_fd_bits_x >> (4UL*sizeof(__typeof__((x)))) ) ) ); \
     281             :   }))
     282             : 
     283             : #define fd_find_lsb( x ) (__extension__({              \
     284             :     __typeof__((x)) _fd_bits_x = (x);                  \
     285             :     fd_tg_select( __typeof__((x)), int,                \
     286             :       fd_uchar_find_lsb  ( (uchar)  _fd_bits_x ),      \
     287             :       fd_ushort_find_lsb ( (ushort) _fd_bits_x ),      \
     288             :       fd_uint_find_lsb   ( (uint)   _fd_bits_x ),      \
     289             :       fd_ulong_find_lsb  ( (ulong)  _fd_bits_x ),      \
     290             :       fd_uint128_find_lsb( (uint128)_fd_bits_x ) );    \
     291             :   }))
     292             : 
     293             : #define fd_find_lsb_w_default( x, d ) (__extension__({                    \
     294             :     __typeof__((x)) _fd_bits_x = (x);                                     \
     295             :     int             _fd_bits_d = (d);                                     \
     296             :     fd_tg_select( __typeof__((x)), int,                                   \
     297             :       fd_uchar_find_lsb_w_default  ( (uchar)  _fd_bits_x, _fd_bits_d ),   \
     298             :       fd_ushort_find_lsb_w_default ( (ushort) _fd_bits_x, _fd_bits_d ),   \
     299             :       fd_uint_find_lsb_w_default   ( (uint)   _fd_bits_x, _fd_bits_d ),   \
     300             :       fd_ulong_find_lsb_w_default  ( (ulong)  _fd_bits_x, _fd_bits_d ),   \
     301             :       fd_uint128_find_lsb_w_default( (uint128)_fd_bits_x, _fd_bits_d ) ); \
     302             :   }))
     303             : 
     304             : #define fd_find_msb( x ) (__extension__({              \
     305             :     __typeof__((x)) _fd_bits_x = (x);                  \
     306             :     fd_tg_select( __typeof__((x)), int,                \
     307             :       fd_uchar_find_msb  ( (uchar)  _fd_bits_x ),      \
     308             :       fd_ushort_find_msb ( (ushort) _fd_bits_x ),      \
     309             :       fd_uint_find_msb   ( (uint)   _fd_bits_x ),      \
     310             :       fd_ulong_find_msb  ( (ulong)  _fd_bits_x ),      \
     311             :       fd_uint128_find_msb( (uint128)_fd_bits_x ) );    \
     312             :   }))
     313             : 
     314             : #define fd_find_msb_w_default( x, d ) (__extension__({                    \
     315             :     __typeof__((x)) _fd_bits_x = (x);                                     \
     316             :     int             _fd_bits_d = (d);                                     \
     317             :     fd_tg_select( __typeof__((x)), int,                                   \
     318             :       fd_uchar_find_msb_w_default  ( (uchar)  _fd_bits_x, _fd_bits_d ),   \
     319             :       fd_ushort_find_msb_w_default ( (ushort) _fd_bits_x, _fd_bits_d ),   \
     320             :       fd_uint_find_msb_w_default   ( (uint)   _fd_bits_x, _fd_bits_d ),   \
     321             :       fd_ulong_find_msb_w_default  ( (ulong)  _fd_bits_x, _fd_bits_d ),   \
     322             :       fd_uint128_find_msb_w_default( (uint128)_fd_bits_x, _fd_bits_d ) ); \
     323             :   }))
     324             : 
     325             : /* Note: defaults picked to match shift trick based implementation in
     326             :    edge cases.  FIXME: Consider using shift trick implementation anyway
     327             :    so that these are "const" functions (e.g. not inline asm that can't
     328             :    be compile time evaluated with compiler time inputs). */
     329             : 
     330             : #define fd_pow2_dn( x ) fd_shift_left( (__typeof__((x)))1, fd_find_msb_w_default( (x), 0 ) )
     331             : 
     332             : #define fd_pow2_up( x ) fd_shift_left( (__typeof__((x)))1, fd_find_msb_w_default( fd_tg_sub( (x), (__typeof__((x)))1 ), -1 ) + 1 )
     333             : 
     334             : /* Note: we use 4UL*sizeof(T) to avoid spurious compiler warnings of
     335             :    shifts wider than type when bswap is used on narrower types. */
     336             : 
     337             : #define fd_bswap( x ) (__extension__({              \
     338             :     __typeof__((x)) _fd_bits_x = (x);               \
     339             :     fd_tg_select( __typeof__((x)), __typeof__((x)), \
     340             :       /**/                       _fd_bits_x,        \
     341             :       __builtin_bswap16( (ushort)_fd_bits_x ),      \
     342             :       __builtin_bswap32( (uint  )_fd_bits_x ),      \
     343             :       __builtin_bswap64( (ulong )_fd_bits_x ),      \
     344             :       (((uint128)__builtin_bswap64( (ulong)_fd_bits_x )) << 64) | \
     345             :       ((uint128)__builtin_bswap64( (ulong)(_fd_bits_x >> (4UL*sizeof(__typeof__((x))))) )) ); \
     346             :   }))
     347             : 
     348             : /* Note: Type generic versions of fd_zz_enc/fd_zz_dec have similar
     349             :    signed/unsigned input -> unsigned/signed output issues as fd_abs
     350             :    above.  Unlike fd_abs though, the distinction is more fundamental
     351             :    than an edge case.  So either we'd force a casting (which defeats the
     352             :    point of making a type generic implementation) or we require
     353             :    toolchain support for __builtin_choose_expr.  Omitting for now. */

Generated by: LCOV version 1.14