#endif
#include <isc/atomic.h>
+#include <isc/bit.h>
#include <isc/buffer.h>
#include <isc/log.h>
#include <isc/magic.h>
static dns_qpcell_t
next_capacity(uint32_t prev_capacity, uint32_t size) {
/*
- * Unfortunately builtin_clz is undefined for 0. We work around this
- * issue by flooring the request size at 2.
+ * Request size was floored at 2 because builtin_clz used to be 0.
+ * We keep this behavior because ISC_LEADING_ZEROS(0) = 32.
*/
- size = ISC_MAX3(size, prev_capacity, 2u);
- uint32_t log2 = 32u - __builtin_clz(size - 1u);
+ size = ISC_MAX3(size, prev_capacity, 2U);
+ uint32_t log2 = 32U - ISC_LEADING_ZEROS(size - 1U);
return 1U << ISC_CLAMP(log2, QP_CHUNK_LOG_MIN, QP_CHUNK_LOG_MAX);
}
#pragma once
+#include <isc/bit.h>
#include <isc/refcount.h>
#include <dns/qp.h>
branch_count_bitmap_before(dns_qpnode_t *n, dns_qpshift_t bit) {
uint64_t mask = (1ULL << bit) - 1 - TAG_MASK;
uint64_t bitmap = branch_index(n) & mask;
- return (dns_qpweight_t)__builtin_popcountll(bitmap);
+ return (dns_qpweight_t)ISC_POPCOUNT(bitmap);
}
/*
#include <stdlib.h>
#include <isc/async.h>
+#include <isc/bit.h>
#include <isc/buffer.h>
#include <isc/log.h>
#include <isc/loop.h>
(void)dns_name_concatenate(&tmp_name, dns_rootname, trig_name);
}
-#ifndef HAVE_BUILTIN_CLZ
-/**
- * \brief Count Leading Zeros: Find the location of the left-most set
- * bit.
- */
-static unsigned int
-clz(dns_rpz_cidr_word_t w) {
- unsigned int bit;
-
- bit = DNS_RPZ_CIDR_WORD_BITS - 1;
-
- if ((w & 0xffff0000) != 0) {
- w >>= 16;
- bit -= 16;
- }
-
- if ((w & 0xff00) != 0) {
- w >>= 8;
- bit -= 8;
- }
-
- if ((w & 0xf0) != 0) {
- w >>= 4;
- bit -= 4;
- }
-
- if ((w & 0xc) != 0) {
- w >>= 2;
- bit -= 2;
- }
-
- if ((w & 2) != 0) {
- --bit;
- }
-
- return bit;
-}
-#endif /* ifndef HAVE_BUILTIN_CLZ */
-
/*
* Find the first differing bit in two keys (IP addresses).
*/
for (i = 0; bit < maxbit; i++, bit += DNS_RPZ_CIDR_WORD_BITS) {
delta = key1->w[i] ^ key2->w[i];
if (delta != 0) {
-#ifdef HAVE_BUILTIN_CLZ
- bit += __builtin_clz(delta);
-#else /* ifdef HAVE_BUILTIN_CLZ */
- bit += clz(delta);
-#endif /* ifdef HAVE_BUILTIN_CLZ */
+ bit += ISC_LEADING_ZEROS(delta);
break;
}
}
#include <string.h>
#include <isc/atomic.h>
+#include <isc/bit.h>
#include <isc/histo.h>
#include <isc/magic.h>
#include <isc/mem.h>
value_to_key(const isc_histo_t *hg, uint64_t value) {
/* ensure that denormal numbers are all in chunk zero */
uint64_t chunked = value | CHUNKSIZE(hg);
- int clz = __builtin_clzll((unsigned long long)(chunked));
+ int clz = ISC_LEADING_ZEROS(chunked);
/* actually 1 less than the exponent except for denormals */
uint exponent = 63 - hg->sigbits - clz;
/* mantissa has leading bit set except for denormals */
--- /dev/null
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#pragma once
+
+#include <limits.h>
+#include <stdint.h>
+
+#include <isc/attributes.h>
+#include <isc/util.h>
+
+#ifndef __has_header
+#define __has_header(x) 0
+#endif
+
+#if __has_header(<stdbit.h>)
+
+#include <stdbit.h>
+
+#define ISC_POPCOUNT(x) stdc_count_zeros(x)
+#define ISC_LEADING_ZEROS(x) stdc_leading_zeros(x)
+#define ISC_TRAILING_ZEROS(x) stdc_trailing_zeros(x)
+#define ISC_LEADING_ONES(x) stdc_leading_ones(x)
+#define ISC_TRAILING_ONES(x) stdc_trailing_ones(x)
+
+#else /* __has_header(<stdbit.h>) */
+
+#ifdef HAVE_BUILTIN_POPCOUNTG
+#define ISC_POPCOUNT(x) __builtin_popcountg(x)
+#else /* HAVE_BUILTIN_POPCOUNTG */
+#define ISC_POPCOUNT(x) \
+ _Generic((x), \
+ unsigned int: __builtin_popcount, \
+ unsigned long: __builtin_popcountl, \
+ unsigned long long: __builtin_popcountll)(x)
+#endif /* HAVE_BUILTIN_POPCOUNTG */
+
+#ifdef HAVE_BUILTIN_CLZG
+#define ISC_LEADING_ZEROS(x) __builtin_clzg(x, (int)(sizeof(x) * 8))
+#else /* HAVE_BUILTIN_CLZG */
+#define ISC_LEADING_ZEROS(x) \
+ ((x) == 0) ? (sizeof(x) * 8) \
+ : _Generic((x), \
+ unsigned int: __builtin_clz, \
+ unsigned long: __builtin_clzl, \
+ unsigned long long: __builtin_clzll)(x)
+#endif /* HAVE_BUILTIN_CLZG */
+
+#ifdef HAVE_BUILTIN_CTZG
+#define ISC_TRAILING_ZEROS(x) __builtin_ctzg(x, (int)sizeof(x) * 8)
+#else /* HAVE_BUILTIN_CTZG */
+#define ISC_TRAILING_ZEROS(x) \
+ ((x) == 0) ? (sizeof(x) * 8) \
+ : _Generic((x), \
+ unsigned int: __builtin_ctz, \
+ unsigned long: __builtin_ctzl, \
+ unsigned long long: __builtin_ctzll)(x)
+#endif /* HAVE_BUILTIN_CTZG */
+
+#define ISC_LEADING_ONES(x) ISC_LEADING_ZEROS(~(x))
+#define ISC_TRAILING_ONES(x) ISC_TRAILING_ZEROS(~(x))
+
+#endif /* __has_header(<stdbit.h>) */
+
+#if SIZE_MAX == UINT64_MAX
+#define isc_rotate_leftsize(x, n) isc_rotate_left64(x, n)
+#define isc_rotate_rightsize(x, n) isc_rotate_right64(x, n)
+#elif SIZE_MAX == UINT32_MAX
+#define isc_rotate_leftsize(x, n) isc_rotate_left32(x, n)
+#define isc_rotate_rightsize(x, n) isc_rotate_right32(x, n)
+#else
+#error "size_t must be either 32 or 64-bits"
+#endif
+
+static inline uint8_t __attribute__((always_inline))
+isc_rotate_left8(const uint8_t x, uint32_t n) {
+ return (x << n) | (x >> (8 - n));
+}
+
+static inline uint16_t __attribute__((always_inline))
+isc_rotate_left16(const uint16_t x, uint32_t n) {
+ return (x << n) | (x >> (16 - n));
+}
+
+static inline uint32_t __attribute__((always_inline))
+isc_rotate_left32(const uint32_t x, uint32_t n) {
+ return (x << n) | (x >> (32 - n));
+}
+
+static inline uint64_t __attribute__((always_inline))
+isc_rotate_left64(const uint64_t x, uint32_t n) {
+ return (x << n) | (x >> (64 - n));
+}
+
+static inline uint8_t __attribute__((always_inline))
+isc_rotate_right8(const uint8_t x, uint32_t n) {
+ return (x >> n) | (x << (8 - n));
+}
+
+static inline uint16_t __attribute__((always_inline))
+isc_rotate_right16(const uint16_t x, uint32_t n) {
+ return (x >> n) | (x << (16 - n));
+}
+
+static inline uint32_t __attribute__((always_inline))
+isc_rotate_right32(const uint32_t x, uint32_t n) {
+ return (x >> n) | (x << (32 - n));
+}
+
+static inline uint64_t __attribute__((always_inline))
+isc_rotate_right64(const uint64_t x, uint32_t n) {
+ return (x >> n) | (x << (64 - n));
+}
#include <stdint.h>
#include <string.h>
+#include <isc/bit.h>
+
/* The constant K from Rust's fxhash */
#define K 0x9e3779b97f4a7c15ull
-static inline size_t
-rotate_left(size_t x, unsigned int n) {
- return (x << n) | (x >> (sizeof(size_t) * 8 - n));
-}
-
static inline size_t
fx_add_to_hash(size_t hash, size_t i) {
- return rotate_left(hash, 5) ^ i * K;
+ return isc_rotate_leftsize(hash, 5) ^ i * K;
}
/*
#pragma once
#include <isc/ascii.h>
+#include <isc/bit.h>
#include <isc/endian.h>
#include <isc/types.h>
#include <isc/util.h>
#define cROUNDS 2
#define dROUNDS 4
-#define ROTATE64(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b))))
-
-#define HALF_ROUND64(a, b, c, d, s, t) \
- a += b; \
- c += d; \
- b = ROTATE64(b, s) ^ a; \
- d = ROTATE64(d, t) ^ c; \
- a = ROTATE64(a, 32);
+#define HALF_ROUND64(a, b, c, d, s, t) \
+ a += b; \
+ c += d; \
+ b = isc_rotate_left64(b, s) ^ a; \
+ d = isc_rotate_left64(d, t) ^ c; \
+ a = isc_rotate_left64(a, 32);
#define FULL_ROUND64(v0, v1, v2, v3) \
HALF_ROUND64(v0, v1, v2, v3, 13, 16); \
#define SIPROUND FULL_ROUND64
-#define ROTATE32(x, b) (uint32_t)(((x) << (b)) | ((x) >> (32 - (b))))
-
-#define HALF_ROUND32(a, b, c, d, s, t) \
- a += b; \
- c += d; \
- b = ROTATE32(b, s) ^ a; \
- d = ROTATE32(d, t) ^ c; \
- a = ROTATE32(a, 16);
+#define HALF_ROUND32(a, b, c, d, s, t) \
+ a += b; \
+ c += d; \
+ b = isc_rotate_left32(b, s) ^ a; \
+ d = isc_rotate_left32(d, t) ^ c; \
+ a = isc_rotate_left32(a, 16);
#define FULL_ROUND32(v0, v1, v2, v3) \
HALF_ROUND32(v0, v1, v2, v3, 5, 8); \
foreach fn : [
'__builtin_add_overflow',
- '__builtin_clz',
'__builtin_mul_overflow',
'__builtin_sub_overflow',
'__builtin_unreachable',
endif
endforeach
+# meson_version (>=1.3.0) : required in cc.has_function
+if cc.has_function('__builtin_clzg')
+ config.set('HAVE_BUILTIN_CLZG', true)
+elif not (
+ cc.has_function('__builtin_clz')
+ and cc.has_function('__builtin_clzl')
+ and cc.has_function('__builtin_clzll')
+)
+ error(
+ '__builtin_clzg or __builtin_clz* functions are required, please fix your toolchain',
+ )
+endif
+
+# meson_version (>=1.3.0) : required in cc.has_function
+if cc.has_function('__builtin_ctzg')
+ config.set('HAVE_BUILTIN_CTZG', true)
+elif not (
+ cc.has_function('__builtin_ctz')
+ and cc.has_function('__builtin_ctzl')
+ and cc.has_function('__builtin_ctzll')
+)
+ error(
+ '__builtin_ctzg or __builtin_ctz* functions are required, please fix your toolchain',
+ )
+endif
+
+# meson_version (>=1.3.0) : required in cc.has_function
+if cc.has_function('__builtin_popcountg')
+ config.set('HAVE_BUILTIN_POPCOUNTG', true)
+elif not (
+ cc.has_function('__builtin_popcount')
+ and cc.has_function('__builtin_popcountl')
+ and cc.has_function('__builtin_popcountll')
+)
+ error(
+ '__builtin_popcountg or __builtin_popcount* functions are required, please fix your toolchain',
+ )
+endif
+
foreach attr : ['malloc', 'returns_nonnull']
if cc.has_function_attribute(attr)
config.set('HAVE_FUNC_ATTRIBUTE_@0@'.format(attr.to_upper()), 1)
echo "$list"
}
+#
+# Check for the usage of built-in bit operarators
+#
+list=$(git grep -l -e '__builtin_ctz' --or -e '__builtin_popcount' --or -e '__builtin_clz' lib bin ':(exclude)lib/isc/include/isc/bit\.h' \
+ | grep -e '\.c$' -e '\.h$')
+[ -n "$list" ] && {
+ status=1
+ echo 'Prefer the helpers in <isc/bit.h> over builtin bit utilities:'
+ echo "$list"
+}
+
exit $status