From 88b0bb4db9aaecff8b01e81726b911fa5d02b2fb Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sun, 12 May 2024 14:22:58 -0700 Subject: [PATCH] Prefer stdbit.h to count-one-bits.h etc C23's in the long run should be better supported than Gnulib's count-one-bits.h and similar headers, so switch to the C23 primitives, with a Gnulib fallback for platforms lacking C23. * admin/merge-gnulib (GNULIB_MODULES): Remove count-leading-zeros, count-one-bits, count-trailing-zeros. Add stdc_bit_width, stdc_count_ones, stdc_trailing_zeros. * lib/count-leading-zeros.c, lib/count-leading-zeros.h: * lib/count-one-bits.c, lib/count-one-bits.h: * lib/count-trailing-zeros.c, lib/count-trailing-zeros.h: Remove. * lib/stdbit.c, lib/stdbit.in.h, lib/stdc_bit_width.c: * lib/stdc_count_ones.c, lib/stdc_leading_zeros.c: * lib/stdc_trailing_zeros.c, m4/stdbit_h.m4: New files, copied from Gnulib. * lib/gnulib.mk.in, m4/gnulib-comp.m4: Regenerate. * src/data.c: Do not include count-one-bits.h, count-trailing-zeros.h. Instead, rely on lisp.h including stdbit.h. (Flogcount, Fbool_vector_count_population) (Fbool_vector_count_consecutive): Use stdbit.h macros instead of count-one-bits.h and count-trailing-zeros.h macros. (shift_right_ull, count_one_bits_word, pre_value) (count_trailing_zero_bits): Remove; no longer needed. * src/lisp.h: Include stdbit.h instead of count-leading-zeros.h. (elogb): Use stdbit.h macro instead of count-leading-zeros.h macro. --- INSTALL.REPO | 2 +- admin/merge-gnulib | 5 +- lib/count-leading-zeros.h | 140 --- lib/count-one-bits.h | 169 --- lib/count-trailing-zeros.h | 130 -- lib/gnulib.mk.in | 133 +- lib/stdbit.c | 23 + lib/stdbit.in.h | 1077 +++++++++++++++++ ...ount-trailing-zeros.c => stdc_bit_width.c} | 9 +- lib/{count-one-bits.c => stdc_count_ones.c} | 11 +- ...t-leading-zeros.c => stdc_leading_zeros.c} | 9 +- lib/stdc_trailing_zeros.c | 20 + m4/gnulib-comp.m4 | 46 +- m4/stdbit_h.m4 | 37 + src/data.c | 95 +- src/lisp.h | 7 +- 16 files changed, 1320 insertions(+), 593 deletions(-) delete mode 100644 lib/count-leading-zeros.h delete mode 100644 lib/count-one-bits.h delete mode 100644 lib/count-trailing-zeros.h create mode 100644 lib/stdbit.c create mode 100644 lib/stdbit.in.h rename lib/{count-trailing-zeros.c => stdc_bit_width.c} (78%) rename lib/{count-one-bits.c => stdc_count_ones.c} (78%) rename lib/{count-leading-zeros.c => stdc_leading_zeros.c} (77%) create mode 100644 lib/stdc_trailing_zeros.c create mode 100644 m4/stdbit_h.m4 diff --git a/INSTALL.REPO b/INSTALL.REPO index 77d8153a5a8..46ac4440aee 100644 --- a/INSTALL.REPO +++ b/INSTALL.REPO @@ -80,7 +80,7 @@ handle. The most thorough cleaning can be achieved by 'git clean -fdx' which will leave you with only files from the git repository. Here are some faster methods for a couple of particular error cases: - /usr/bin/m4:aclocal.m4:9: cannot open `m4/count-leading-zeros.m4': No such file or directory + /usr/bin/m4:aclocal.m4:9: cannot open `m4/stdbit_h.m4': No such file or directory This can be fixed with 'rm aclocal.m4'. diff --git a/admin/merge-gnulib b/admin/merge-gnulib index c4daaded015..65e098c7123 100755 --- a/admin/merge-gnulib +++ b/admin/merge-gnulib @@ -29,7 +29,6 @@ GNULIB_MODULES=' alignasof alloca-opt binary-io boot-time byteswap c-ctype c-strcase canonicalize-lgpl careadlinkat close-stream copy-file-range - count-leading-zeros count-one-bits count-trailing-zeros crypto/md5 crypto/md5-buffer crypto/sha1-buffer crypto/sha256-buffer crypto/sha512-buffer d-type diffseq double-slash-root dtoastr dtotimespec dup2 @@ -44,7 +43,9 @@ GNULIB_MODULES=' nanosleep nproc nstrftime pathmax pipe2 pselect pthread_sigmask qcopy-acl readlink readlinkat regex - sig2str sigdescr_np socklen stat-time std-gnu11 stdbool stdckdint stddef stdio + sig2str sigdescr_np socklen stat-time std-gnu11 stdbool + stdc_bit_width stdc_count_ones stdc_trailing_zeros + stdckdint stddef stdio stpcpy strnlen strnlen strtoimax symlink sys_stat sys_time tempname time-h time_r time_rz timegm timer-time timespec-add timespec-sub update-copyright unlocked-io utimensat diff --git a/lib/count-leading-zeros.h b/lib/count-leading-zeros.h deleted file mode 100644 index a4b68c21064..00000000000 --- a/lib/count-leading-zeros.h +++ /dev/null @@ -1,140 +0,0 @@ -/* count-leading-zeros.h -- counts the number of leading 0 bits in a word. - Copyright (C) 2012-2024 Free Software Foundation, Inc. - - This file is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - This file is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program. If not, see . */ - -/* Written by Eric Blake. */ - -#ifndef COUNT_LEADING_ZEROS_H -#define COUNT_LEADING_ZEROS_H 1 - -/* This file uses _GL_INLINE_HEADER_BEGIN, _GL_INLINE. */ -#if !_GL_CONFIG_H_INCLUDED - #error "Please include config.h first." -#endif - -#include -#include - -_GL_INLINE_HEADER_BEGIN -#ifndef COUNT_LEADING_ZEROS_INLINE -# define COUNT_LEADING_ZEROS_INLINE _GL_INLINE -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* Assuming the GCC builtin is BUILTIN and the MSC builtin is MSC_BUILTIN, - expand to code that computes the number of leading zeros of the local - variable 'x' of type TYPE (an unsigned integer type) and return it - from the current function. */ -#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) \ - || (__clang_major__ >= 4) -# define COUNT_LEADING_ZEROS(BUILTIN, MSC_BUILTIN, TYPE) \ - return x ? BUILTIN (x) : CHAR_BIT * sizeof x; -#elif _MSC_VER -extern unsigned char _BitScanReverse (unsigned long *, unsigned long); -# pragma intrinsic (_BitScanReverse) -# if defined _M_X64 -extern unsigned char _BitScanReverse64 (unsigned long *, unsigned long long); -# pragma intrinsic (_BitScanReverse64) -# endif -# define COUNT_LEADING_ZEROS(BUILTIN, MSC_BUILTIN, TYPE) \ - do \ - { \ - unsigned long result; \ - if (MSC_BUILTIN (&result, x)) \ - return CHAR_BIT * sizeof x - 1 - result; \ - return CHAR_BIT * sizeof x; \ - } \ - while (0) -#else -# define COUNT_LEADING_ZEROS(BUILTIN, MSC_BUILTIN, TYPE) \ - do \ - { \ - int count; \ - unsigned int leading_32; \ - if (! x) \ - return CHAR_BIT * sizeof x; \ - for (count = 0; \ - (leading_32 = ((x >> (sizeof (TYPE) * CHAR_BIT - 32)) \ - & 0xffffffffU), \ - count < CHAR_BIT * sizeof x - 32 && !leading_32); \ - count += 32) \ - x = x << 31 << 1; \ - return count + count_leading_zeros_32 (leading_32); \ - } \ - while (0) - -/* Compute and return the number of leading zeros in X, - where 0 < X < 2**32. */ -COUNT_LEADING_ZEROS_INLINE int -count_leading_zeros_32 (unsigned int x) -{ - /* - */ - static const char de_Bruijn_lookup[32] = { - 31, 22, 30, 21, 18, 10, 29, 2, 20, 17, 15, 13, 9, 6, 28, 1, - 23, 19, 11, 3, 16, 14, 7, 24, 12, 4, 8, 25, 5, 26, 27, 0 - }; - - x |= x >> 1; - x |= x >> 2; - x |= x >> 4; - x |= x >> 8; - x |= x >> 16; - return de_Bruijn_lookup[((x * 0x07c4acddU) & 0xffffffffU) >> 27]; -} -#endif - -/* Compute and return the number of leading zeros in X. */ -COUNT_LEADING_ZEROS_INLINE int -count_leading_zeros (unsigned int x) -{ - COUNT_LEADING_ZEROS (__builtin_clz, _BitScanReverse, unsigned int); -} - -/* Compute and return the number of leading zeros in X. */ -COUNT_LEADING_ZEROS_INLINE int -count_leading_zeros_l (unsigned long int x) -{ - COUNT_LEADING_ZEROS (__builtin_clzl, _BitScanReverse, unsigned long int); -} - -/* Compute and return the number of leading zeros in X. */ -COUNT_LEADING_ZEROS_INLINE int -count_leading_zeros_ll (unsigned long long int x) -{ -#if (defined _MSC_VER && !defined __clang__) && !defined _M_X64 - /* 32-bit MSVC does not have _BitScanReverse64, only _BitScanReverse. */ - unsigned long result; - if (_BitScanReverse (&result, (unsigned long) (x >> 32))) - return CHAR_BIT * sizeof x - 1 - 32 - result; - if (_BitScanReverse (&result, (unsigned long) x)) - return CHAR_BIT * sizeof x - 1 - result; - return CHAR_BIT * sizeof x; -#else - COUNT_LEADING_ZEROS (__builtin_clzll, _BitScanReverse64, - unsigned long long int); -#endif -} - -#ifdef __cplusplus -} -#endif - -_GL_INLINE_HEADER_END - -#endif /* COUNT_LEADING_ZEROS_H */ diff --git a/lib/count-one-bits.h b/lib/count-one-bits.h deleted file mode 100644 index 24bf8cc2327..00000000000 --- a/lib/count-one-bits.h +++ /dev/null @@ -1,169 +0,0 @@ -/* count-one-bits.h -- counts the number of 1-bits in a word. - Copyright (C) 2007-2024 Free Software Foundation, Inc. - - This file is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - This file is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program. If not, see . */ - -/* Written by Ben Pfaff. */ - -#ifndef COUNT_ONE_BITS_H -#define COUNT_ONE_BITS_H 1 - -/* This file uses _GL_INLINE_HEADER_BEGIN, _GL_INLINE. */ -#if !_GL_CONFIG_H_INCLUDED - #error "Please include config.h first." -#endif - -#include -#include - -_GL_INLINE_HEADER_BEGIN -#ifndef COUNT_ONE_BITS_INLINE -# define COUNT_ONE_BITS_INLINE _GL_INLINE -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* Assuming the GCC builtin is GCC_BUILTIN and the MSC builtin is MSC_BUILTIN, - expand to code that computes the number of 1-bits of the local - variable 'x' of type TYPE (an unsigned integer type) and return it - from the current function. */ -#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) \ - || (__clang_major__ >= 4) -# define COUNT_ONE_BITS(GCC_BUILTIN, MSC_BUILTIN, TYPE) \ - return GCC_BUILTIN (x) -#else - -/* Compute and return the number of 1-bits set in the least - significant 32 bits of X. */ -COUNT_ONE_BITS_INLINE int -count_one_bits_32 (unsigned int x) -{ - x = ((x & 0xaaaaaaaaU) >> 1) + (x & 0x55555555U); - x = ((x & 0xccccccccU) >> 2) + (x & 0x33333333U); - x = (x >> 16) + (x & 0xffff); - x = ((x & 0xf0f0) >> 4) + (x & 0x0f0f); - return (x >> 8) + (x & 0x00ff); -} - -/* Expand to code that computes the number of 1-bits of the local - variable 'x' of type TYPE (an unsigned integer type) and return it - from the current function. */ -# define COUNT_ONE_BITS_GENERIC(TYPE) \ - do \ - { \ - int count = 0; \ - int bits; \ - for (bits = 0; bits < sizeof (TYPE) * CHAR_BIT; bits += 32) \ - { \ - count += count_one_bits_32 (x); \ - x = x >> 31 >> 1; \ - } \ - return count; \ - } \ - while (0) - -# if 1500 <= _MSC_VER && (defined _M_IX86 || defined _M_X64) - -/* While gcc falls back to its own generic code if the machine - on which it's running doesn't support popcount, with Microsoft's - compiler we need to detect and fallback ourselves. */ - -# if 0 -# include -# else - /* Don't pollute the namespace with too many MSVC intrinsics. */ -extern void __cpuid (int[4], int); -# pragma intrinsic (__cpuid) -extern unsigned int __popcnt (unsigned int); -# pragma intrinsic (__popcnt) -# if defined _M_X64 -extern unsigned long long __popcnt64 (unsigned long long); -# pragma intrinsic (__popcnt64) -# endif -# endif - -# if !defined _M_X64 -static inline __popcnt64 (unsigned long long x) -{ - return __popcnt ((unsigned int) (x >> 32)) + __popcnt ((unsigned int) x); -} -# endif - -/* Return nonzero if popcount is supported. */ - -/* 1 if supported, 0 if not supported, -1 if unknown. */ -extern int popcount_support; - -COUNT_ONE_BITS_INLINE int -popcount_supported (void) -{ - if (popcount_support < 0) - { - /* Do as described in - */ - int cpu_info[4]; - __cpuid (cpu_info, 1); - popcount_support = (cpu_info[2] >> 23) & 1; - } - return popcount_support; -} - -# define COUNT_ONE_BITS(GCC_BUILTIN, MSC_BUILTIN, TYPE) \ - do \ - { \ - if (popcount_supported ()) \ - return MSC_BUILTIN (x); \ - else \ - COUNT_ONE_BITS_GENERIC (TYPE); \ - } \ - while (0) - -# else - -# define COUNT_ONE_BITS(GCC_BUILTIN, MSC_BUILTIN, TYPE) \ - COUNT_ONE_BITS_GENERIC (TYPE) - -# endif -#endif - -/* Compute and return the number of 1-bits set in X. */ -COUNT_ONE_BITS_INLINE int -count_one_bits (unsigned int x) -{ - COUNT_ONE_BITS (__builtin_popcount, __popcnt, unsigned int); -} - -/* Compute and return the number of 1-bits set in X. */ -COUNT_ONE_BITS_INLINE int -count_one_bits_l (unsigned long int x) -{ - COUNT_ONE_BITS (__builtin_popcountl, __popcnt, unsigned long int); -} - -/* Compute and return the number of 1-bits set in X. */ -COUNT_ONE_BITS_INLINE int -count_one_bits_ll (unsigned long long int x) -{ - COUNT_ONE_BITS (__builtin_popcountll, __popcnt64, unsigned long long int); -} - -#ifdef __cplusplus -} -#endif - -_GL_INLINE_HEADER_END - -#endif /* COUNT_ONE_BITS_H */ diff --git a/lib/count-trailing-zeros.h b/lib/count-trailing-zeros.h deleted file mode 100644 index 82de8731ec1..00000000000 --- a/lib/count-trailing-zeros.h +++ /dev/null @@ -1,130 +0,0 @@ -/* count-trailing-zeros.h -- counts the number of trailing 0 bits in a word. - Copyright 2013-2024 Free Software Foundation, Inc. - - This file is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - This file is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program. If not, see . */ - -/* Written by Paul Eggert. */ - -#ifndef COUNT_TRAILING_ZEROS_H -#define COUNT_TRAILING_ZEROS_H 1 - -/* This file uses _GL_INLINE_HEADER_BEGIN, _GL_INLINE. */ -#if !_GL_CONFIG_H_INCLUDED - #error "Please include config.h first." -#endif - -#include -#include - -_GL_INLINE_HEADER_BEGIN -#ifndef COUNT_TRAILING_ZEROS_INLINE -# define COUNT_TRAILING_ZEROS_INLINE _GL_INLINE -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* Assuming the GCC builtin is BUILTIN and the MSC builtin is MSC_BUILTIN, - expand to code that computes the number of trailing zeros of the local - variable 'x' of type TYPE (an unsigned integer type) and return it - from the current function. */ -#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) \ - || (__clang_major__ >= 4) -# define COUNT_TRAILING_ZEROS(BUILTIN, MSC_BUILTIN, TYPE) \ - return x ? BUILTIN (x) : CHAR_BIT * sizeof x; -#elif _MSC_VER -extern unsigned char _BitScanForward (unsigned long *, unsigned long); -# pragma intrinsic (_BitScanForward) -# if defined _M_X64 -extern unsigned char _BitScanForward64 (unsigned long *, unsigned long long); -# pragma intrinsic (_BitScanForward64) -# endif -# define COUNT_TRAILING_ZEROS(BUILTIN, MSC_BUILTIN, TYPE) \ - do \ - { \ - unsigned long result; \ - return MSC_BUILTIN (&result, x) ? result : CHAR_BIT * sizeof x; \ - } \ - while (0) -#else -# define COUNT_TRAILING_ZEROS(BUILTIN, MSC_BUILTIN, TYPE) \ - do \ - { \ - int count = 0; \ - if (! x) \ - return CHAR_BIT * sizeof x; \ - for (count = 0; \ - (count < CHAR_BIT * sizeof x - 32 \ - && ! (x & 0xffffffffU)); \ - count += 32) \ - x = x >> 31 >> 1; \ - return count + count_trailing_zeros_32 (x); \ - } \ - while (0) - -/* Compute and return the number of trailing zeros in the least - significant 32 bits of X. One of these bits must be nonzero. */ -COUNT_TRAILING_ZEROS_INLINE int -count_trailing_zeros_32 (unsigned int x) -{ - /* - */ - static const char de_Bruijn_lookup[32] = { - 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, - 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 - }; - return de_Bruijn_lookup[(((x & -x) * 0x077cb531U) & 0xffffffffU) >> 27]; -} -#endif - -/* Compute and return the number of trailing zeros in X. */ -COUNT_TRAILING_ZEROS_INLINE int -count_trailing_zeros (unsigned int x) -{ - COUNT_TRAILING_ZEROS (__builtin_ctz, _BitScanForward, unsigned int); -} - -/* Compute and return the number of trailing zeros in X. */ -COUNT_TRAILING_ZEROS_INLINE int -count_trailing_zeros_l (unsigned long int x) -{ - COUNT_TRAILING_ZEROS (__builtin_ctzl, _BitScanForward, unsigned long int); -} - -/* Compute and return the number of trailing zeros in X. */ -COUNT_TRAILING_ZEROS_INLINE int -count_trailing_zeros_ll (unsigned long long int x) -{ -#if (defined _MSC_VER && !defined __clang__) && !defined _M_X64 - /* 32-bit MSVC does not have _BitScanForward64, only _BitScanForward. */ - unsigned long result; - if (_BitScanForward (&result, (unsigned long) x)) - return result; - if (_BitScanForward (&result, (unsigned long) (x >> 32))) - return result + 32; - return CHAR_BIT * sizeof x; -#else - COUNT_TRAILING_ZEROS (__builtin_ctzll, _BitScanForward64, - unsigned long long int); -#endif -} - -#ifdef __cplusplus -} -#endif - -_GL_INLINE_HEADER_END - -#endif diff --git a/lib/gnulib.mk.in b/lib/gnulib.mk.in index d03e193b63c..358d58d5015 100644 --- a/lib/gnulib.mk.in +++ b/lib/gnulib.mk.in @@ -86,9 +86,6 @@ # careadlinkat \ # close-stream \ # copy-file-range \ -# count-leading-zeros \ -# count-one-bits \ -# count-trailing-zeros \ # crypto/md5 \ # crypto/md5-buffer \ # crypto/sha1-buffer \ @@ -156,6 +153,9 @@ # stat-time \ # std-gnu11 \ # stdbool \ +# stdc_bit_width \ +# stdc_count_ones \ +# stdc_trailing_zeros \ # stdckdint \ # stddef \ # stdio \ @@ -358,6 +358,7 @@ GL_GENERATE_GMP_H_CONDITION = @GL_GENERATE_GMP_H_CONDITION@ GL_GENERATE_IEEE754_H_CONDITION = @GL_GENERATE_IEEE754_H_CONDITION@ GL_GENERATE_LIMITS_H_CONDITION = @GL_GENERATE_LIMITS_H_CONDITION@ GL_GENERATE_MINI_GMP_H_CONDITION = @GL_GENERATE_MINI_GMP_H_CONDITION@ +GL_GENERATE_STDBIT_H_CONDITION = @GL_GENERATE_STDBIT_H_CONDITION@ GL_GENERATE_STDCKDINT_H_CONDITION = @GL_GENERATE_STDCKDINT_H_CONDITION@ GL_GENERATE_STDDEF_H_CONDITION = @GL_GENERATE_STDDEF_H_CONDITION@ GL_GENERATE_STDINT_H_CONDITION = @GL_GENERATE_STDINT_H_CONDITION@ @@ -664,6 +665,20 @@ GL_GNULIB_VSPRINTF_POSIX = @GL_GNULIB_VSPRINTF_POSIX@ GL_GNULIB_WCTOMB = @GL_GNULIB_WCTOMB@ GL_GNULIB_WRITE = @GL_GNULIB_WRITE@ GL_GNULIB__EXIT = @GL_GNULIB__EXIT@ +GL_STDC_BIT_CEIL = @GL_STDC_BIT_CEIL@ +GL_STDC_BIT_FLOOR = @GL_STDC_BIT_FLOOR@ +GL_STDC_BIT_WIDTH = @GL_STDC_BIT_WIDTH@ +GL_STDC_COUNT_ONES = @GL_STDC_COUNT_ONES@ +GL_STDC_COUNT_ZEROS = @GL_STDC_COUNT_ZEROS@ +GL_STDC_FIRST_LEADING_ONE = @GL_STDC_FIRST_LEADING_ONE@ +GL_STDC_FIRST_LEADING_ZERO = @GL_STDC_FIRST_LEADING_ZERO@ +GL_STDC_FIRST_TRAILING_ONE = @GL_STDC_FIRST_TRAILING_ONE@ +GL_STDC_FIRST_TRAILING_ZERO = @GL_STDC_FIRST_TRAILING_ZERO@ +GL_STDC_HAS_SINGLE_BIT = @GL_STDC_HAS_SINGLE_BIT@ +GL_STDC_LEADING_ONES = @GL_STDC_LEADING_ONES@ +GL_STDC_LEADING_ZEROS = @GL_STDC_LEADING_ZEROS@ +GL_STDC_TRAILING_ONES = @GL_STDC_TRAILING_ONES@ +GL_STDC_TRAILING_ZEROS = @GL_STDC_TRAILING_ZEROS@ GMALLOC_OBJ = @GMALLOC_OBJ@ GMP_H = @GMP_H@ GNULIBHEADERS_OVERRIDE_WINT_T = @GNULIBHEADERS_OVERRIDE_WINT_T@ @@ -1315,6 +1330,7 @@ SIZE_T_SUFFIX = @SIZE_T_SUFFIX@ SMALL_JA_DIC = @SMALL_JA_DIC@ SQLITE3_CFLAGS = @SQLITE3_CFLAGS@ SQLITE3_LIBS = @SQLITE3_LIBS@ +STDBIT_H = @STDBIT_H@ STDCKDINT_H = @STDCKDINT_H@ STDDEF_H = @STDDEF_H@ STDDEF_NOT_IDEMPOTENT = @STDDEF_NOT_IDEMPOTENT@ @@ -1444,6 +1460,7 @@ gl_GNULIB_ENABLED_open_CONDITION = @gl_GNULIB_ENABLED_open_CONDITION@ gl_GNULIB_ENABLED_rawmemchr_CONDITION = @gl_GNULIB_ENABLED_rawmemchr_CONDITION@ gl_GNULIB_ENABLED_strtoll_CONDITION = @gl_GNULIB_ENABLED_strtoll_CONDITION@ gl_GNULIB_ENABLED_utimens_CONDITION = @gl_GNULIB_ENABLED_utimens_CONDITION@ +gl_GNULIB_ENABLED_verify_CONDITION = @gl_GNULIB_ENABLED_verify_CONDITION@ gl_LIBOBJDEPS = @gl_LIBOBJDEPS@ gl_LIBOBJS = @gl_LIBOBJS@ gl_LTLIBOBJS = @gl_LTLIBOBJS@ @@ -1721,36 +1738,6 @@ endif endif ## end gnulib module copy-file-range -## begin gnulib module count-leading-zeros -ifeq (,$(OMIT_GNULIB_MODULE_count-leading-zeros)) - -libgnu_a_SOURCES += count-leading-zeros.c - -EXTRA_DIST += count-leading-zeros.h - -endif -## end gnulib module count-leading-zeros - -## begin gnulib module count-one-bits -ifeq (,$(OMIT_GNULIB_MODULE_count-one-bits)) - -libgnu_a_SOURCES += count-one-bits.c - -EXTRA_DIST += count-one-bits.h - -endif -## end gnulib module count-one-bits - -## begin gnulib module count-trailing-zeros -ifeq (,$(OMIT_GNULIB_MODULE_count-trailing-zeros)) - -libgnu_a_SOURCES += count-trailing-zeros.c - -EXTRA_DIST += count-trailing-zeros.h - -endif -## end gnulib module count-trailing-zeros - ## begin gnulib module crypto/md5 ifeq (,$(OMIT_GNULIB_MODULE_crypto/md5)) @@ -3052,6 +3039,84 @@ EXTRA_DIST += stat-time.h endif ## end gnulib module stat-time +## begin gnulib module stdbit-h +ifeq (,$(OMIT_GNULIB_MODULE_stdbit-h)) + +BUILT_SOURCES += $(STDBIT_H) + +# We need the following in order to create when the system +# doesn't have one that works with the given compiler. +ifneq (,$(GL_GENERATE_STDBIT_H_CONDITION)) +stdbit.h: stdbit.in.h $(top_builddir)/config.status + $(gl_V_at)$(SED_HEADER_STDOUT) \ + -e 's/@''GL_STDC_LEADING_ZEROS''@/$(GL_STDC_LEADING_ZEROS)/g' \ + -e 's/@''GL_STDC_LEADING_ONES''@/$(GL_STDC_LEADING_ONES)/g' \ + -e 's/@''GL_STDC_TRAILING_ZEROS''@/$(GL_STDC_TRAILING_ZEROS)/g' \ + -e 's/@''GL_STDC_TRAILING_ONES''@/$(GL_STDC_TRAILING_ONES)/g' \ + -e 's/@''GL_STDC_FIRST_LEADING_ZERO''@/$(GL_STDC_FIRST_LEADING_ZERO)/g' \ + -e 's/@''GL_STDC_FIRST_LEADING_ONE''@/$(GL_STDC_FIRST_LEADING_ONE)/g' \ + -e 's/@''GL_STDC_FIRST_TRAILING_ZERO''@/$(GL_STDC_FIRST_TRAILING_ZERO)/g' \ + -e 's/@''GL_STDC_FIRST_TRAILING_ONE''@/$(GL_STDC_FIRST_TRAILING_ONE)/g' \ + -e 's/@''GL_STDC_COUNT_ZEROS''@/$(GL_STDC_COUNT_ZEROS)/g' \ + -e 's/@''GL_STDC_COUNT_ONES''@/$(GL_STDC_COUNT_ONES)/g' \ + -e 's/@''GL_STDC_HAS_SINGLE_BIT''@/$(GL_STDC_HAS_SINGLE_BIT)/g' \ + -e 's/@''GL_STDC_BIT_WIDTH''@/$(GL_STDC_BIT_WIDTH)/g' \ + -e 's/@''GL_STDC_BIT_FLOOR''@/$(GL_STDC_BIT_FLOOR)/g' \ + -e 's/@''GL_STDC_BIT_CEIL''@/$(GL_STDC_BIT_CEIL)/g' \ + $(srcdir)/stdbit.in.h > $@-t + $(AM_V_at)mv $@-t $@ +libgnu_a_SOURCES += stdbit.c +else +stdbit.h: $(top_builddir)/config.status + rm -f $@ +endif +MOSTLYCLEANFILES += stdbit.h stdbit.h-t + +EXTRA_DIST += stdbit.in.h + +endif +## end gnulib module stdbit-h + +## begin gnulib module stdc_bit_width +ifeq (,$(OMIT_GNULIB_MODULE_stdc_bit_width)) + +ifneq (,$(GL_GENERATE_STDBIT_H_CONDITION)) +libgnu_a_SOURCES += stdc_bit_width.c +endif + +endif +## end gnulib module stdc_bit_width + +## begin gnulib module stdc_count_ones +ifeq (,$(OMIT_GNULIB_MODULE_stdc_count_ones)) + +ifneq (,$(GL_GENERATE_STDBIT_H_CONDITION)) +libgnu_a_SOURCES += stdc_count_ones.c +endif + +endif +## end gnulib module stdc_count_ones + +## begin gnulib module stdc_leading_zeros +ifeq (,$(OMIT_GNULIB_MODULE_stdc_leading_zeros)) + +ifneq (,$(GL_GENERATE_STDBIT_H_CONDITION)) +libgnu_a_SOURCES += stdc_leading_zeros.c +endif + +endif +## end gnulib module stdc_leading_zeros + +## begin gnulib module stdc_trailing_zeros +ifeq (,$(OMIT_GNULIB_MODULE_stdc_trailing_zeros)) + +ifneq (,$(GL_GENERATE_STDBIT_H_CONDITION)) +libgnu_a_SOURCES += stdc_trailing_zeros.c +endif + +endif +## end gnulib module stdc_trailing_zeros + ## begin gnulib module stdckdint ifeq (,$(OMIT_GNULIB_MODULE_stdckdint)) @@ -4274,7 +4339,9 @@ endif ## begin gnulib module verify ifeq (,$(OMIT_GNULIB_MODULE_verify)) +ifneq (,$(gl_GNULIB_ENABLED_verify_CONDITION)) +endif EXTRA_DIST += verify.h endif diff --git a/lib/stdbit.c b/lib/stdbit.c new file mode 100644 index 00000000000..4801e74d281 --- /dev/null +++ b/lib/stdbit.c @@ -0,0 +1,23 @@ +/* Support C23 bit and byte utilities on non-C23 platforms. + + Copyright 2024 Free Software Foundation, Inc. + + This file is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . */ + +/* Written by Paul Eggert. */ + +#include + +#define _GL_STDBIT_INLINE _GL_EXTERN_INLINE +#include diff --git a/lib/stdbit.in.h b/lib/stdbit.in.h new file mode 100644 index 00000000000..9f9e60a5d38 --- /dev/null +++ b/lib/stdbit.in.h @@ -0,0 +1,1077 @@ +/* stdbit.h - C23 bit and byte utilities for non-C23 platforms + + Copyright 2024 Free Software Foundation, Inc. + + This file is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . */ + +/* Written by Paul Eggert. */ + +#ifndef STDBIT_H +#define STDBIT_H 1 + +/* This file uses _GL_INLINE, WORDS_BIGENDIAN. */ +#if !_GL_CONFIG_H_INCLUDED + #error "Please include config.h first." +#endif + +_GL_INLINE_HEADER_BEGIN + +#ifndef _GL_STDBIT_INLINE +# define _GL_STDBIT_INLINE _GL_INLINE +#endif +#ifndef _GL_STDC_LEADING_ZEROS_INLINE +# define _GL_STDC_LEADING_ZEROS_INLINE _GL_INLINE +#endif +#ifndef _GL_STDC_LEADING_ONES_INLINE +# define _GL_STDC_LEADING_ONES_INLINE _GL_INLINE +#endif +#ifndef _GL_STDC_TRAILING_ZEROS_INLINE +# define _GL_STDC_TRAILING_ZEROS_INLINE _GL_INLINE +#endif +#ifndef _GL_STDC_TRAILING_ONES_INLINE +# define _GL_STDC_TRAILING_ONES_INLINE _GL_INLINE +#endif +#ifndef _GL_STDC_FIRST_LEADING_ZERO_INLINE +# define _GL_STDC_FIRST_LEADING_ZERO_INLINE _GL_INLINE +#endif +#ifndef _GL_STDC_FIRST_LEADING_ONE_INLINE +# define _GL_STDC_FIRST_LEADING_ONE_INLINE _GL_INLINE +#endif +#ifndef _GL_STDC_FIRST_TRAILING_ZERO_INLINE +# define _GL_STDC_FIRST_TRAILING_ZERO_INLINE _GL_INLINE +#endif +#ifndef _GL_STDC_FIRST_TRAILING_ONE_INLINE +# define _GL_STDC_FIRST_TRAILING_ONE_INLINE _GL_INLINE +#endif +#ifndef _GL_STDC_COUNT_ZEROS_INLINE +# define _GL_STDC_COUNT_ZEROS_INLINE _GL_INLINE +#endif +#ifndef _GL_STDC_COUNT_ONES_INLINE +# define _GL_STDC_COUNT_ONES_INLINE _GL_INLINE +#endif +#ifndef _GL_STDC_HAS_SINGLE_BIT_INLINE +# define _GL_STDC_HAS_SINGLE_BIT_INLINE _GL_INLINE +#endif +#ifndef _GL_STDC_BIT_WIDTH_INLINE +# define _GL_STDC_BIT_WIDTH_INLINE _GL_INLINE +#endif +#ifndef _GL_STDC_BIT_FLOOR_INLINE +# define _GL_STDC_BIT_FLOOR_INLINE _GL_INLINE +#endif +#ifndef _GL_STDC_BIT_CEIL_INLINE +# define _GL_STDC_BIT_CEIL_INLINE _GL_INLINE +#endif + +/* An expression, preferably with the type of A, that has the value of B. */ +#if ((defined __GNUC__ && 2 <= __GNUC__) \ + || (defined __clang_major__ && 4 <= __clang_major__) \ + || (defined __IBMC__ && 1210 <= __IBMC__ && defined __IBM__TYPEOF__) \ + || (defined __SUNPRO_C && 0x5110 <= __SUNPRO_C && !__STDC__)) +# define _GL_STDBIT_TYPEOF_CAST(a, b) ((__typeof__ (a)) (b)) +#elif 202311 <= __STDC_VERSION__ +# define _GL_STDBIT_TYPEOF_CAST(a, b) ((typeof (a)) (b)) +#else +/* This platform is so old that it lacks typeof, so _Generic is likely + missing or unreliable. The C23 standard seems to allow yielding B + (which is always unsigned long long int), so do that. */ +# define _GL_STDBIT_TYPEOF_CAST(a, b) (b) +#endif + + +/* ISO C 23 § 7.18.1 General */ + +#define __STDC_VERSION_STDBIT_H__ 202311L + + +/* ISO C 23 § 7.18.2 Endian */ + +#define __STDC_ENDIAN_BIG__ 4321 +#define __STDC_ENDIAN_LITTLE__ 1234 +#ifdef WORDS_BIGENDIAN +# define __STDC_ENDIAN_NATIVE__ __STDC_ENDIAN_BIG__ +#else +# define __STDC_ENDIAN_NATIVE__ __STDC_ENDIAN_LITTLE__ +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + +#if 3 < __GNUC__ + (4 <= __GNUC_MINOR__) || 4 <= __clang_major__ +# define _GL_STDBIT_HAS_BUILTIN_CLZ true +# define _GL_STDBIT_HAS_BUILTIN_CTZ true +# define _GL_STDBIT_HAS_BUILTIN_POPCOUNT true +#elif defined __has_builtin +# if (__has_builtin (__builtin_clz) \ + && __has_builtin (__builtin_clzl) \ + && __has_builtin (__builtin_clzll)) +# define _GL_STDBIT_HAS_BUILTIN_CLZ true +# endif +# if (__has_builtin (__builtin_ctz) \ + && __has_builtin (__builtin_ctzl) \ + && __has_builtin (__builtin_ctzll)) +# define _GL_STDBIT_HAS_BUILTIN_CTZ true +# endif +# if (__has_builtin (__builtin_popcount) \ + && __has_builtin (__builtin_popcountl) \ + && __has_builtin (__builtin_popcountll)) +# define _GL_STDBIT_HAS_BUILTIN_POPCOUNT true +# endif +#endif + +/* Count leading 0 bits of N, even if N is 0. */ +#ifdef _GL_STDBIT_HAS_BUILTIN_CLZ +_GL_STDBIT_INLINE int +__gl_stdbit_clz (unsigned int n) +{ + return n ? __builtin_clz (n) : 8 * sizeof n; +} +_GL_STDBIT_INLINE int +__gl_stdbit_clzl (unsigned long int n) +{ + return n ? __builtin_clzl (n) : 8 * sizeof n; +} +_GL_STDBIT_INLINE int +__gl_stdbit_clzll (unsigned long long int n) +{ + return n ? __builtin_clzll (n) : 8 * sizeof n; +} +#elif defined _MSC_VER + +/* Declare the few MSVC intrinsics that we need. We prefer not to include + because it would pollute the namespace. */ +extern unsigned char _BitScanReverse (unsigned long *, unsigned long); +# pragma intrinsic (_BitScanReverse) +# ifdef _M_X64 +extern unsigned char _BitScanReverse64 (unsigned long *, unsigned long long); +# pragma intrinsic (_BitScanReverse64) +# endif + +_GL_STDBIT_INLINE int +__gl_stdbit_clzl (unsigned long int n) +{ + unsigned long int r; + return 8 * sizeof n - (_BitScanReverse (&r, n) ? r + 1 : 0); +} +_GL_STDBIT_INLINE int +__gl_stdbit_clz (unsigned int n) +{ + return __gl_stdbit_clzl (n) - 8 * (sizeof 0ul - sizeof n); +} +_GL_STDBIT_INLINE int +__gl_stdbit_clzll (unsigned long long int n) +{ +# ifdef _M_X64 + unsigned long int r; + return 8 * sizeof n - (_BitScanReverse64 (&r, n) ? r + 1 : 0); +# else + unsigned long int hi = n >> 32; + return __gl_stdbit_clzl (hi ? hi : n) + (hi ? 0 : 32); +# endif +} + +#else /* !_MSC_VER */ + +_GL_STDBIT_INLINE int +__gl_stdbit_clzll (unsigned long long int n) +{ + int r = 0; + for (int i = 8 * sizeof n >> 1; 1 << 6 <= i; i >>= 1) + { + int a = (1ull << i <= n) * i; n >>= a; r += a; + } + int a5 = (0x00000000ffffffff < n) << 5; n >>= a5; r += a5; + int a4 = (0x000000000000ffff < n) << 4; n >>= a4; r += a4; + int a3 = (0x00000000000000ff < n) << 3; n >>= a3; r += a3; + int a2 = (0x000000000000000f < n) << 2; n >>= a2; r += a2; + return (8 * sizeof n - (1 << 2) - r) + ((0x11112234ull >> (n << 2)) & 0xf); +} +_GL_STDBIT_INLINE int +__gl_stdbit_clz (unsigned int n) +{ + return __gl_stdbit_clzll (n) - 8 * (sizeof 0ull - sizeof 0u); +} +_GL_STDBIT_INLINE int +__gl_stdbit_clzl (unsigned long int n) +{ + return __gl_stdbit_clzll (n) - 8 * (sizeof 0ull - sizeof 0ul); +} +#endif + +/* Count trailing 0 bits of N, even if N is 0. */ +#ifdef _GL_STDBIT_HAS_BUILTIN_CTZ +_GL_STDBIT_INLINE int +__gl_stdbit_ctz (unsigned int n) +{ + return n ? __builtin_ctz (n) : 8 * sizeof n; +} +_GL_STDBIT_INLINE int +__gl_stdbit_ctzl (unsigned long int n) +{ + return n ? __builtin_ctzl (n) : 8 * sizeof n; +} +_GL_STDBIT_INLINE int +__gl_stdbit_ctzll (unsigned long long int n) +{ + return n ? __builtin_ctzll (n) : 8 * sizeof n; +} +#elif defined _MSC_VER + +/* Declare the few MSVC intrinsics that we need. We prefer not to include + because it would pollute the namespace. */ +extern unsigned char _BitScanForward (unsigned long *, unsigned long); +# pragma intrinsic (_BitScanForward) +# ifdef _M_X64 +extern unsigned char _BitScanForward64 (unsigned long *, unsigned long long); +# pragma intrinsic (_BitScanForward64) +# endif + +_GL_STDBIT_INLINE int +__gl_stdbit_ctzl (unsigned long int n) +{ + unsigned long int r; + return _BitScanForward (&r, n) ? r : 8 * sizeof n; +} +_GL_STDBIT_INLINE int +__gl_stdbit_ctz (unsigned int n) +{ + return __gl_stdbit_ctzl (n | (1ul << (8 * sizeof n - 1) << 1)); +} +_GL_STDBIT_INLINE int +__gl_stdbit_ctzll (unsigned long long int n) +{ +# ifdef _M_X64 + unsigned long int r; + return _BitScanForward64 (&r, n) ? r : 8 * sizeof n; +# else + unsigned int lo = n; + return __gl_stdbit_ctzl (lo ? lo : n >> 32) + (lo ? 0 : 32); +# endif +} + +#else /* !_MSC_VER */ + +_GL_STDBIT_INLINE int +__gl_stdbit_ctz (unsigned int n) +{ + return 8 * sizeof n - (n ? __gl_stdbit_clz (n & -n) + 1 : 0); +} +_GL_STDBIT_INLINE int +__gl_stdbit_ctzl (unsigned long int n) +{ + return 8 * sizeof n - (n ? __gl_stdbit_clzl (n & -n) + 1 : 0); +} +_GL_STDBIT_INLINE int +__gl_stdbit_ctzll (unsigned long long int n) +{ + return 8 * sizeof n - (n ? __gl_stdbit_clzll (n & -n) + 1 : 0); +} +#endif + +#if @GL_STDC_COUNT_ONES@ +/* Count 1 bits in N. */ +# ifdef _GL_STDBIT_HAS_BUILTIN_POPCOUNT +# define __gl_stdbit_popcount __builtin_popcount +# define __gl_stdbit_popcountl __builtin_popcountl +# define __gl_stdbit_popcountll __builtin_popcountll +# else +_GL_STDC_COUNT_ONES_INLINE int +__gl_stdbit_popcount_wide (unsigned long long int n) +{ + if (sizeof n & (sizeof n - 1)) + { + /* Use a simple O(log N) loop on theoretical platforms where N's + width is not a power of 2. */ + int count = 0; + for (int i = 0; i < 8 * sizeof n; i++, n >>= 1) + count += n & 1; + return count; + } + else + { + /* N's width is a power of 2; count in parallel. */ + unsigned long long int + max = -1ull, + x555555 = max / (1 << 1 | 1), /* 0x555555... */ + x333333 = max / (1 << 2 | 1), /* 0x333333... */ + x0f0f0f = max / (1 << 4 | 1), /* 0x0f0f0f... */ + x010101 = max / ((1 << 8) - 1), /* 0x010101... */ + x000_7f = max / 0xffffffffffffffff * 0x7f; /* 0x000000000000007f... */ + n -= (n >> 1) & x555555; + n = (n & x333333) + ((n >> 2) & x333333); + n = (n + (n >> 4)) & x0f0f0f; + + /* If the popcount always fits in 8 bits, multiply so that the + popcount is in the leading 8 bits of the product; these days + this is typically faster than the alternative below. */ + if (8 * sizeof n < 1 << 8) + return n * x010101 >> 8 * (sizeof n - 1); + + /* N is at least 256 bits wide! Fall back on an O(log log N) + loop that a compiler could unroll. Unroll the first three + iterations by hand, to skip some division and masking. This + is the most we can easily do without hassling with constants + that a typical-platform compiler would reject. */ + n += n >> (1 << 3); + n += n >> (1 << 4); + n += n >> (1 << 5); + n &= x000_7f; + for (int i = 64; i < 8 * sizeof n; i <<= 1) + n = (n + (n >> i)) & max / (1ull << i | 1); + return n; + } +} + +# ifdef _MSC_VER +# if 1500 <= _MSC_VER && (defined _M_IX86 || defined _M_X64) +/* Declare the few MSVC intrinsics that we need. We prefer not to include + because it would pollute the namespace. */ +extern void __cpuid (int[4], int); +# pragma intrinsic (__cpuid) +extern unsigned int __popcnt (unsigned int); +# pragma intrinsic (__popcnt) +# ifdef _M_X64 +extern unsigned long long __popcnt64 (unsigned long long); +# pragma intrinsic (__popcnt64) +# else +_GL_STDC_COUNT_ONES_INLINE int +__popcnt64 (unsigned long long int n) +{ + return __popcnt (n >> 32) + __popcnt (n); +} +# endif +# endif + +/* 1 if supported, -1 if not, 0 if unknown. */ +extern signed char __gl_stdbit_popcount_support; + +_GL_STDC_COUNT_ONES_INLINE bool +__gl_stdbit_popcount_supported (void) +{ + if (!__gl_stdbit_popcount_support) + { + /* Do as described in + + Although Microsoft started requiring POPCNT in MS-Windows 11 24H2, + we'll be more cautious. */ + int cpu_info[4]; + __cpuid (cpu_info, 1); + __gl_stdbit_popcount_support = cpu_info[2] & 1 << 23 ? 1 : -1; + } + return 0 < __gl_stdbit_popcount_support; +} +_GL_STDC_COUNT_ONES_INLINE int +__gl_stdbit_popcount (unsigned int n) +{ + return (__gl_stdbit_popcount_supported () + ? __popcnt (n) + : __gl_stdbit_popcount_wide (n)); +} +_GL_STDC_COUNT_ONES_INLINE int +__gl_stdbit_popcountl (unsigned long int n) +{ + return (__gl_stdbit_popcount_supported () + ? __popcnt (n) + : __gl_stdbit_popcount_wide (n)); +} +_GL_STDC_COUNT_ONES_INLINE int +__gl_stdbit_popcountll (unsigned long long int n) +{ + return (__gl_stdbit_popcount_supported () + ? __popcnt64 (n) + : __gl_stdbit_popcount_wide (n)); +} +# else /* !_MSC_VER */ +# define __gl_stdbit_popcount __gl_stdbit_popcount_wide +# define __gl_stdbit_popcountl __gl_stdbit_popcount_wide +# define __gl_stdbit_popcountll __gl_stdbit_popcount_wide +# endif +# endif +#endif + + +/* ISO C 23 § 7.18.3 Count Leading Zeros */ + +#if @GL_STDC_LEADING_ZEROS@ + +_GL_STDC_LEADING_ZEROS_INLINE unsigned int +stdc_leading_zeros_ui (unsigned int n) +{ + return __gl_stdbit_clz (n); +} + +_GL_STDC_LEADING_ZEROS_INLINE unsigned int +stdc_leading_zeros_uc (unsigned char n) +{ + return stdc_leading_zeros_ui (n) - 8 * (sizeof 0u - sizeof n); +} + +_GL_STDC_LEADING_ZEROS_INLINE unsigned int +stdc_leading_zeros_us (unsigned short int n) +{ + return stdc_leading_zeros_ui (n) - 8 * (sizeof 0u - sizeof n); +} + +_GL_STDC_LEADING_ZEROS_INLINE unsigned int +stdc_leading_zeros_ul (unsigned long int n) +{ + return __gl_stdbit_clzl (n); +} + +_GL_STDC_LEADING_ZEROS_INLINE unsigned int +stdc_leading_zeros_ull (unsigned long long int n) +{ + return __gl_stdbit_clzll (n); +} + +# define stdc_leading_zeros(n) \ + (sizeof (n) == 1 ? stdc_leading_zeros_uc (n) \ + : sizeof (n) == sizeof (unsigned short int) ? stdc_leading_zeros_us (n) \ + : sizeof (n) == sizeof 0u ? stdc_leading_zeros_ui (n) \ + : sizeof (n) == sizeof 0ul ? stdc_leading_zeros_ul (n) \ + : stdc_leading_zeros_ull (n)) + +#endif + + +/* ISO C 23 § 7.18.4 Count Leading Ones */ + +#if @GL_STDC_LEADING_ONES@ + +_GL_STDC_LEADING_ONES_INLINE unsigned int +stdc_leading_ones_uc (unsigned char n) +{ + return stdc_leading_zeros_uc (~n); +} + +_GL_STDC_LEADING_ONES_INLINE unsigned int +stdc_leading_ones_us (unsigned short int n) +{ + return stdc_leading_zeros_us (~n); +} + +_GL_STDC_LEADING_ONES_INLINE unsigned int +stdc_leading_ones_ui (unsigned int n) +{ + return stdc_leading_zeros_ui (~n); +} + +_GL_STDC_LEADING_ONES_INLINE unsigned int +stdc_leading_ones_ul (unsigned long int n) +{ + return stdc_leading_zeros_ul (~n); +} + +_GL_STDC_LEADING_ONES_INLINE unsigned int +stdc_leading_ones_ull (unsigned long long int n) +{ + return stdc_leading_zeros_ull (~n); +} + +# define stdc_leading_ones(n) \ + (sizeof (n) == 1 ? stdc_leading_ones_uc (n) \ + : sizeof (n) == sizeof (unsigned short int) ? stdc_leading_ones_us (n) \ + : sizeof (n) == sizeof 0u ? stdc_leading_ones_ui (n) \ + : sizeof (n) == sizeof 0ul ? stdc_leading_ones_ul (n) \ + : stdc_leading_ones_ull (n)) + +#endif + + +/* ISO C 23 § 7.18.5 Count Trailing Zeros */ + +#if @GL_STDC_TRAILING_ZEROS@ + +_GL_STDC_TRAILING_ZEROS_INLINE unsigned int +stdc_trailing_zeros_ui (unsigned int n) +{ + return __gl_stdbit_ctz (n); +} + +_GL_STDC_TRAILING_ZEROS_INLINE unsigned int +stdc_trailing_zeros_uc (unsigned char n) +{ + return stdc_trailing_zeros_ui (n | (1 + (unsigned char) -1)); +} + +_GL_STDC_TRAILING_ZEROS_INLINE unsigned int +stdc_trailing_zeros_us (unsigned short int n) +{ + return stdc_trailing_zeros_ui (n | (1 + (unsigned short int) -1)); +} + +_GL_STDC_TRAILING_ZEROS_INLINE unsigned int +stdc_trailing_zeros_ul (unsigned long int n) +{ + return __gl_stdbit_ctzl (n); +} + +_GL_STDC_TRAILING_ZEROS_INLINE unsigned int +stdc_trailing_zeros_ull (unsigned long long int n) +{ + return __gl_stdbit_ctzll (n); +} + +# define stdc_trailing_zeros(n) \ + (sizeof (n) == 1 ? stdc_trailing_zeros_uc (n) \ + : sizeof (n) == sizeof (unsigned short int) ? stdc_trailing_zeros_us (n) \ + : sizeof (n) == sizeof 0u ? stdc_trailing_zeros_ui (n) \ + : sizeof (n) == sizeof 0ul ? stdc_trailing_zeros_ul (n) \ + : stdc_trailing_zeros_ull (n)) + +#endif + + +/* ISO C 23 § 7.18.6 Count Trailing Ones */ + +#if @GL_STDC_TRAILING_ONES@ + +_GL_STDC_TRAILING_ONES_INLINE unsigned int +stdc_trailing_ones_uc (unsigned char n) +{ + return stdc_trailing_zeros_uc (~n); +} + +_GL_STDC_TRAILING_ONES_INLINE unsigned int +stdc_trailing_ones_us (unsigned short int n) +{ + return stdc_trailing_zeros_us (~n); +} + +_GL_STDC_TRAILING_ONES_INLINE unsigned int +stdc_trailing_ones_ui (unsigned int n) +{ + return stdc_trailing_zeros_ui (~n); +} + +_GL_STDC_TRAILING_ONES_INLINE unsigned int +stdc_trailing_ones_ul (unsigned long int n) +{ + return stdc_trailing_zeros_ul (~n); +} + +_GL_STDC_TRAILING_ONES_INLINE unsigned int +stdc_trailing_ones_ull (unsigned long long int n) +{ + return stdc_trailing_zeros_ull (~n); +} + +# define stdc_trailing_ones(n) \ + (sizeof (n) == 1 ? stdc_trailing_ones_uc (n) \ + : sizeof (n) == sizeof (unsigned short int) ? stdc_trailing_ones_us (n) \ + : sizeof (n) == sizeof 0u ? stdc_trailing_ones_ui (n) \ + : sizeof (n) == sizeof 0ul ? stdc_trailing_ones_ul (n) \ + : stdc_trailing_ones_ull (n)) + +#endif + + +/* ISO C 23 § 7.18.7 First Leading Zero */ + +#if @GL_STDC_FIRST_LEADING_ZERO@ + +_GL_STDC_FIRST_LEADING_ZERO_INLINE unsigned int +stdc_first_leading_zero_uc (unsigned char n) +{ + unsigned int count = stdc_leading_ones_uc (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +_GL_STDC_FIRST_LEADING_ZERO_INLINE unsigned int +stdc_first_leading_zero_us (unsigned short int n) +{ + unsigned int count = stdc_leading_ones_us (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +_GL_STDC_FIRST_LEADING_ZERO_INLINE unsigned int +stdc_first_leading_zero_ui (unsigned int n) +{ + unsigned int count = stdc_leading_ones_ui (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +_GL_STDC_FIRST_LEADING_ZERO_INLINE unsigned int +stdc_first_leading_zero_ul (unsigned long int n) +{ + unsigned int count = stdc_leading_ones_ul (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +_GL_STDC_FIRST_LEADING_ZERO_INLINE unsigned int +stdc_first_leading_zero_ull (unsigned long long int n) +{ + unsigned int count = stdc_leading_ones_ull (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +# define stdc_first_leading_zero(n) \ + (sizeof (n) == 1 ? stdc_first_leading_zero_uc (n) \ + : sizeof (n) == sizeof (unsigned short) ? stdc_first_leading_zero_us (n) \ + : sizeof (n) == sizeof 0u ? stdc_first_leading_zero_ui (n) \ + : sizeof (n) == sizeof 0ul ? stdc_first_leading_zero_ul (n) \ + : stdc_first_leading_zero_ull (n)) + +#endif + + +/* ISO C 23 § 7.18.8 First Leading One */ + +#if @GL_STDC_FIRST_LEADING_ONE@ + +_GL_STDC_FIRST_LEADING_ONE_INLINE unsigned int +stdc_first_leading_one_uc (unsigned char n) +{ + unsigned int count = stdc_leading_zeros_uc (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +_GL_STDC_FIRST_LEADING_ONE_INLINE unsigned int +stdc_first_leading_one_us (unsigned short int n) +{ + unsigned int count = stdc_leading_zeros_us (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +_GL_STDC_FIRST_LEADING_ONE_INLINE unsigned int +stdc_first_leading_one_ui (unsigned int n) +{ + unsigned int count = stdc_leading_zeros_ui (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +_GL_STDC_FIRST_LEADING_ONE_INLINE unsigned int +stdc_first_leading_one_ul (unsigned long int n) +{ + unsigned int count = stdc_leading_zeros_ul (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +_GL_STDC_FIRST_LEADING_ONE_INLINE unsigned int +stdc_first_leading_one_ull (unsigned long long int n) +{ + unsigned int count = stdc_leading_zeros_ull (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +# define stdc_first_leading_one(n) \ + (sizeof (n) == 1 ? stdc_first_leading_one_uc (n) \ + : sizeof (n) == sizeof (unsigned short) ? stdc_first_leading_one_us (n) \ + : sizeof (n) == sizeof 0u ? stdc_first_leading_one_ui (n) \ + : sizeof (n) == sizeof 0ul ? stdc_first_leading_one_ul (n) \ + : stdc_first_leading_one_ull (n)) + +#endif + + +/* ISO C 23 § 7.18.9 First Trailing Zero */ + +#if @GL_STDC_FIRST_TRAILING_ZERO@ + +_GL_STDC_FIRST_TRAILING_ZERO_INLINE unsigned int +stdc_first_trailing_zero_uc (unsigned char n) +{ + unsigned int count = stdc_trailing_ones_uc (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +_GL_STDC_FIRST_TRAILING_ZERO_INLINE unsigned int +stdc_first_trailing_zero_us (unsigned short int n) +{ + unsigned int count = stdc_trailing_ones_us (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +_GL_STDC_FIRST_TRAILING_ZERO_INLINE unsigned int +stdc_first_trailing_zero_ui (unsigned int n) +{ + unsigned int count = stdc_trailing_ones_ui (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +_GL_STDC_FIRST_TRAILING_ZERO_INLINE unsigned int +stdc_first_trailing_zero_ul (unsigned long int n) +{ + unsigned int count = stdc_trailing_ones_ul (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +_GL_STDC_FIRST_TRAILING_ZERO_INLINE unsigned int +stdc_first_trailing_zero_ull (unsigned long long int n) +{ + unsigned int count = stdc_trailing_ones_ull (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +# define stdc_first_trailing_zero(n) \ + (sizeof (n) == 1 ? stdc_first_trailing_zero_uc (n) \ + : sizeof (n) == sizeof (unsigned short) ? stdc_first_trailing_zero_us (n) \ + : sizeof (n) == sizeof 0u ? stdc_first_trailing_zero_ui (n) \ + : sizeof (n) == sizeof 0ul ? stdc_first_trailing_zero_ul (n) \ + : stdc_first_trailing_zero_ull (n)) + +#endif + + +/* ISO C 23 § 7.18.10 First Trailing One */ + +#if @GL_STDC_FIRST_TRAILING_ONE@ + +_GL_STDC_FIRST_TRAILING_ONE_INLINE unsigned int +stdc_first_trailing_one_uc (unsigned char n) +{ + unsigned int count = stdc_trailing_zeros_uc (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +_GL_STDC_FIRST_TRAILING_ONE_INLINE unsigned int +stdc_first_trailing_one_us (unsigned short int n) +{ + unsigned int count = stdc_trailing_zeros_us (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +_GL_STDC_FIRST_TRAILING_ONE_INLINE unsigned int +stdc_first_trailing_one_ui (unsigned int n) +{ + unsigned int count = stdc_trailing_zeros_ui (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +_GL_STDC_FIRST_TRAILING_ONE_INLINE unsigned int +stdc_first_trailing_one_ul (unsigned long int n) +{ + unsigned int count = stdc_trailing_zeros_ul (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +_GL_STDC_FIRST_TRAILING_ONE_INLINE unsigned int +stdc_first_trailing_one_ull (unsigned long long int n) +{ + unsigned int count = stdc_trailing_zeros_ull (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +#define stdc_first_trailing_one(n) \ + (sizeof (n) == 1 ? stdc_first_trailing_one_uc (n) \ + : sizeof (n) == sizeof (unsigned short) ? stdc_first_trailing_one_us (n) \ + : sizeof (n) == sizeof 0u ? stdc_first_trailing_one_ui (n) \ + : sizeof (n) == sizeof 0ul ? stdc_first_trailing_one_ul (n) \ + : stdc_first_trailing_one_ull (n)) + +#endif + + +/* ISO C 23 § 7.18.12 Count Ones */ + +#if @GL_STDC_COUNT_ONES@ + +_GL_STDC_COUNT_ONES_INLINE unsigned int +stdc_count_ones_ui (unsigned int n) +{ + return __gl_stdbit_popcount (n); +} + +_GL_STDC_COUNT_ONES_INLINE unsigned int +stdc_count_ones_uc (unsigned char n) +{ + return stdc_count_ones_ui (n); +} + +_GL_STDC_COUNT_ONES_INLINE unsigned int +stdc_count_ones_us (unsigned short int n) +{ + return stdc_count_ones_ui (n); +} + +_GL_STDC_COUNT_ONES_INLINE unsigned int +stdc_count_ones_ul (unsigned long int n) +{ + return __gl_stdbit_popcountl (n); +} + +_GL_STDC_COUNT_ONES_INLINE unsigned int +stdc_count_ones_ull (unsigned long long int n) +{ + return __gl_stdbit_popcountll (n); +} + +# define stdc_count_ones(n) \ + (sizeof (n) == 1 ? stdc_count_ones_uc (n) \ + : sizeof (n) == sizeof (unsigned short int) ? stdc_count_ones_us (n) \ + : sizeof (n) == sizeof 0u ? stdc_count_ones_ui (n) \ + : sizeof (n) == sizeof 0ul ? stdc_count_ones_ul (n) \ + : stdc_count_ones_ull (n)) + +#endif + + +/* ISO C 23 § 7.18.11 Count Zeros */ + +#if @GL_STDC_COUNT_ZEROS@ + +_GL_STDC_COUNT_ZEROS_INLINE unsigned int +stdc_count_zeros_uc (unsigned char n) +{ + return stdc_count_ones_uc (~n); +} + +_GL_STDC_COUNT_ZEROS_INLINE unsigned int +stdc_count_zeros_us (unsigned short int n) +{ + return stdc_count_ones_us (~n); +} + +_GL_STDC_COUNT_ZEROS_INLINE unsigned int +stdc_count_zeros_ui (unsigned int n) +{ + return stdc_count_ones_ui (~n); +} + +_GL_STDC_COUNT_ZEROS_INLINE unsigned int +stdc_count_zeros_ul (unsigned long int n) +{ + return stdc_count_ones_ul (~n); +} + +_GL_STDC_COUNT_ZEROS_INLINE unsigned int +stdc_count_zeros_ull (unsigned long long int n) +{ + return stdc_count_ones_ull (~n); +} + +# define stdc_count_zeros(n) \ + (sizeof (n) == 1 ? stdc_count_zeros_uc (n) \ + : sizeof (n) == sizeof (unsigned short int) ? stdc_count_zeros_us (n) \ + : sizeof (n) == sizeof 0u ? stdc_count_zeros_ui (n) \ + : sizeof (n) == sizeof 0ul ? stdc_count_zeros_ul (n) \ + : stdc_count_zeros_ull (n)) + +#endif + + +/* ISO C 23 § 7.18.13 Single-bit Check */ + +#if @GL_STDC_HAS_SINGLE_BIT@ + +_GL_STDC_HAS_SINGLE_BIT_INLINE bool +stdc_has_single_bit_uc (unsigned char n) +{ + unsigned char n_1 = n - 1, nx = n_1 ^ n; + return n_1 < nx; +} + +_GL_STDC_HAS_SINGLE_BIT_INLINE bool +stdc_has_single_bit_us (unsigned short int n) +{ + unsigned short int n_1 = n - 1, nx = n_1 ^ n; + return n_1 < nx; +} + +_GL_STDC_HAS_SINGLE_BIT_INLINE bool +stdc_has_single_bit_ui (unsigned int n) +{ + unsigned int n_1 = n - 1, nx = n_1 ^ n; + return n_1 < nx; +} + +_GL_STDC_HAS_SINGLE_BIT_INLINE bool +stdc_has_single_bit_ul (unsigned long int n) +{ + unsigned long int n_1 = n - 1, nx = n_1 ^ n; + return n_1 < nx; +} + +_GL_STDC_HAS_SINGLE_BIT_INLINE bool +stdc_has_single_bit_ull (unsigned long long int n) +{ + unsigned long long int n_1 = n - 1, nx = n_1 ^ n; + return n_1 < nx; +} + +# define stdc_has_single_bit(n) \ + ((bool) \ + (sizeof (n) == 1 ? stdc_has_single_bit_uc (n) \ + : sizeof (n) == sizeof (unsigned short int) ? stdc_has_single_bit_us (n) \ + : sizeof (n) == sizeof 0u ? stdc_has_single_bit_ui (n) \ + : sizeof (n) == sizeof 0ul ? stdc_has_single_bit_ul (n) \ + : stdc_has_single_bit_ull (n))) + +#endif + + +/* ISO C 23 § 7.18.14 Bit Width */ + +#if @GL_STDC_BIT_WIDTH@ + +_GL_STDC_BIT_WIDTH_INLINE unsigned int +stdc_bit_width_uc (unsigned char n) +{ + return 8 * sizeof n - stdc_leading_zeros_uc (n); +} + +_GL_STDC_BIT_WIDTH_INLINE unsigned int +stdc_bit_width_us (unsigned short int n) +{ + return 8 * sizeof n - stdc_leading_zeros_us (n); +} + +_GL_STDC_BIT_WIDTH_INLINE unsigned int +stdc_bit_width_ui (unsigned int n) +{ + return 8 * sizeof n - stdc_leading_zeros_ui (n); +} + +_GL_STDC_BIT_WIDTH_INLINE unsigned int +stdc_bit_width_ul (unsigned long int n) +{ + return 8 * sizeof n - stdc_leading_zeros_ul (n); +} + +_GL_STDC_BIT_WIDTH_INLINE unsigned int +stdc_bit_width_ull (unsigned long long int n) +{ + return 8 * sizeof n - stdc_leading_zeros_ull (n); +} + +# define stdc_bit_width(n) \ + (sizeof (n) == 1 ? stdc_bit_width_uc (n) \ + : sizeof (n) == sizeof (unsigned short int) ? stdc_bit_width_us (n) \ + : sizeof (n) == sizeof 0u ? stdc_bit_width_ui (n) \ + : sizeof (n) == sizeof 0ul ? stdc_bit_width_ul (n) \ + : stdc_bit_width_ull (n)) + +#endif + + +/* ISO C 23 § 7.18.15 Bit Floor */ + +#if @GL_STDC_BIT_FLOOR@ + +_GL_STDC_BIT_FLOOR_INLINE unsigned char +stdc_bit_floor_uc (unsigned char n) +{ + return n ? 1u << (stdc_bit_width_uc (n) - 1) : 0; +} + +_GL_STDC_BIT_FLOOR_INLINE unsigned short int +stdc_bit_floor_us (unsigned short int n) +{ + return n ? 1u << (stdc_bit_width_us (n) - 1) : 0; +} + +_GL_STDC_BIT_FLOOR_INLINE unsigned int +stdc_bit_floor_ui (unsigned int n) +{ + return n ? 1u << (stdc_bit_width_ui (n) - 1) : 0; +} + +_GL_STDC_BIT_FLOOR_INLINE unsigned long int +stdc_bit_floor_ul (unsigned long int n) +{ + return n ? 1ul << (stdc_bit_width_ul (n) - 1) : 0; +} + +_GL_STDC_BIT_FLOOR_INLINE unsigned long long int +stdc_bit_floor_ull (unsigned long long int n) +{ + return n ? 1ull << (stdc_bit_width_ull (n) - 1) : 0; +} + +# define stdc_bit_floor(n) \ + (_GL_STDBIT_TYPEOF_CAST \ + (n, \ + (sizeof (n) == 1 ? stdc_bit_floor_uc (n) \ + : sizeof (n) == sizeof (unsigned short int) ? stdc_bit_floor_us (n) \ + : sizeof (n) == sizeof 0u ? stdc_bit_floor_ui (n) \ + : sizeof (n) == sizeof 0ul ? stdc_bit_floor_ul (n) \ + : stdc_bit_floor_ull (n)))) + +#endif + + +/* ISO C 23 § 7.18.16 Bit Ceiling */ + +#if @GL_STDC_BIT_CEIL@ + +_GL_STDC_BIT_CEIL_INLINE unsigned char +stdc_bit_ceil_uc (unsigned char n) +{ + return n <= 1 ? 1 : 2u << (stdc_bit_width_uc (n - 1) - 1); +} + +_GL_STDC_BIT_CEIL_INLINE unsigned short int +stdc_bit_ceil_us (unsigned short int n) +{ + return n <= 1 ? 1 : 2u << (stdc_bit_width_us (n - 1) - 1); +} + +_GL_STDC_BIT_CEIL_INLINE unsigned int +stdc_bit_ceil_ui (unsigned int n) +{ + return n <= 1 ? 1 : 2u << (stdc_bit_width_ui (n - 1) - 1); +} + +_GL_STDC_BIT_CEIL_INLINE unsigned long int +stdc_bit_ceil_ul (unsigned long int n) +{ + return n <= 1 ? 1 : 2ul << (stdc_bit_width_ul (n - 1) - 1); +} + +_GL_STDC_BIT_CEIL_INLINE unsigned long long int +stdc_bit_ceil_ull (unsigned long long int n) +{ + return n <= 1 ? 1 : 2ull << (stdc_bit_width_ull (n - 1) - 1); +} + +# define stdc_bit_ceil(n) \ + (_GL_STDBIT_TYPEOF_CAST \ + (n, \ + (sizeof (n) == 1 ? stdc_bit_ceil_uc (n) \ + : sizeof (n) == sizeof (unsigned short int) ? stdc_bit_ceil_us (n) \ + : sizeof (n) == sizeof 0u ? stdc_bit_ceil_ui (n) \ + : sizeof (n) == sizeof 0ul ? stdc_bit_ceil_ul (n) \ + : stdc_bit_ceil_ull (n)))) + +#endif + + +#ifdef __cplusplus +} +#endif + +_GL_INLINE_HEADER_END + +#endif /* STDBIT_H */ diff --git a/lib/count-trailing-zeros.c b/lib/stdc_bit_width.c similarity index 78% rename from lib/count-trailing-zeros.c rename to lib/stdc_bit_width.c index e13f77788da..a0dc8de3b5f 100644 --- a/lib/count-trailing-zeros.c +++ b/lib/stdc_bit_width.c @@ -1,6 +1,5 @@ -/* Count the number of trailing 0 bits in a word. - - Copyright 2013-2024 Free Software Foundation, Inc. +/* stdc_bit_width_* functions. + Copyright (C) 2024 Free Software Foundation, Inc. This file is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as @@ -17,5 +16,5 @@ #include -#define COUNT_TRAILING_ZEROS_INLINE _GL_EXTERN_INLINE -#include "count-trailing-zeros.h" +#define _GL_STDC_BIT_WIDTH_INLINE _GL_EXTERN_INLINE +#include diff --git a/lib/count-one-bits.c b/lib/stdc_count_ones.c similarity index 78% rename from lib/count-one-bits.c rename to lib/stdc_count_ones.c index 54b87088028..7421178adf0 100644 --- a/lib/count-one-bits.c +++ b/lib/stdc_count_ones.c @@ -1,6 +1,5 @@ -/* Count the number of 1-bits in a word. - - Copyright (C) 2012-2024 Free Software Foundation, Inc. +/* stdc_count_ones_* functions. + Copyright (C) 2024 Free Software Foundation, Inc. This file is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as @@ -17,9 +16,9 @@ #include -#define COUNT_ONE_BITS_INLINE _GL_EXTERN_INLINE -#include "count-one-bits.h" +#define _GL_STDC_COUNT_ONES_INLINE _GL_EXTERN_INLINE +#include #if 1500 <= _MSC_VER && (defined _M_IX86 || defined _M_X64) -int popcount_support = -1; +signed char __gl_stdbit_popcount_support; #endif diff --git a/lib/count-leading-zeros.c b/lib/stdc_leading_zeros.c similarity index 77% rename from lib/count-leading-zeros.c rename to lib/stdc_leading_zeros.c index 2bbfd674849..45695e51aa8 100644 --- a/lib/count-leading-zeros.c +++ b/lib/stdc_leading_zeros.c @@ -1,6 +1,5 @@ -/* Count the number of leading 0 bits in a word. - - Copyright (C) 2012-2024 Free Software Foundation, Inc. +/* stdc_leading_zeros_* functions. + Copyright (C) 2024 Free Software Foundation, Inc. This file is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as @@ -17,5 +16,5 @@ #include -#define COUNT_LEADING_ZEROS_INLINE _GL_EXTERN_INLINE -#include "count-leading-zeros.h" +#define _GL_STDC_LEADING_ZEROS_INLINE _GL_EXTERN_INLINE +#include diff --git a/lib/stdc_trailing_zeros.c b/lib/stdc_trailing_zeros.c new file mode 100644 index 00000000000..f4bc43ac6ba --- /dev/null +++ b/lib/stdc_trailing_zeros.c @@ -0,0 +1,20 @@ +/* stdc_trailing_zeros_* functions. + Copyright (C) 2024 Free Software Foundation, Inc. + + This file is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . */ + +#include + +#define _GL_STDC_TRAILING_ZEROS_INLINE _GL_EXTERN_INLINE +#include diff --git a/m4/gnulib-comp.m4 b/m4/gnulib-comp.m4 index 61040987b57..4dd1e68d15c 100644 --- a/m4/gnulib-comp.m4 +++ b/m4/gnulib-comp.m4 @@ -63,9 +63,6 @@ AC_DEFUN([gl_EARLY], # Code from module cloexec: # Code from module close-stream: # Code from module copy-file-range: - # Code from module count-leading-zeros: - # Code from module count-one-bits: - # Code from module count-trailing-zeros: # Code from module crypto/md5: # Code from module crypto/md5-buffer: # Code from module crypto/sha1-buffer: @@ -174,7 +171,12 @@ AC_DEFUN([gl_EARLY], # Code from module ssize_t: # Code from module stat-time: # Code from module std-gnu11: + # Code from module stdbit-h: # Code from module stdbool: + # Code from module stdc_bit_width: + # Code from module stdc_count_ones: + # Code from module stdc_leading_zeros: + # Code from module stdc_trailing_zeros: # Code from module stdckdint: # Code from module stddef: # Code from module stdint: @@ -514,7 +516,18 @@ AC_DEFUN([gl_INIT], gt_TYPE_SSIZE_T gl_STAT_TIME gl_STAT_BIRTHTIME + gl_STDBIT_H + gl_CONDITIONAL_HEADER([stdbit.h]) + AC_PROG_MKDIR_P gl_C_BOOL + AC_REQUIRE([gl_STDBIT_H]) + GL_STDC_BIT_WIDTH=1 + AC_REQUIRE([gl_STDBIT_H]) + GL_STDC_COUNT_ONES=1 + AC_REQUIRE([gl_STDBIT_H]) + GL_STDC_LEADING_ZEROS=1 + AC_REQUIRE([gl_STDBIT_H]) + GL_STDC_TRAILING_ZEROS=1 AC_CHECK_HEADERS_ONCE([stdckdint.h]) if test $ac_cv_header_stdckdint_h = yes; then GL_GENERATE_STDCKDINT_H=false @@ -673,6 +686,7 @@ AC_DEFUN([gl_INIT], gl_gnulib_enabled_6099e9737f757db36c47fa9d9f02e88c=false gl_gnulib_enabled_strtoll=false gl_gnulib_enabled_utimens=false + gl_gnulib_enabled_verify=false gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec=false func_gl_gnulib_m4code_260941c0e5dc67ec9e87d1fb321c300b () { @@ -953,6 +967,12 @@ AC_DEFUN([gl_INIT], gl_gnulib_enabled_utimens=true fi } + func_gl_gnulib_m4code_verify () + { + if $gl_gnulib_enabled_verify; then :; else + gl_gnulib_enabled_verify=true + fi + } func_gl_gnulib_m4code_682e609604ccaac6be382e4ee3a4eaec () { if $gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec; then :; else @@ -1016,6 +1036,9 @@ AC_DEFUN([gl_INIT], if case $host_os in mingw* | windows*) false;; *) test $HAVE_GETRANDOM = 0 || test $REPLACE_GETRANDOM = 1;; esac; then func_gl_gnulib_m4code_open fi + if test $REPLACE_MKTIME = 1; then + func_gl_gnulib_m4code_verify + fi if test $HAVE_READLINKAT = 0 || test $REPLACE_READLINKAT = 1; then func_gl_gnulib_m4code_260941c0e5dc67ec9e87d1fb321c300b fi @@ -1025,6 +1048,9 @@ AC_DEFUN([gl_INIT], if test $ac_use_included_regex = yes; then func_gl_gnulib_m4code_fd38c7e463b54744b77b98aeafb4fa7c fi + if test $ac_use_included_regex = yes; then + func_gl_gnulib_m4code_verify + fi if test $HAVE_DECL_STRTOIMAX = 0 || test $REPLACE_STRTOIMAX = 1; then func_gl_gnulib_m4code_strtoll fi @@ -1065,6 +1091,7 @@ AC_DEFUN([gl_INIT], AM_CONDITIONAL([gl_GNULIB_ENABLED_6099e9737f757db36c47fa9d9f02e88c], [$gl_gnulib_enabled_6099e9737f757db36c47fa9d9f02e88c]) AM_CONDITIONAL([gl_GNULIB_ENABLED_strtoll], [$gl_gnulib_enabled_strtoll]) AM_CONDITIONAL([gl_GNULIB_ENABLED_utimens], [$gl_gnulib_enabled_utimens]) + AM_CONDITIONAL([gl_GNULIB_ENABLED_verify], [$gl_gnulib_enabled_verify]) AM_CONDITIONAL([gl_GNULIB_ENABLED_682e609604ccaac6be382e4ee3a4eaec], [$gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec]) # End of code from modules m4_ifval(gl_LIBSOURCES_LIST, [ @@ -1276,12 +1303,6 @@ AC_DEFUN([gl_FILE_LIST], [ lib/close-stream.c lib/close-stream.h lib/copy-file-range.c - lib/count-leading-zeros.c - lib/count-leading-zeros.h - lib/count-one-bits.c - lib/count-one-bits.h - lib/count-trailing-zeros.c - lib/count-trailing-zeros.h lib/diffseq.h lib/dirent-private.h lib/dirent.in.h @@ -1414,6 +1435,12 @@ AC_DEFUN([gl_FILE_LIST], [ lib/signal.in.h lib/stat-time.c lib/stat-time.h + lib/stdbit.c + lib/stdbit.in.h + lib/stdc_bit_width.c + lib/stdc_count_ones.c + lib/stdc_leading_zeros.c + lib/stdc_trailing_zeros.c lib/stdckdint.in.h lib/stddef.in.h lib/stdint.in.h @@ -1567,6 +1594,7 @@ AC_DEFUN([gl_FILE_LIST], [ m4/stat-time.m4 m4/std-gnu11.m4 m4/stdalign.m4 + m4/stdbit_h.m4 m4/stddef_h.m4 m4/stdint.m4 m4/stdio_h.m4 diff --git a/m4/stdbit_h.m4 b/m4/stdbit_h.m4 new file mode 100644 index 00000000000..6af813f39dc --- /dev/null +++ b/m4/stdbit_h.m4 @@ -0,0 +1,37 @@ +# stdbit_h.m4 +# serial 2 +dnl Copyright 2024 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl A placeholder for , for platforms that have issues. + +AC_DEFUN_ONCE([gl_STDBIT_H], +[ + AC_REQUIRE([gl_BIGENDIAN]) + + AC_CHECK_HEADERS_ONCE([stdbit.h]) + if test $ac_cv_header_stdbit_h = yes; then + GL_GENERATE_STDBIT_H=false + else + GL_GENERATE_STDBIT_H=true + fi + + dnl We don't use gl_MODULE_INDICATOR_INIT_VARIABLE here, because stdbit.in.h + dnl does not use #include_next. + GL_STDC_LEADING_ZEROS=0; AC_SUBST([GL_STDC_LEADING_ZEROS]) + GL_STDC_LEADING_ONES=0; AC_SUBST([GL_STDC_LEADING_ONES]) + GL_STDC_TRAILING_ZEROS=0; AC_SUBST([GL_STDC_TRAILING_ZEROS]) + GL_STDC_TRAILING_ONES=0; AC_SUBST([GL_STDC_TRAILING_ONES]) + GL_STDC_FIRST_LEADING_ZERO=0; AC_SUBST([GL_STDC_FIRST_LEADING_ZERO]) + GL_STDC_FIRST_LEADING_ONE=0; AC_SUBST([GL_STDC_FIRST_LEADING_ONE]) + GL_STDC_FIRST_TRAILING_ZERO=0; AC_SUBST([GL_STDC_FIRST_TRAILING_ZERO]) + GL_STDC_FIRST_TRAILING_ONE=0; AC_SUBST([GL_STDC_FIRST_TRAILING_ONE]) + GL_STDC_COUNT_ZEROS=0; AC_SUBST([GL_STDC_COUNT_ZEROS]) + GL_STDC_COUNT_ONES=0; AC_SUBST([GL_STDC_COUNT_ONES]) + GL_STDC_HAS_SINGLE_BIT=0; AC_SUBST([GL_STDC_HAS_SINGLE_BIT]) + GL_STDC_BIT_WIDTH=0; AC_SUBST([GL_STDC_BIT_WIDTH]) + GL_STDC_BIT_FLOOR=0; AC_SUBST([GL_STDC_BIT_FLOOR]) + GL_STDC_BIT_CEIL=0; AC_SUBST([GL_STDC_BIT_CEIL]) +]) diff --git a/src/data.c b/src/data.c index ea611ad1abf..30d8eab7359 100644 --- a/src/data.c +++ b/src/data.c @@ -23,8 +23,6 @@ along with GNU Emacs. If not, see . */ #include #include -#include -#include #include #include "lisp.h" @@ -3500,12 +3498,8 @@ representation. */) } eassume (FIXNUMP (value)); - EMACS_INT v = XFIXNUM (value) < 0 ? -1 - XFIXNUM (value) : XFIXNUM (value); - return make_fixnum (EMACS_UINT_WIDTH <= UINT_WIDTH - ? count_one_bits (v) - : EMACS_UINT_WIDTH <= ULONG_WIDTH - ? count_one_bits_l (v) - : count_one_bits_ll (v)); + EMACS_UINT v = XFIXNUM (value) < 0 ? -1 - XFIXNUM (value) : XFIXNUM (value); + return make_fixnum (stdc_count_ones (v)); } DEFUN ("ash", Fash, Sash, 2, 2, 0, @@ -3662,36 +3656,6 @@ bool_vector_spare_mask (EMACS_INT nr_bits) return (((bits_word) 1) << (nr_bits % BITS_PER_BITS_WORD)) - 1; } -/* Shift VAL right by the width of an unsigned long long. - ULLONG_WIDTH must be less than BITS_PER_BITS_WORD. */ - -static bits_word -shift_right_ull (bits_word w) -{ - /* Pacify bogus GCC warning about shift count exceeding type width. */ - int shift = ULLONG_WIDTH - BITS_PER_BITS_WORD < 0 ? ULLONG_WIDTH : 0; - return w >> shift; -} - -/* Return the number of 1 bits in W. */ - -static int -count_one_bits_word (bits_word w) -{ - if (BITS_WORD_MAX <= UINT_MAX) - return count_one_bits (w); - else if (BITS_WORD_MAX <= ULONG_MAX) - return count_one_bits_l (w); - else - { - int i = 0, count = 0; - while (count += count_one_bits_ll (w), - (i += ULLONG_WIDTH) < BITS_PER_BITS_WORD) - w = shift_right_ull (w); - return count; - } -} - enum bool_vector_op { bool_vector_exclusive_or, bool_vector_union, bool_vector_intersection, @@ -3798,55 +3762,6 @@ bool_vector_binop_driver (Lisp_Object a, return dest; } -/* PRECONDITION must be true. Return VALUE. This odd construction - works around a bogus GCC diagnostic "shift count >= width of type". */ - -static int -pre_value (bool precondition, int value) -{ - eassume (precondition); - return precondition ? value : 0; -} - -/* Compute the number of trailing zero bits in val. If val is zero, - return the number of bits in val. */ -static int -count_trailing_zero_bits (bits_word val) -{ - if (BITS_WORD_MAX == UINT_MAX) - return count_trailing_zeros (val); - if (BITS_WORD_MAX == ULONG_MAX) - return count_trailing_zeros_l (val); - if (BITS_WORD_MAX == ULLONG_MAX) - return count_trailing_zeros_ll (val); - - /* The rest of this code is for the unlikely platform where bits_word differs - in width from unsigned int, unsigned long, and unsigned long long. */ - val |= ~ BITS_WORD_MAX; - if (BITS_WORD_MAX <= UINT_MAX) - return count_trailing_zeros (val); - if (BITS_WORD_MAX <= ULONG_MAX) - return count_trailing_zeros_l (val); - else - { - int count; - for (count = 0; - count < BITS_PER_BITS_WORD - ULLONG_WIDTH; - count += ULLONG_WIDTH) - { - if (val & ULLONG_MAX) - return count + count_trailing_zeros_ll (val); - val = shift_right_ull (val); - } - - if (BITS_PER_BITS_WORD % ULLONG_WIDTH != 0 - && BITS_WORD_MAX == (bits_word) -1) - val |= (bits_word) 1 << pre_value (ULONG_MAX < BITS_WORD_MAX, - BITS_PER_BITS_WORD % ULLONG_WIDTH); - return count + count_trailing_zeros_ll (val); - } -} - DEFUN ("bool-vector-exclusive-or", Fbool_vector_exclusive_or, Sbool_vector_exclusive_or, 2, 3, 0, doc: /* Return A ^ B, bitwise exclusive or. @@ -3961,7 +3876,7 @@ value from A's length. */) adata = bool_vector_data (a); for (i = 0; i < nwords; i++) - count += count_one_bits_word (adata[i]); + count += stdc_count_ones (adata[i]); return make_fixnum (count); } @@ -4009,7 +3924,7 @@ A is a bool vector, B is t or nil, and I is an index into A. */) /* Do not count the pad bits. */ mword |= (bits_word) 1 << (BITS_PER_BITS_WORD - offset); - count = count_trailing_zero_bits (mword); + count = stdc_trailing_zeros (mword); pos++; if (count + offset < BITS_PER_BITS_WORD) return make_fixnum (count); @@ -4029,7 +3944,7 @@ A is a bool vector, B is t or nil, and I is an index into A. */) in the current mword. */ mword = bits_word_to_host_endian (adata[pos]); mword ^= twiddle; - count += count_trailing_zero_bits (mword); + count += stdc_trailing_zeros (mword); } else if (nr_bits % BITS_PER_BITS_WORD != 0) { diff --git a/src/lisp.h b/src/lisp.h index 8ee37f5298a..d61a4d5c982 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -23,6 +23,7 @@ along with GNU Emacs. If not, see . */ #include #include #include +#include #include #include #include @@ -37,7 +38,6 @@ along with GNU Emacs. If not, see . */ #include #include -#include #include #include @@ -4148,11 +4148,12 @@ integer_to_uintmax (Lisp_Object num, uintmax_t *n) } } -/* Return floor (log2 (N)) as an int, where 0 < N <= ULLONG_MAX. */ +/* Return floor (log2 (N)) as an int. If N is zero, return -1. */ INLINE int elogb (unsigned long long int n) { - return ULLONG_WIDTH - 1 - count_leading_zeros_ll (n); + int width = stdc_bit_width (n); + return width - 1; } /* A modification count. These are wide enough, and incremented