From: "Richard W.M. Jones" <rjones(a)redhat.com>
Signed-off-by: Laszlo Ersek <lersek(a)redhat.com>
(cherry picked from libnbd commit 27a9bb45c70dbb1112cab6bdc1a61b21f78bc6f4)
---
configure.ac | 3 +++
common/include/ispowerof2.h | 13 +++++++++++++
common/include/test-ispowerof2.c | 10 ++++++++++
3 files changed, 26 insertions(+)
diff --git a/configure.ac b/configure.ac
index 9075b0eabda1..597097922831 100644
--- a/configure.ac
+++ b/configure.ac
@@ -344,6 +344,9 @@ test (void)
]
)
+dnl Check sizeof long.
+AC_CHECK_SIZEOF(long)
+
dnl Check for other headers, all optional.
AC_CHECK_HEADERS([\
alloca.h \
diff --git a/common/include/ispowerof2.h b/common/include/ispowerof2.h
index b9a5cc7caf01..c5bcb0c81077 100644
--- a/common/include/ispowerof2.h
+++ b/common/include/ispowerof2.h
@@ -46,4 +46,17 @@ is_power_of_2 (unsigned long v)
return v && ((v & (v - 1)) == 0);
}
+/* Calculate log2(v) which is the size of the equivalent bit shift
+ * for a power of 2. For example log_2_bits (512) == 9.
+ *
+ * Note this is undefined for v == 0.
+ *
+ * __builtin_clzl is available in GCC and clang.
+ */
+static inline int
+log_2_bits (unsigned long v)
+{
+ return SIZEOF_LONG*8 - __builtin_clzl (v) - 1;
+}
+
#endif /* NBDKIT_ISPOWEROF2_H */
diff --git a/common/include/test-ispowerof2.c b/common/include/test-ispowerof2.c
index 9f904b2fc5e8..fd880fa3b551 100644
--- a/common/include/test-ispowerof2.c
+++ b/common/include/test-ispowerof2.c
@@ -58,5 +58,15 @@ main (void)
for (i = 4; i <= 0x80000000; i <<= 1)
assert (! is_power_of_2 (i-1));
+ /* Check log_2_bits on some known values. */
+ assert (log_2_bits (1) == 0);
+ assert (log_2_bits (512) == 9);
+ assert (log_2_bits (4096) == 12);
+ assert (log_2_bits (0x80000000) == 31);
+#if SIZEOF_LONG == 8
+ assert (log_2_bits (0x100000000) == 32);
+ assert (log_2_bits (0x8000000000000000) == 63);
+#endif
+
exit (EXIT_SUCCESS);
}