]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
basic/logarithm: add popcount() wrapper
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Mon, 3 Apr 2023 12:32:39 +0000 (14:32 +0200)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Mon, 24 Apr 2023 08:02:30 +0000 (10:02 +0200)
__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.

src/boot/efi/splash.c
src/fundamental/logarithm.h [moved from src/basic/logarithm.h with 76% similarity]
src/shared/tpm2-util.c
src/test/test-logarithm.c

index f2d9f20e96854450e447d9190ffa93da771e1dcc..8daeb71cb25d1c0b543f1ba4a0b4509eb5272be2 100644 (file)
@@ -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;
similarity index 76%
rename from src/basic/logarithm.h
rename to src/fundamental/logarithm.h
index 646f2d3613a39727360ab57391bcc8692e3dea90..0b03bbded12a257ec4d3d0b9ba3f337a60ffcf07 100644 (file)
@@ -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);                                       \
index 4f51682e8d019cd40a3e64bf1cc5288f44d3e193..97a9a3909b18f8f302a5e66070947c527dce039f 100644 (file)
@@ -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. */
index b6818b422cf167d78371cb2f6932643d5240254a..b35fea9c27c7d87b4992d8eab0a50076e80d8b45 100644 (file)
@@ -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);