summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2023-04-03 14:32:39 +0200
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2023-04-24 10:02:30 +0200
commita12bc99ef0fc04fa48767c891f7a6db6404e51d5 (patch)
treef5840c3081c8aea6cddd557635313a2ab2d426a4
parent6eccc3cfa9dcfea3c8b508a66d2d592e6b9fcb93 (diff)
downloadsystemd-a12bc99ef0fc04fa48767c891f7a6db6404e51d5.tar.gz
basic/logarithm: add popcount() wrapper
__builtin_popcount() is a bit of a mouthful, so let's provide a helper. Using _Generic has the advantage that if a type other then the ones on the list is given, compilation will fail. This is nice, because if by any change we pass a wider type, it is rejected immediately instead of being truncated. log.h is also needed. It is included transitively, but let's include it directly. macro.h is *not* needed.
-rw-r--r--src/boot/efi/splash.c9
-rw-r--r--src/fundamental/logarithm.h (renamed from src/basic/logarithm.h)10
-rw-r--r--src/shared/tpm2-util.c4
-rw-r--r--src/test/test-logarithm.c21
4 files changed, 37 insertions, 7 deletions
diff --git a/src/boot/efi/splash.c b/src/boot/efi/splash.c
index f2d9f20e96..8daeb71cb2 100644
--- a/src/boot/efi/splash.c
+++ b/src/boot/efi/splash.c
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "graphics.h"
+#include "logarithm.h"
#include "proto/graphics-output.h"
#include "splash.h"
#include "unaligned-fundamental.h"
@@ -141,14 +142,14 @@ static void read_channel_maks(
channel_shift[R] = __builtin_ctz(dib->channel_mask_r);
channel_shift[G] = __builtin_ctz(dib->channel_mask_g);
channel_shift[B] = __builtin_ctz(dib->channel_mask_b);
- channel_scale[R] = 0xff / ((1 << __builtin_popcount(dib->channel_mask_r)) - 1);
- channel_scale[G] = 0xff / ((1 << __builtin_popcount(dib->channel_mask_g)) - 1);
- channel_scale[B] = 0xff / ((1 << __builtin_popcount(dib->channel_mask_b)) - 1);
+ channel_scale[R] = 0xff / ((1 << popcount(dib->channel_mask_r)) - 1);
+ channel_scale[G] = 0xff / ((1 << popcount(dib->channel_mask_g)) - 1);
+ channel_scale[B] = 0xff / ((1 << popcount(dib->channel_mask_b)) - 1);
if (dib->size >= SIZEOF_BMP_DIB_RGBA && dib->channel_mask_a != 0) {
channel_mask[A] = dib->channel_mask_a;
channel_shift[A] = __builtin_ctz(dib->channel_mask_a);
- channel_scale[A] = 0xff / ((1 << __builtin_popcount(dib->channel_mask_a)) - 1);
+ channel_scale[A] = 0xff / ((1 << popcount(dib->channel_mask_a)) - 1);
} else {
channel_mask[A] = 0;
channel_shift[A] = 0;
diff --git a/src/basic/logarithm.h b/src/fundamental/logarithm.h
index 646f2d3613..0b03bbded1 100644
--- a/src/basic/logarithm.h
+++ b/src/fundamental/logarithm.h
@@ -3,8 +3,6 @@
#include <stdint.h>
-#include "macro.h"
-
/* Note: log2(0) == log2(1) == 0 here and below. */
#define CONST_LOG2ULL(x) ((x) > 1 ? (unsigned) __builtin_clzll(x) ^ 63U : 0)
@@ -30,6 +28,14 @@ static inline unsigned u32ctz(uint32_t n) {
#endif
}
+#define popcount(n) \
+ _Generic((n), \
+ unsigned char: __builtin_popcount(n), \
+ unsigned short: __builtin_popcount(n), \
+ unsigned: __builtin_popcount(n), \
+ unsigned long: __builtin_popcountl(n), \
+ unsigned long long: __builtin_popcountll(n))
+
#define CONST_LOG2U(x) ((x) > 1 ? __SIZEOF_INT__ * 8 - __builtin_clz(x) - 1 : 0)
#define NONCONST_LOG2U(x) ({ \
unsigned _x = (x); \
diff --git a/src/shared/tpm2-util.c b/src/shared/tpm2-util.c
index 4f51682e8d..97a9a3909b 100644
--- a/src/shared/tpm2-util.c
+++ b/src/shared/tpm2-util.c
@@ -14,6 +14,8 @@
#include "hexdecoct.h"
#include "hmac.h"
#include "lock-util.h"
+#include "log.h"
+#include "logarithm.h"
#include "memory-util.h"
#include "openssl-util.h"
#include "parse-util.h"
@@ -773,7 +775,7 @@ size_t tpm2_tpms_pcr_selection_weight(const TPMS_PCR_SELECTION *s) {
uint32_t mask;
tpm2_tpms_pcr_selection_to_mask(s, &mask);
- return (size_t)__builtin_popcount(mask);
+ return popcount(mask);
}
/* Utility functions for TPML_PCR_SELECTION. */
diff --git a/src/test/test-logarithm.c b/src/test/test-logarithm.c
index b6818b422c..b35fea9c27 100644
--- a/src/test/test-logarithm.c
+++ b/src/test/test-logarithm.c
@@ -71,4 +71,25 @@ TEST(log2i) {
assert_se(log2i(INT_MAX) == sizeof(int)*8-2);
}
+TEST(popcount) {
+ uint16_t u16a = 0x0000;
+ uint16_t u16b = 0xFFFF;
+ uint32_t u32a = 0x00000010;
+ uint32_t u32b = 0xFFFFFFFF;
+ uint64_t u64a = 0x0000000000000010;
+ uint64_t u64b = 0x0100000000100010;
+
+ assert_se(popcount(u16a) == 0);
+ assert_se(popcount(u16b) == 16);
+ assert_se(popcount(u32a) == 1);
+ assert_se(popcount(u32b) == 32);
+ assert_se(popcount(u64a) == 1);
+ assert_se(popcount(u64b) == 3);
+
+ /* This would fail:
+ * error: ‘_Generic’ selector of type ‘int’ is not compatible with any association
+ * assert_se(popcount(0x10) == 1);
+ */
+}
+
DEFINE_TEST_MAIN(LOG_INFO);