62b759f09182193e78ca79a57babff82dbc4c6d1
[folly.git] / folly / Bits.cpp
1 /*
2  * Copyright 2013 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "folly/Bits.h"
18
19 #include "folly/CpuId.h"
20
21 // None of this is necessary if we're compiling for a target that supports
22 // popcnt
23 #ifndef __POPCNT__
24
25 // Clang doesn't support ifuncs. This also allows ifunc support to be explicitly
26 // passed in as a compile flag.
27 #ifndef FOLLY_HAVE_IFUNC
28 #  ifdef __clang__
29 #    define FOLLY_HAVE_IFUNC 0
30 #  else
31 #    define FOLLY_HAVE_IFUNC 1
32 #  endif
33 #endif
34
35 namespace {
36
37 int popcount_builtin(unsigned int x) {
38   return __builtin_popcount(x);
39 }
40
41 int popcountll_builtin(unsigned long long x) {
42   return __builtin_popcountll(x);
43 }
44
45
46 #if FOLLY_HAVE_IFUNC
47
48 // Strictly speaking, these versions of popcount are usable without ifunc
49 // support. However, we would have to check, via CpuId, if the processor
50 // implements the popcnt instruction first, which is what we use ifunc for.
51 int popcount_inst(unsigned int x) {
52   int n;
53   asm ("popcntl %1, %0" : "=r" (n) : "r" (x));
54   return n;
55 }
56
57 int popcountll_inst(unsigned long long x) {
58   unsigned long long n;
59   asm ("popcntq %1, %0" : "=r" (n) : "r" (x));
60   return n;
61 }
62
63 typedef decltype(popcount_builtin) Type_popcount;
64 typedef decltype(popcountll_builtin) Type_popcountll;
65
66 // This function is called on startup to resolve folly::detail::popcount
67 extern "C" Type_popcount* folly_popcount_ifunc() {
68   return folly::CpuId().popcnt() ?  popcount_inst : popcount_builtin;
69 }
70
71 // This function is called on startup to resolve folly::detail::popcountll
72 extern "C" Type_popcountll* folly_popcountll_ifunc() {
73   return folly::CpuId().popcnt() ?  popcountll_inst : popcountll_builtin;
74 }
75
76 #endif // FOLLY_HAVE_IFUNC
77
78 }  // namespace
79
80 namespace folly {
81 namespace detail {
82
83 // Call folly_popcount_ifunc on startup to resolve to either popcount_inst
84 // or popcount_builtin
85 int popcount(unsigned int x)
86 #if FOLLY_HAVE_IFUNC
87   __attribute__((ifunc("folly_popcount_ifunc")));
88 #else
89 {  return popcount_builtin(x); }
90 #endif
91
92 // Call folly_popcount_ifunc on startup to resolve to either popcountll_inst
93 // or popcountll_builtin
94 int popcountll(unsigned long long x)
95 #if FOLLY_HAVE_IFUNC
96   __attribute__((ifunc("folly_popcountll_ifunc")));
97 #else
98 {  return popcountll_builtin(x); }
99 #endif
100
101 }  // namespace detail
102 }  // namespace folly
103
104 #endif  /* !__POPCNT__ */
105