Blob Blame History Raw
--- fmpz/popcnt.c.orig	2015-08-13 10:16:22.000000000 -0600
+++ fmpz/popcnt.c	2016-04-23 14:50:25.442091489 -0600
@@ -25,6 +25,54 @@ static __inline__ mp_bitcnt_t shortCount
 }
 #endif
 
+#ifdef __x86_64__
+#include <cpuid.h>
+
+static mp_bitcnt_t slow_fmpz_popcnt(const fmpz_t c)
+{
+        fmpz c1;
+        c1 = *c;
+        if(!COEFF_IS_MPZ(c1))
+        {
+                if(*c < 0) return 0;
+                else return __builtin_popcountl(*c);
+        } else
+        {
+                __mpz_struct *t = COEFF_TO_PTR(c1);
+                if(flint_mpz_cmp_si(t,0) < 0) return 0;
+                else return mpz_popcount(t);
+        }
+}
+
+static mp_bitcnt_t __attribute__((target ("popcnt")))
+fast_fmpz_popcnt(const fmpz_t c)
+{
+        fmpz c1;
+        c1 = *c;
+        if(!COEFF_IS_MPZ(c1))
+        {
+                if(*c < 0) return 0;
+                else return __builtin_popcountl(*c);
+        } else
+        {
+                __mpz_struct *t = COEFF_TO_PTR(c1);
+                if(flint_mpz_cmp_si(t,0) < 0) return 0;
+                else return mpz_popcount(t);
+        }
+}
+
+static void __attribute__((optimize ("O0")))
+(*resolve_fmpz_popcnt (void))(void) {
+        unsigned int eax, ebx, ecx, edx;
+        return (__get_cpuid(1, &eax, &ebx, &ecx, &edx) &&
+                (ecx & bit_POPCNT) != 0)
+                ? (void (*)(void))&fast_fmpz_popcnt
+                : (void (*)(void))&slow_fmpz_popcnt;
+}
+
+mp_bitcnt_t __attribute__((ifunc ("resolve_fmpz_popcnt")))
+fmpz_popcnt(const fmpz_t c);
+#else
 mp_bitcnt_t fmpz_popcnt(const fmpz_t c)
 {
         fmpz c1;
@@ -40,3 +88,4 @@ mp_bitcnt_t fmpz_popcnt(const fmpz_t c)
                 else return mpz_popcount(t);
         }
 }
+#endif