diff mbox series

[FFmpeg-devel,02/23] compat: add a fallback implementation of C23 stdbit.h

Message ID 20240914111036.17164-3-anton@khirnov.net
State New
Headers show
Series [FFmpeg-devel,01/23] compat: drop gcc, suncc, and pthreads stdatomic emulation | expand

Checks

Context Check Description
yinshiyou/make_loongarch64 success Make finished
yinshiyou/make_fate_loongarch64 success Make fate finished
andriy/make_x86 success Make finished
andriy/make_fate_x86 success Make fate finished

Commit Message

Anton Khirnov Sept. 14, 2024, 10:45 a.m. UTC
From: Rémi Denis-Courmont <remi@remlab.net>

Header contents taken from VLC commit 7a970a33329c9836d169727ddbaf49a33240d587.

Signed-off-by: Anton Khirnov <anton@khirnov.net>
---
 compat/stdbit/stdbit.h | 594 +++++++++++++++++++++++++++++++++++++++++
 configure              |   4 +
 tests/ref/fate/source  |   1 +
 3 files changed, 599 insertions(+)
 create mode 100644 compat/stdbit/stdbit.h

Comments

James Almer Sept. 14, 2024, 1:10 p.m. UTC | #1
On 9/14/2024 7:45 AM, Anton Khirnov wrote:
> From: Rémi Denis-Courmont <remi@remlab.net>
> 
> Header contents taken from VLC commit 7a970a33329c9836d169727ddbaf49a33240d587.
> 
> Signed-off-by: Anton Khirnov <anton@khirnov.net>
> ---
>   compat/stdbit/stdbit.h | 594 +++++++++++++++++++++++++++++++++++++++++
>   configure              |   4 +
>   tests/ref/fate/source  |   1 +
>   3 files changed, 599 insertions(+)
>   create mode 100644 compat/stdbit/stdbit.h
> 
> diff --git a/compat/stdbit/stdbit.h b/compat/stdbit/stdbit.h
> new file mode 100644
> index 0000000000..b6a2c7e945
> --- /dev/null
> +++ b/compat/stdbit/stdbit.h
> @@ -0,0 +1,594 @@
> +/*
> + * Copyright (C) 2023 Rémi Denis-Courmont
> + *
> + * This program 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 program 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, write to the Free Software Foundation,
> + * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
> + */
> +
> +#ifndef __STDC_VERSION_STDBIT_H__
> +#define __STDC_VERSION_STDBIT_H__ 202311L
> +
> +#include <stdbool.h>
> +#include <limits.h> /* CHAR_BIT */
> +
> +#define __STDC_ENDIAN_LITTLE__ 1234
> +#define __STDC_ENDIAN_BIG__    4321
> +
> +#ifdef __BYTE_ORDER__

This doesn't seem to be defined in msvc. I looked at VLC and their CI 
seems to use gcc only for Windows, which would explain why it's written 
as is.

It should be safe to just hardcode little endian for it (or Windows in 
general, even for aarch64).
diff mbox series

Patch

diff --git a/compat/stdbit/stdbit.h b/compat/stdbit/stdbit.h
new file mode 100644
index 0000000000..b6a2c7e945
--- /dev/null
+++ b/compat/stdbit/stdbit.h
@@ -0,0 +1,594 @@ 
+/*
+ * Copyright (C) 2023 Rémi Denis-Courmont
+ *
+ * This program 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 program 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, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ */
+
+#ifndef __STDC_VERSION_STDBIT_H__
+#define __STDC_VERSION_STDBIT_H__ 202311L
+
+#include <stdbool.h>
+#include <limits.h> /* CHAR_BIT */
+
+#define __STDC_ENDIAN_LITTLE__ 1234
+#define __STDC_ENDIAN_BIG__    4321
+
+#ifdef __BYTE_ORDER__
+# if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
+#  define __STDC_ENDIAN_NATIVE__ __STDC_ENDIAN_LITTLE__
+# elif (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
+#  define __STDC_ENDIAN_NATIVE__ __STDC_ENDIAN_BIG__
+# else
+#  define __STDC_ENDIAN_NATIVE__ 3412
+# endif
+#else
+# error Not implemented.
+#endif
+
+#define __stdbit_generic_type_func(func, value) \
+    _Generic (value, \
+        unsigned long long: stdc_##func##_ull((unsigned long long)(value)), \
+        unsigned long:      stdc_##func##_ul((unsigned long)(value)), \
+        unsigned int:       stdc_##func##_ui((unsigned int)(value)), \
+        unsigned short:     stdc_##func##_us((unsigned short)(value)), \
+        unsigned char:      stdc_##func##_uc((unsigned char)(value)))
+
+#if defined (__GNUC__) || defined (__clang__)
+static inline unsigned int stdc_leading_zeros_ull(unsigned long long value)
+{
+    return value ? __builtin_clzll(value) : (CHAR_BIT * sizeof (value));
+}
+
+static inline unsigned int stdc_leading_zeros_ul(unsigned long value)
+{
+    return value ? __builtin_clzl(value) : (CHAR_BIT * sizeof (value));
+}
+
+static inline unsigned int stdc_leading_zeros_ui(unsigned int value)
+{
+    return value ? __builtin_clz(value) : (CHAR_BIT * sizeof (value));
+}
+
+static inline unsigned int stdc_leading_zeros_us(unsigned short value)
+{
+    return stdc_leading_zeros_ui(value)
+           - CHAR_BIT * (sizeof (int) - sizeof (value));
+}
+
+static inline unsigned int stdc_leading_zeros_uc(unsigned char value)
+{
+    return stdc_leading_zeros_ui(value) - (CHAR_BIT * (sizeof (int) - 1));
+}
+#else
+static inline unsigned int __stdc_leading_zeros(unsigned long long value,
+                                                unsigned int size)
+{
+    unsigned int zeros = size * CHAR_BIT;
+
+    while (value != 0) {
+        value >>= 1;
+        zeros--;
+    }
+
+    return zeros;
+}
+
+static inline unsigned int stdc_leading_zeros_ull(unsigned long long value)
+{
+    return __stdc_leading_zeros(value, sizeof (value));
+}
+
+static inline unsigned int stdc_leading_zeros_ul(unsigned long value)
+{
+    return __stdc_leading_zeros(value, sizeof (value));
+}
+
+static inline unsigned int stdc_leading_zeros_ui(unsigned int value)
+{
+    return __stdc_leading_zeros(value, sizeof (value));
+}
+
+static inline unsigned int stdc_leading_zeros_us(unsigned short value)
+{
+    return __stdc_leading_zeros(value, sizeof (value));
+}
+
+static inline unsigned int stdc_leading_zeros_uc(unsigned char value)
+{
+    return __stdc_leading_zeros(value, sizeof (value));
+}
+#endif
+
+#define stdc_leading_zeros(value) \
+        __stdbit_generic_type_func(leading_zeros, value)
+
+static inline unsigned int stdc_leading_ones_ull(unsigned long long value)
+{
+    return stdc_leading_zeros_ull(~value);
+}
+
+static inline unsigned int stdc_leading_ones_ul(unsigned long value)
+{
+    return stdc_leading_zeros_ul(~value);
+}
+
+static inline unsigned int stdc_leading_ones_ui(unsigned int value)
+{
+    return stdc_leading_zeros_ui(~value);
+}
+
+static inline unsigned int stdc_leading_ones_us(unsigned short value)
+{
+    return stdc_leading_zeros_us(~value);
+}
+
+static inline unsigned int stdc_leading_ones_uc(unsigned char value)
+{
+    return stdc_leading_zeros_uc(~value);
+}
+
+#define stdc_leading_ones(value) \
+        __stdbit_generic_type_func(leading_ones, value)
+
+#if defined (__GNUC__) || defined (__clang__)
+static inline unsigned int stdc_trailing_zeros_ull(unsigned long long value)
+{
+    return value ? (unsigned int)__builtin_ctzll(value)
+                 : (CHAR_BIT * sizeof (value));
+}
+
+static inline unsigned int stdc_trailing_zeros_ul(unsigned long value)
+{
+    return value ? (unsigned int)__builtin_ctzl(value)
+                 : (CHAR_BIT * sizeof (value));
+}
+
+static inline unsigned int stdc_trailing_zeros_ui(unsigned int value)
+{
+    return value ? (unsigned int)__builtin_ctz(value)
+                 : (CHAR_BIT * sizeof (value));
+}
+
+static inline unsigned int stdc_trailing_zeros_us(unsigned short value)
+{
+    return value ? (unsigned int)__builtin_ctz(value)
+                 : (CHAR_BIT * sizeof (value));
+}
+
+static inline unsigned int stdc_trailing_zeros_uc(unsigned char value)
+{
+    return value ? (unsigned int)__builtin_ctz(value)
+                 : (CHAR_BIT * sizeof (value));
+}
+#else
+static inline unsigned int __stdc_trailing_zeros(unsigned long long value,
+                                                 unsigned int size)
+{
+    unsigned int zeros = size * CHAR_BIT;
+
+    while (value != 0) {
+        value <<= 1;
+        zeros--;
+    }
+
+    return zeros;
+}
+
+static inline unsigned int stdc_trailing_zeros_ull(unsigned long long value)
+{
+    return __stdc_trailing_zeros(value, sizeof (value));
+}
+
+static inline unsigned int stdc_trailing_zeros_ul(unsigned long value)
+{
+    return __stdc_trailing_zeros(value, sizeof (value));
+}
+
+static inline unsigned int stdc_trailing_zeros_ui(unsigned int value)
+{
+    return __stdc_trailing_zeros(value, sizeof (value));
+}
+
+static inline unsigned int stdc_trailing_zeros_us(unsigned short value)
+{
+    return __stdc_trailing_zeros(value, sizeof (value));
+}
+
+static inline unsigned int stdc_trailing_zeros_uc(unsigned char value)
+{
+    return __stdc_trailing_zeros(value, sizeof (value));
+}
+#endif
+
+#define stdc_trailing_zeros(value) \
+        __stdbit_generic_type_func(trailing_zeros, value)
+
+static inline unsigned int stdc_trailing_ones_ull(unsigned long long value)
+{
+    return stdc_trailing_zeros_ull(~value);
+}
+
+static inline unsigned int stdc_trailing_ones_ul(unsigned long value)
+{
+    return stdc_trailing_zeros_ul(~value);
+}
+
+static inline unsigned int stdc_trailing_ones_ui(unsigned int value)
+{
+    return stdc_trailing_zeros_ui(~value);
+}
+
+static inline unsigned int stdc_trailing_ones_us(unsigned short value)
+{
+    return stdc_trailing_zeros_us(~value);
+}
+
+static inline unsigned int stdc_trailing_ones_uc(unsigned char value)
+{
+    return stdc_trailing_zeros_uc(~value);
+}
+
+#define stdc_trailing_ones(value) \
+        __stdbit_generic_type_func(trailing_ones, value)
+
+static inline unsigned int stdc_first_leading_one_ull(unsigned long long value)
+{
+    return value ? (stdc_leading_zeros_ull(value) + 1) : 0;
+}
+
+static inline unsigned int stdc_first_leading_one_ul(unsigned long value)
+{
+    return value ? (stdc_leading_zeros_ul(value) + 1) : 0;
+}
+
+static inline unsigned int stdc_first_leading_one_ui(unsigned int value)
+{
+    return value ? (stdc_leading_zeros_ui(value) + 1) : 0;
+}
+
+static inline unsigned int stdc_first_leading_one_us(unsigned short value)
+{
+    return value ? (stdc_leading_zeros_us(value) + 1) : 0;
+}
+
+static inline unsigned int stdc_first_leading_one_uc(unsigned char value)
+{
+    return value ? (stdc_leading_zeros_uc(value) + 1) : 0;
+}
+
+#define stdc_first_leading_one(value) \
+        __stdbit_generic_type_func(first_leading_one, value)
+
+static inline unsigned int stdc_first_leading_zero_ull(unsigned long long value)
+{
+    return stdc_leading_ones_ull(~value);
+}
+
+static inline unsigned int stdc_first_leading_zero_ul(unsigned long value)
+{
+    return stdc_leading_ones_ul(~value);
+}
+
+static inline unsigned int stdc_first_leading_zero_ui(unsigned int value)
+{
+    return stdc_leading_ones_ui(~value);
+}
+
+static inline unsigned int stdc_first_leading_zero_us(unsigned short value)
+{
+    return stdc_leading_ones_us(~value);
+}
+
+static inline unsigned int stdc_first_leading_zero_uc(unsigned char value)
+{
+    return stdc_leading_ones_uc(~value);
+}
+
+#define stdc_first_leading_zero(value) \
+        __stdbit_generic_type_func(first_leading_zero, value)
+
+#if defined (__GNUC__) || defined (__clang__)
+static inline unsigned int stdc_first_trailing_one_ull(unsigned long long value)
+{
+    return __builtin_ffsll(value);
+}
+
+static inline unsigned int stdc_first_trailing_one_ul(unsigned long value)
+{
+    return __builtin_ffsl(value);
+}
+
+static inline unsigned int stdc_first_trailing_one_ui(unsigned int value)
+{
+    return __builtin_ffs(value);
+}
+
+static inline unsigned int stdc_first_trailing_one_us(unsigned short value)
+{
+    return __builtin_ffs(value);
+}
+
+static inline unsigned int stdc_first_trailing_one_uc(unsigned char value)
+{
+    return __builtin_ffs(value);
+}
+#else
+static inline unsigned int stdc_first_trailing_one_ull(unsigned long long value)
+{
+    return value ? (1 + stdc_trailing_zeros_ull(value)) : 0;
+}
+
+static inline unsigned int stdc_first_trailing_one_ul(unsigned long value)
+{
+    return value ? (1 + stdc_trailing_zeros_ul(value)) : 0;
+}
+
+static inline unsigned int stdc_first_trailing_one_ui(unsigned int value)
+{
+    return value ? (1 + stdc_trailing_zeros_ui(value)) : 0;
+}
+
+static inline unsigned int stdc_first_trailing_one_us(unsigned short value)
+{
+    return value ? (1 + stdc_trailing_zeros_us(value)) : 0;
+}
+
+static inline unsigned int stdc_first_trailing_one_uc(unsigned char value)
+{
+    return value ? (1 + stdc_trailing_zeros_uc(value)) : 0;
+}
+#endif
+
+#define stdc_first_trailing_one(value) \
+        __stdbit_generic_type_func(first_trailing_one, value)
+
+static inline unsigned int stdc_first_trailing_zero_ull(unsigned long long value)
+{
+    return stdc_first_trailing_one_ull(~value);
+}
+
+static inline unsigned int stdc_first_trailing_zero_ul(unsigned long value)
+{
+    return stdc_first_trailing_one_ul(~value);
+}
+
+static inline unsigned int stdc_first_trailing_zero_ui(unsigned int value)
+{
+    return stdc_first_trailing_one_ui(~value);
+}
+
+static inline unsigned int stdc_first_trailing_zero_us(unsigned short value)
+{
+    return stdc_first_trailing_one_us(~value);
+}
+
+static inline unsigned int stdc_first_trailing_zero_uc(unsigned char value)
+{
+    return stdc_first_trailing_one_uc(~value);
+}
+
+#define stdc_first_trailing_zero(value) \
+        __stdbit_generic_type_func(first_trailing_zero, value)
+
+#if defined (__GNUC__) || defined (__clang__)
+static inline unsigned int stdc_count_ones_ull(unsigned long long value)
+{
+    return __builtin_popcountll(value);
+}
+
+static inline unsigned int stdc_count_ones_ul(unsigned long value)
+{
+    return __builtin_popcountl(value);
+}
+
+static inline unsigned int stdc_count_ones_ui(unsigned int value)
+{
+    return __builtin_popcount(value);
+}
+
+static inline unsigned int stdc_count_ones_us(unsigned short value)
+{
+    return __builtin_popcount(value);
+}
+
+static inline unsigned int stdc_count_ones_uc(unsigned char value)
+{
+    return __builtin_popcount(value);
+}
+#else
+static inline unsigned int __stdc_count_ones(unsigned long long value,
+                                             unsigned int size)
+{
+    unsigned int ones = 0;
+
+    for (unsigned int c = 0; c < (size * CHAR_BIT); c++) {
+         ones += value & 1;
+         value >>= 1;
+    }
+
+    return ones;
+}
+
+static inline unsigned int stdc_count_ones_ull(unsigned long long value)
+{
+    return __stdc_count_ones(value, sizeof (value));
+}
+
+static inline unsigned int stdc_count_ones_ul(unsigned long value)
+{
+    return __stdc_count_ones(value, sizeof (value));
+}
+
+static inline unsigned int stdc_count_ones_ui(unsigned int value)
+{
+    return __stdc_count_ones(value, sizeof (value));
+}
+
+static inline unsigned int stdc_count_ones_us(unsigned short value)
+{
+    return __stdc_count_ones(value, sizeof (value));
+}
+
+static inline unsigned int stdc_count_ones_uc(unsigned char value)
+{
+    return __stdc_count_ones(value, sizeof (value));
+}
+#endif
+
+#define stdc_count_ones(value) \
+        __stdbit_generic_type_func(count_ones, value)
+
+static inline unsigned int stdc_count_zeros_ull(unsigned long long value)
+{
+    return stdc_count_ones_ull(~value);
+}
+
+static inline unsigned int stdc_count_zeros_ul(unsigned long value)
+{
+    return stdc_count_ones_ul(~value);
+}
+
+static inline unsigned int stdc_count_zeros_ui(unsigned int value)
+{
+    return stdc_count_ones_ui(~value);
+}
+
+static inline unsigned int stdc_count_zeros_us(unsigned short value)
+{
+    return stdc_count_ones_us(~value);
+}
+
+static inline unsigned int stdc_count_zeros_uc(unsigned char value)
+{
+    return stdc_count_ones_uc(~value);
+}
+
+#define stdc_count_zeros(value) \
+        __stdbit_generic_type_func(count_zeros, value)
+
+static inline bool stdc_has_single_bit_ull(unsigned long long value)
+{
+    return value && (value & (value - 1)) == 0;
+}
+
+static inline bool stdc_has_single_bit_ul(unsigned long value)
+{
+    return value && (value & (value - 1)) == 0;
+}
+
+static inline bool stdc_has_single_bit_ui(unsigned int value)
+{
+    return value && (value & (value - 1)) == 0;
+}
+
+static inline bool stdc_has_single_bit_us(unsigned short value)
+{
+    return value && (value & (value - 1)) == 0;
+}
+
+static inline bool stdc_has_single_bit_uc(unsigned char value)
+{
+    return value && (value & (value - 1)) == 0;
+}
+
+#define stdc_has_single_bit(value) \
+        __stdbit_generic_type_func(has_single_bit, value)
+
+static inline unsigned int stdc_bit_width_ull(unsigned long long value)
+{
+    return (CHAR_BIT * sizeof (value)) - stdc_leading_zeros_ull(value);
+}
+
+static inline unsigned int stdc_bit_width_ul(unsigned long value)
+{
+    return (CHAR_BIT * sizeof (value)) - stdc_leading_zeros_ul(value);
+}
+
+static inline unsigned int stdc_bit_width_ui(unsigned int value)
+{
+    return (CHAR_BIT * sizeof (value)) - stdc_leading_zeros_ui(value);
+}
+
+static inline unsigned int stdc_bit_width_us(unsigned short value)
+{
+    return (CHAR_BIT * sizeof (value)) - stdc_leading_zeros_us(value);
+}
+
+static inline unsigned int stdc_bit_width_uc(unsigned char value)
+{
+    return (CHAR_BIT * sizeof (value)) - stdc_leading_zeros_uc(value);
+}
+
+#define stdc_bit_width(value) \
+        __stdbit_generic_type_func(bit_width, value)
+
+static inline unsigned long long stdc_bit_floor_ull(unsigned long long value)
+{
+    return value ? (1ULL << (stdc_bit_width_ull(value) - 1)) : 0ULL;
+}
+
+static inline unsigned long stdc_bit_floor_ul(unsigned long value)
+{
+    return value ? (1UL << (stdc_bit_width_ul(value) - 1)) : 0UL;
+}
+
+static inline unsigned int stdc_bit_floor_ui(unsigned int value)
+{
+    return value ? (1U << (stdc_bit_width_ui(value) - 1)) : 0U;
+}
+
+static inline unsigned short stdc_bit_floor_us(unsigned short value)
+{
+    return value ? (1U << (stdc_bit_width_us(value) - 1)) : 0U;
+}
+
+static inline unsigned int stdc_bit_floor_uc(unsigned char value)
+{
+    return value ? (1U << (stdc_bit_width_uc(value) - 1)) : 0U;
+}
+
+#define stdc_bit_floor(value) \
+        __stdbit_generic_type_func(bit_floor, value)
+
+/* NOTE: Bit ceiling undefines overflow. */
+static inline unsigned long long stdc_bit_ceil_ull(unsigned long long value)
+{
+    return 1ULL << (value ? stdc_bit_width_ull(value - 1) : 0);
+}
+
+static inline unsigned long stdc_bit_ceil_ul(unsigned long value)
+{
+    return 1UL << (value ? stdc_bit_width_ul(value - 1) : 0);
+}
+
+static inline unsigned int stdc_bit_ceil_ui(unsigned int value)
+{
+    return 1U << (value ? stdc_bit_width_ui(value - 1) : 0);
+}
+
+static inline unsigned short stdc_bit_ceil_us(unsigned short value)
+{
+    return 1U << (value ? stdc_bit_width_us(value - 1) : 0);
+}
+
+static inline unsigned int stdc_bit_ceil_uc(unsigned char value)
+{
+    return 1U << (value ? stdc_bit_width_uc(value - 1) : 0);
+}
+
+#define stdc_bit_ceil(value) \
+        __stdbit_generic_type_func(bit_ceil, value)
+
+#endif /* __STDC_VERSION_STDBIT_H__ */
diff --git a/configure b/configure
index 337172a6c6..83c0d02f8c 100755
--- a/configure
+++ b/configure
@@ -7766,6 +7766,10 @@  if disabled stdatomic; then
     fi
 fi
 
+check_builtin stdbit "stdbit.h assert.h" \
+    'static_assert(__STDC_VERSION_STDBIT_H__ >= 202311L, "Compiler lacks stdbit.h")' || \
+    add_cppflags '-I\$(SRC_PATH)/compat/stdbit'
+
 # Check if requested libraries were found.
 for lib in $AUTODETECT_LIBS; do
     requested $lib && ! enabled $lib && die "ERROR: $lib requested but not found";
diff --git a/tests/ref/fate/source b/tests/ref/fate/source
index 1703b36c02..78d3a2e0fa 100644
--- a/tests/ref/fate/source
+++ b/tests/ref/fate/source
@@ -24,6 +24,7 @@  Headers without standard inclusion guards:
 compat/djgpp/math.h
 compat/float/float.h
 compat/float/limits.h
+compat/stdbit/stdbit.h
 libavcodec/bitstream_template.h
 tools/decode_simple.h
 Use of av_clip() where av_clip_uintp2() could be used: