(root)/
coreutils-9.4/
lib/
count-leading-zeros.h
       1  /* count-leading-zeros.h -- counts the number of leading 0 bits in a word.
       2     Copyright (C) 2012-2023 Free Software Foundation, Inc.
       3  
       4     This file is free software: you can redistribute it and/or modify
       5     it under the terms of the GNU Lesser General Public License as
       6     published by the Free Software Foundation; either version 2.1 of the
       7     License, or (at your option) any later version.
       8  
       9     This file is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12     GNU Lesser General Public License for more details.
      13  
      14     You should have received a copy of the GNU Lesser General Public License
      15     along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
      16  
      17  /* Written by Eric Blake.  */
      18  
      19  #ifndef COUNT_LEADING_ZEROS_H
      20  #define COUNT_LEADING_ZEROS_H 1
      21  
      22  /* This file uses _GL_INLINE_HEADER_BEGIN, _GL_INLINE.  */
      23  #if !_GL_CONFIG_H_INCLUDED
      24   #error "Please include config.h first."
      25  #endif
      26  
      27  #include <limits.h>
      28  #include <stdlib.h>
      29  
      30  _GL_INLINE_HEADER_BEGIN
      31  #ifndef COUNT_LEADING_ZEROS_INLINE
      32  # define COUNT_LEADING_ZEROS_INLINE _GL_INLINE
      33  #endif
      34  
      35  #ifdef __cplusplus
      36  extern "C" {
      37  #endif
      38  
      39  /* Assuming the GCC builtin is BUILTIN and the MSC builtin is MSC_BUILTIN,
      40     expand to code that computes the number of leading zeros of the local
      41     variable 'x' of type TYPE (an unsigned integer type) and return it
      42     from the current function.  */
      43  #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) \
      44      || (__clang_major__ >= 4)
      45  # define COUNT_LEADING_ZEROS(BUILTIN, MSC_BUILTIN, TYPE)                \
      46    return x ? BUILTIN (x) : CHAR_BIT * sizeof x;
      47  #elif _MSC_VER
      48  # pragma intrinsic (_BitScanReverse)
      49  # if defined _M_X64
      50  #  pragma intrinsic (_BitScanReverse64)
      51  # endif
      52  # define COUNT_LEADING_ZEROS(BUILTIN, MSC_BUILTIN, TYPE)                \
      53      do                                                                  \
      54        {                                                                 \
      55          unsigned long result;                                           \
      56          if (MSC_BUILTIN (&result, x))                                   \
      57            return CHAR_BIT * sizeof x - 1 - result;                      \
      58          return CHAR_BIT * sizeof x;                                     \
      59        }                                                                 \
      60      while (0)
      61  #else
      62  # define COUNT_LEADING_ZEROS(BUILTIN, MSC_BUILTIN, TYPE)                \
      63      do                                                                  \
      64        {                                                                 \
      65          int count;                                                      \
      66          unsigned int leading_32;                                        \
      67          if (! x)                                                        \
      68            return CHAR_BIT * sizeof x;                                   \
      69          for (count = 0;                                                 \
      70               (leading_32 = ((x >> (sizeof (TYPE) * CHAR_BIT - 32))      \
      71                              & 0xffffffffU),                             \
      72                count < CHAR_BIT * sizeof x - 32 && !leading_32);         \
      73               count += 32)                                               \
      74            x = x << 31 << 1;                                             \
      75          return count + count_leading_zeros_32 (leading_32);             \
      76        }                                                                 \
      77      while (0)
      78  
      79  /* Compute and return the number of leading zeros in X,
      80     where 0 < X < 2**32.  */
      81  COUNT_LEADING_ZEROS_INLINE int
      82  count_leading_zeros_32 (unsigned int x)
      83  {
      84    /* <https://github.com/gibsjose/BitHacks>
      85       <https://www.fit.vutbr.cz/~ibarina/pub/bithacks.pdf> */
      86    static const char de_Bruijn_lookup[32] = {
      87      31, 22, 30, 21, 18, 10, 29, 2, 20, 17, 15, 13, 9, 6, 28, 1,
      88      23, 19, 11, 3, 16, 14, 7, 24, 12, 4, 8, 25, 5, 26, 27, 0
      89    };
      90  
      91    x |= x >> 1;
      92    x |= x >> 2;
      93    x |= x >> 4;
      94    x |= x >> 8;
      95    x |= x >> 16;
      96    return de_Bruijn_lookup[((x * 0x07c4acddU) & 0xffffffffU) >> 27];
      97  }
      98  #endif
      99  
     100  /* Compute and return the number of leading zeros in X. */
     101  COUNT_LEADING_ZEROS_INLINE int
     102  count_leading_zeros (unsigned int x)
     103  {
     104    COUNT_LEADING_ZEROS (__builtin_clz, _BitScanReverse, unsigned int);
     105  }
     106  
     107  /* Compute and return the number of leading zeros in X. */
     108  COUNT_LEADING_ZEROS_INLINE int
     109  count_leading_zeros_l (unsigned long int x)
     110  {
     111    COUNT_LEADING_ZEROS (__builtin_clzl, _BitScanReverse, unsigned long int);
     112  }
     113  
     114  /* Compute and return the number of leading zeros in X. */
     115  COUNT_LEADING_ZEROS_INLINE int
     116  count_leading_zeros_ll (unsigned long long int x)
     117  {
     118  #if (defined _MSC_VER && !defined __clang__) && !defined _M_X64
     119    /* 32-bit MSVC does not have _BitScanReverse64, only _BitScanReverse.  */
     120    unsigned long result;
     121    if (_BitScanReverse (&result, (unsigned long) (x >> 32)))
     122      return CHAR_BIT * sizeof x - 1 - 32 - result;
     123    if (_BitScanReverse (&result, (unsigned long) x))
     124      return CHAR_BIT * sizeof x - 1 - result;
     125    return CHAR_BIT * sizeof x;
     126  #else
     127    COUNT_LEADING_ZEROS (__builtin_clzll, _BitScanReverse64,
     128                         unsigned long long int);
     129  #endif
     130  }
     131  
     132  #ifdef __cplusplus
     133  }
     134  #endif
     135  
     136  _GL_INLINE_HEADER_END
     137  
     138  #endif /* COUNT_LEADING_ZEROS_H */