aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/arch/neon.h13
-rw-r--r--src/arch/portable.h23
-rw-r--r--test/016_popcount_u32/00_all.in0
-rw-r--r--test/016_popcount_u32/00_all.out1
-rw-r--r--test/016_popcount_u32/popcount_u32_tests.c43
5 files changed, 69 insertions, 11 deletions
diff --git a/src/arch/neon.h b/src/arch/neon.h
index 6261c9a..1fb1c82 100644
--- a/src/arch/neon.h
+++ b/src/arch/neon.h
@@ -30,16 +30,17 @@ STATIC_INLINE uint8x8_t compose_corners_slim(uint8x8_t, uint8x8_t);
30#define SOLVED_CUBE STATIC_CUBE( \ 30#define SOLVED_CUBE STATIC_CUBE( \
31 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11) 31 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)
32 32
33/* TODO: optimize this (use intrinsics?) */
34STATIC_INLINE int 33STATIC_INLINE int
35popcount_u32(uint32_t x) 34popcount_u32(uint32_t x)
36{ 35{
37 int ret; 36 /* Same as the portable version */
37 x -= (x >> UINT32_C(1)) & UINT32_C(0x55555555);
38 x = (x & UINT32_C(0x33333333)) +
39 ((x >> UINT32_C(2)) & UINT32_C(0x33333333));
40 x = (x + (x >> UINT32_C(4))) & UINT32_C(0x0F0F0F0F);
41 x = (x * UINT32_C(0x01010101)) >> UINT32_C(24);
38 42
39 for (ret = 0; x != 0; x >>= 1) 43 return (int)x;
40 ret += x & 1;
41
42 return ret;
43} 44}
44 45
45STATIC void 46STATIC void
diff --git a/src/arch/portable.h b/src/arch/portable.h
index 56d3074..bd67c18 100644
--- a/src/arch/portable.h
+++ b/src/arch/portable.h
@@ -9,16 +9,29 @@
9#define SOLVED_CUBE STATIC_CUBE( \ 9#define SOLVED_CUBE STATIC_CUBE( \
10 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11) 10 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)
11 11
12/* TODO: optimize this (use bit tricks?) */
13STATIC_INLINE int 12STATIC_INLINE int
14popcount_u32(uint32_t x) 13popcount_u32(uint32_t x)
15{ 14{
16 int ret; 15 /*
16 Bit trick: accumulate in pairs of bits, quads of bits and so on,
17 until the final result is the sum of all bits.
17 18
18 for (ret = 0; x != 0; x >>= 1) 19 x = (x & 0x55555555) + ((x >> 1) & 0x55555555);
19 ret += x & 1; 20 x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
21 x = (x & 0x0F0F0F0F) + ((x >> 4) & 0x0F0F0F0F);
22 x = (x & 0x00FF00FF) + ((x >> 8) & 0x00FF00FF);
23 x = (x & 0x0000FFFF) + ((x >> 16) & 0x0000FFFF);
20 24
21 return ret; 25 The actual method we use is a small optimization of the one above.
26 */
27
28 x -= (x >> UINT32_C(1)) & UINT32_C(0x55555555);
29 x = (x & UINT32_C(0x33333333)) +
30 ((x >> UINT32_C(2)) & UINT32_C(0x33333333));
31 x = (x + (x >> UINT32_C(4))) & UINT32_C(0x0F0F0F0F);
32 x = (x * UINT32_C(0x01010101)) >> UINT32_C(24);
33
34 return (int)x;
22} 35}
23 36
24STATIC void 37STATIC void
diff --git a/test/016_popcount_u32/00_all.in b/test/016_popcount_u32/00_all.in
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/016_popcount_u32/00_all.in
diff --git a/test/016_popcount_u32/00_all.out b/test/016_popcount_u32/00_all.out
new file mode 100644
index 0000000..7326d96
--- /dev/null
+++ b/test/016_popcount_u32/00_all.out
@@ -0,0 +1 @@
Ok
diff --git a/test/016_popcount_u32/popcount_u32_tests.c b/test/016_popcount_u32/popcount_u32_tests.c
new file mode 100644
index 0000000..ff60c68
--- /dev/null
+++ b/test/016_popcount_u32/popcount_u32_tests.c
@@ -0,0 +1,43 @@
1#include "../test.h"
2
3int popcount_u32(uint32_t x);
4
5int
6popcount_u32_simple(uint32_t x)
7{
8 int ret;
9
10 for (ret = 0; x != 0; x >>= 1)
11 ret += x & 1;
12
13 return ret;
14}
15
16bool
17correct(uint32_t x)
18{
19 int expected = popcount_u32_simple(x);
20 int actual = popcount_u32(x);
21 if (actual != expected) {
22 printf("Error at %" PRIu32 ": expected %d bits, found %d\n",
23 x, expected, actual);
24 return false;
25 }
26 return true;
27}
28
29void run(void) {
30 uint32_t i;
31
32 /* Test all numbers up to 2^16, and other ranges of 2^16 numbers */
33 for (i = 0; i < 0xFFFF; i++) {
34 if (!correct(i) ||
35 !correct(i + UINT32_C(0xFFFF0000)) ||
36 !correct(i + UINT32_C(1000000)) ||
37 !correct(i + UINT32_C(1)) ||
38 !correct(i + UINT32_C(1234567)))
39 return;
40 }
41
42 printf("Ok\n");
43}

Generated with cgit - Back to sebastiano.tronto.net