/*
- * Copyright 2012 Facebook, Inc.
+ * Copyright 2013 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
// popcnt
#ifndef __POPCNT__
-namespace {
+// Clang doesn't support ifuncs. This also allows ifunc support to be explicitly
+// passed in as a compile flag.
+#ifndef FOLLY_HAVE_IFUNC
+# ifdef __clang__
+# define FOLLY_HAVE_IFUNC 0
+# else
+# define FOLLY_HAVE_IFUNC 1
+# endif
+#endif
-int popcount_inst(unsigned int x) {
- asm ("popcntl %0, %0" : "=r" (x) : "0" (x));
- return x;
-}
+namespace {
int popcount_builtin(unsigned int x) {
return __builtin_popcount(x);
}
-int popcountll_inst(unsigned long long x) {
- asm ("popcntq %0, %0" : "=r" (x) : "0" (x));
- return x;
-}
-
int popcountll_builtin(unsigned long long x) {
return __builtin_popcountll(x);
}
+
+#if FOLLY_HAVE_IFUNC
+
+// Strictly speaking, these versions of popcount are usable without ifunc
+// support. However, we would have to check, via CpuId, if the processor
+// implements the popcnt instruction first, which is what we use ifunc for.
+int popcount_inst(unsigned int x) {
+ int n;
+ asm ("popcntl %1, %0" : "=r" (n) : "r" (x));
+ return n;
+}
+
+int popcountll_inst(unsigned long long x) {
+ unsigned long long n;
+ asm ("popcntq %1, %0" : "=r" (n) : "r" (x));
+ return n;
+}
+
typedef decltype(popcount_builtin) Type_popcount;
typedef decltype(popcountll_builtin) Type_popcountll;
-} // namespace
-
// This function is called on startup to resolve folly::detail::popcount
extern "C" Type_popcount* folly_popcount_ifunc() {
return folly::CpuId().popcnt() ? popcount_inst : popcount_builtin;
return folly::CpuId().popcnt() ? popcountll_inst : popcountll_builtin;
}
+#endif // FOLLY_HAVE_IFUNC
+
+} // namespace
+
namespace folly {
namespace detail {
// Call folly_popcount_ifunc on startup to resolve to either popcount_inst
// or popcount_builtin
int popcount(unsigned int x)
+#if FOLLY_HAVE_IFUNC
__attribute__((ifunc("folly_popcount_ifunc")));
+#else
+{ return popcount_builtin(x); }
+#endif
// Call folly_popcount_ifunc on startup to resolve to either popcountll_inst
// or popcountll_builtin
int popcountll(unsigned long long x)
+#if FOLLY_HAVE_IFUNC
__attribute__((ifunc("folly_popcountll_ifunc")));
+#else
+{ return popcountll_builtin(x); }
+#endif
} // namespace detail
} // namespace folly