diff options
Diffstat (limited to '')
| -rw-r--r-- | src/arch/neon.h | 13 | ||||
| -rw-r--r-- | src/arch/portable.h | 23 | ||||
| -rw-r--r-- | test/016_popcount_u32/00_all.in | 0 | ||||
| -rw-r--r-- | test/016_popcount_u32/00_all.out | 1 | ||||
| -rw-r--r-- | test/016_popcount_u32/popcount_u32_tests.c | 43 |
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?) */ | ||
| 34 | STATIC_INLINE int | 33 | STATIC_INLINE int |
| 35 | popcount_u32(uint32_t x) | 34 | popcount_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 | ||
| 45 | STATIC void | 46 | STATIC 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?) */ | ||
| 13 | STATIC_INLINE int | 12 | STATIC_INLINE int |
| 14 | popcount_u32(uint32_t x) | 13 | popcount_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 | ||
| 24 | STATIC void | 37 | STATIC 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 | |||
| 3 | int popcount_u32(uint32_t x); | ||
| 4 | |||
| 5 | int | ||
| 6 | popcount_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 | |||
| 16 | bool | ||
| 17 | correct(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 | |||
| 29 | void 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 | } | ||
