aboutsummaryrefslogtreecommitdiff
path: root/libgcc/libgcc2.c
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2013-06-28 11:28:40 +0200
committerJakub Jelinek <jakub@gcc.gnu.org>2013-06-28 11:28:40 +0200
commit4ea3d77451d330e8bae29bae981814673dc3b746 (patch)
tree6bb2542aeca126f3ed7209d470724896cf4de0ba /libgcc/libgcc2.c
parentebf8f0eaebb0ede888d8d86719d7cbd82a5f6270 (diff)
downloadgcc-4ea3d77451d330e8bae29bae981814673dc3b746.zip
gcc-4ea3d77451d330e8bae29bae981814673dc3b746.tar.gz
gcc-4ea3d77451d330e8bae29bae981814673dc3b746.tar.bz2
re PR middle-end/36041 (Speed up builtin_popcountll)
PR middle-end/36041 * libgcc2.c (POPCOUNTCST2, POPCOUNTCST4, POPCOUNTCST8, POPCOUNTCST): Define. (__popcountSI2): For __SIZEOF_INT__ > 2 targets use arithmetics instead of table lookups. (__popcountDI2): Likewise. From-SVN: r200506
Diffstat (limited to 'libgcc/libgcc2.c')
-rw-r--r--libgcc/libgcc2.c41
1 files changed, 41 insertions, 0 deletions
diff --git a/libgcc/libgcc2.c b/libgcc/libgcc2.c
index 9138c1e..a47d8af 100644
--- a/libgcc/libgcc2.c
+++ b/libgcc/libgcc2.c
@@ -819,17 +819,42 @@ const UQItype __popcount_tab[256] =
};
#endif
+#if defined(L_popcountsi2) || defined(L_popcountdi2)
+#define POPCOUNTCST2(x) (((UWtype) x << BITS_PER_UNIT) | x)
+#define POPCOUNTCST4(x) (((UWtype) x << (2 * BITS_PER_UNIT)) | x)
+#define POPCOUNTCST8(x) (((UWtype) x << (4 * BITS_PER_UNIT)) | x)
+#if W_TYPE_SIZE == BITS_PER_UNIT
+#define POPCOUNTCST(x) x
+#elif W_TYPE_SIZE == 2 * BITS_PER_UNIT
+#define POPCOUNTCST(x) POPCOUNTCST2 (x)
+#elif W_TYPE_SIZE == 4 * BITS_PER_UNIT
+#define POPCOUNTCST(x) POPCOUNTCST4 (POPCOUNTCST2 (x))
+#elif W_TYPE_SIZE == 8 * BITS_PER_UNIT
+#define POPCOUNTCST(x) POPCOUNTCST8 (POPCOUNTCST4 (POPCOUNTCST2 (x)))
+#endif
+#endif
+
#ifdef L_popcountsi2
#undef int
int
__popcountSI2 (UWtype x)
{
+ /* Force table lookup on targets like AVR and RL78 which only
+ pretend they have LIBGCC2_UNITS_PER_WORD 4, but actually
+ have 1, and other small word targets. */
+#if __SIZEOF_INT__ > 2 && defined (POPCOUNTCST) && BITS_PER_UNIT == 8
+ x = x - ((x >> 1) & POPCOUNTCST (0x55));
+ x = (x & POPCOUNTCST (0x33)) + ((x >> 2) & POPCOUNTCST (0x33));
+ x = (x + (x >> 4)) & POPCOUNTCST (0x0F);
+ return (x * POPCOUNTCST (0x01)) >> (W_TYPE_SIZE - BITS_PER_UNIT);
+#else
int i, ret = 0;
for (i = 0; i < W_TYPE_SIZE; i += 8)
ret += __popcount_tab[(x >> i) & 0xff];
return ret;
+#endif
}
#endif
@@ -838,12 +863,28 @@ __popcountSI2 (UWtype x)
int
__popcountDI2 (UDWtype x)
{
+ /* Force table lookup on targets like AVR and RL78 which only
+ pretend they have LIBGCC2_UNITS_PER_WORD 4, but actually
+ have 1, and other small word targets. */
+#if __SIZEOF_INT__ > 2 && defined (POPCOUNTCST) && BITS_PER_UNIT == 8
+ const DWunion uu = {.ll = x};
+ UWtype x1 = uu.s.low, x2 = uu.s.high;
+ x1 = x1 - ((x1 >> 1) & POPCOUNTCST (0x55));
+ x2 = x2 - ((x2 >> 1) & POPCOUNTCST (0x55));
+ x1 = (x1 & POPCOUNTCST (0x33)) + ((x1 >> 2) & POPCOUNTCST (0x33));
+ x2 = (x2 & POPCOUNTCST (0x33)) + ((x2 >> 2) & POPCOUNTCST (0x33));
+ x1 = (x1 + (x1 >> 4)) & POPCOUNTCST (0x0F);
+ x2 = (x2 + (x2 >> 4)) & POPCOUNTCST (0x0F);
+ x1 += x2;
+ return (x1 * POPCOUNTCST (0x01)) >> (W_TYPE_SIZE - BITS_PER_UNIT);
+#else
int i, ret = 0;
for (i = 0; i < 2*W_TYPE_SIZE; i += 8)
ret += __popcount_tab[(x >> i) & 0xff];
return ret;
+#endif
}
#endif