Commit 3a976a95 authored by Owen Yamauchi's avatar Owen Yamauchi Committed by Jordan DeLong

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
parent d059cdd4
...@@ -22,33 +22,47 @@ ...@@ -22,33 +22,47 @@
// popcnt // popcnt
#ifndef __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 { 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 popcount_inst(unsigned int x) {
int n; int n;
asm ("popcntl %1, %0" : "=r" (n) : "r" (x)); asm ("popcntl %1, %0" : "=r" (n) : "r" (x));
return n; return n;
} }
int popcount_builtin(unsigned int x) {
return __builtin_popcount(x);
}
int popcountll_inst(unsigned long long x) { int popcountll_inst(unsigned long long x) {
unsigned long long n; unsigned long long n;
asm ("popcntq %1, %0" : "=r" (n) : "r" (x)); asm ("popcntq %1, %0" : "=r" (n) : "r" (x));
return n; return n;
} }
int popcountll_builtin(unsigned long long x) {
return __builtin_popcountll(x);
}
typedef decltype(popcount_builtin) Type_popcount; typedef decltype(popcount_builtin) Type_popcount;
typedef decltype(popcountll_builtin) Type_popcountll; typedef decltype(popcountll_builtin) Type_popcountll;
} // namespace
// This function is called on startup to resolve folly::detail::popcount // This function is called on startup to resolve folly::detail::popcount
extern "C" Type_popcount* folly_popcount_ifunc() { extern "C" Type_popcount* folly_popcount_ifunc() {
return folly::CpuId().popcnt() ? popcount_inst : popcount_builtin; return folly::CpuId().popcnt() ? popcount_inst : popcount_builtin;
...@@ -59,27 +73,29 @@ extern "C" Type_popcountll* folly_popcountll_ifunc() { ...@@ -59,27 +73,29 @@ extern "C" Type_popcountll* folly_popcountll_ifunc() {
return folly::CpuId().popcnt() ? popcountll_inst : popcountll_builtin; return folly::CpuId().popcnt() ? popcountll_inst : popcountll_builtin;
} }
#endif // FOLLY_HAVE_IFUNC
} // namespace
namespace folly { namespace folly {
namespace detail { namespace detail {
// Call folly_popcount_ifunc on startup to resolve to either popcount_inst // Call folly_popcount_ifunc on startup to resolve to either popcount_inst
// or popcount_builtin // or popcount_builtin
int popcount(unsigned int x) int popcount(unsigned int x)
// Clang does not support ifuncs, so we call directly for now #if FOLLY_HAVE_IFUNC
#ifdef __clang__
{ return popcount_builtin(x); }
#else
__attribute__((ifunc("folly_popcount_ifunc"))); __attribute__((ifunc("folly_popcount_ifunc")));
#else
{ return popcount_builtin(x); }
#endif #endif
// Call folly_popcount_ifunc on startup to resolve to either popcountll_inst // Call folly_popcount_ifunc on startup to resolve to either popcountll_inst
// or popcountll_builtin // or popcountll_builtin
int popcountll(unsigned long long x) int popcountll(unsigned long long x)
// Clang does not support ifuncs, so we call directly for now #if FOLLY_HAVE_IFUNC
#ifdef __clang__
{ return popcount_builtin(x); }
#else
__attribute__((ifunc("folly_popcountll_ifunc"))); __attribute__((ifunc("folly_popcountll_ifunc")));
#else
{ return popcountll_builtin(x); }
#endif #endif
} // namespace detail } // namespace detail
......
...@@ -56,6 +56,12 @@ AC_CHECK_TYPE([__int128], ...@@ -56,6 +56,12 @@ AC_CHECK_TYPE([__int128],
[AC_DEFINE([HAVE_INT128_T], [1], [Define if __int128 exists])], [AC_DEFINE([HAVE_INT128_T], [1], [Define if __int128 exists])],
[AC_DEFINE([HAVE_INT128_T], [0], [Define if __int128 does not exist])]) [AC_DEFINE([HAVE_INT128_T], [0], [Define if __int128 does not exist])])
AC_CHECK_TYPES([ptrdiff_t]) 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. # Checks for library functions.
AC_CHECK_FUNCS([getdelim \ AC_CHECK_FUNCS([getdelim \
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment