From 3a976a95d97a91f59a49ca507fde66d0f4f4fcf1 Mon Sep 17 00:00:00 2001 From: Owen Yamauchi Date: Tue, 19 Feb 2013 12:20:43 -0800 Subject: [PATCH] Abstract ifunc support into a define 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 | 52 ++++++++++++++++++++++++++++++---------------- folly/configure.ac | 6 ++++++ 2 files changed, 40 insertions(+), 18 deletions(-) diff --git a/folly/Bits.cpp b/folly/Bits.cpp index 9513cd33..62b759f0 100644 --- a/folly/Bits.cpp +++ b/folly/Bits.cpp @@ -22,33 +22,47 @@ // 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 diff --git a/folly/configure.ac b/folly/configure.ac index fad83bb8..d2b28c59 100644 --- a/folly/configure.ac +++ b/folly/configure.ac @@ -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 \ -- 2.34.1