Abstract ifunc support into a define
authorOwen Yamauchi <oyamauchi@fb.com>
Tue, 19 Feb 2013 20:20:43 +0000 (12:20 -0800)
committerJordan DeLong <jdelong@fb.com>
Tue, 19 Mar 2013 00:07:54 +0000 (17:07 -0700)
Summary:
There are platforms other than clang that don't support ifuncs. (The one
I'm concerned about is ARM.) I changed the ifdef __clang__ around the
ifunc attributes to be more abstract, so we can can pass in this flag on
the command line, or use autoconf to detect it.

Test Plan:
fbmake runtests. Manually define HAVE_IFUNC 0 and make sure the
popcount() and popcountll() functions get compiled as calls to
popcount_builtin.

Run autoreconf, ./configure, make sure the feature gets detected
properly by looking at config.h.

Reviewed By: andrewjcg@fb.com

FB internal diff: D712192

folly/Bits.cpp
folly/configure.ac

index 9513cd33c84df0c325558faf3aaf22925a4f8b00..62b759f09182193e78ca79a57babff82dbc4c6d1 100644 (file)
 // popcnt
 #ifndef __POPCNT__
 
+// 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
+
 namespace {
 
+int popcount_builtin(unsigned int x) {
+  return __builtin_popcount(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 popcount_builtin(unsigned int x) {
-  return __builtin_popcount(x);
-}
-
 int popcountll_inst(unsigned long long x) {
   unsigned long long n;
   asm ("popcntq %1, %0" : "=r" (n) : "r" (x));
   return n;
 }
 
-int popcountll_builtin(unsigned long long x) {
-  return __builtin_popcountll(x);
-}
-
 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;
@@ -59,27 +73,29 @@ extern "C" Type_popcountll* folly_popcountll_ifunc() {
   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)
-// Clang does not support ifuncs, so we call directly for now
-#ifdef __clang__
-{  return popcount_builtin(x); }
-#else
+#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)
-// Clang does not support ifuncs, so we call directly for now
-#ifdef __clang__
-{  return popcount_builtin(x); }
-#else
+#if FOLLY_HAVE_IFUNC
   __attribute__((ifunc("folly_popcountll_ifunc")));
+#else
+{  return popcountll_builtin(x); }
 #endif
 
 }  // namespace detail
index fad83bb8d6b9a8bc3e357ae49eaab43f247ae25f..d2b28c59c3e98858fe7765f193ad0ced1f652c48 100644 (file)
@@ -56,6 +56,12 @@ AC_CHECK_TYPE([__int128],
   [AC_DEFINE([HAVE_INT128_T], [1], [Define if __int128 exists])],
   [AC_DEFINE([HAVE_INT128_T], [0], [Define if __int128 does not exist])])
 AC_CHECK_TYPES([ptrdiff_t])
+AC_COMPILE_IFELSE(
+  [AC_LANG_SOURCE[extern "C" void (*test_ifunc(void))() { return 0; }
+                  void func() __attribute__((ifunc("test_ifunc")));]],
+  [AC_DEFINE([HAVE_IFUNC], [1], [Define to 1 if the compiler supports ifunc])],
+  [AC_DEFINE([HAVE_IFUNC], [0], [Define to 0 if the compiler doesn't support ifunc])]
+)
 
 # Checks for library functions.
 AC_CHECK_FUNCS([getdelim \