Commit f1eb3c50 authored by Christopher Dykes's avatar Christopher Dykes Committed by Facebook Github Bot

Switch Bits.h to just use the popcount builtins directly

Summary:
These builtins are available on all platforms under GCC, using the instruction directly when available and a fallback implementation otherwise.
They are implemented in the builtins portability header for MSVC.

Reviewed By: yfeldblum

Differential Revision: D5185106

fbshipit-source-id: a58305a6b99eb49bd165876a4a60c512a259b225
parent 43fde9f2
/*
* Copyright 2017 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <folly/Bits.h>
#include <folly/CpuId.h>
#include <folly/Portability.h>
// None of this is necessary if we're compiling for a target that supports
// popcnt, which includes MSVC
#if !defined(__POPCNT__) && !defined(_MSC_VER)
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 && !defined(FOLLY_SANITIZE_ADDRESS)
// 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;
// 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;
}
// This function is called on startup to resolve folly::detail::popcountll
extern "C" Type_popcountll* folly_popcountll_ifunc() {
return folly::CpuId().popcnt() ? popcountll_inst : popcountll_builtin;
}
#endif // FOLLY_HAVE_IFUNC && !defined(FOLLY_SANITIZE_ADDRESS)
} // 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 && !defined(FOLLY_SANITIZE_ADDRESS)
__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 && !defined(FOLLY_SANITIZE_ADDRESS)
__attribute__((__ifunc__("folly_popcountll_ifunc")));
#else
{ return popcountll_builtin(x); }
#endif
} // namespace detail
} // namespace folly
#endif /* !__POPCNT__ */
......@@ -66,7 +66,6 @@
#include <folly/portability/Builtins.h>
#include <folly/Assume.h>
#include <folly/detail/BitsDetail.h>
#include <folly/detail/BitIteratorDetail.h>
#include <folly/Likely.h>
......@@ -214,7 +213,7 @@ inline typename std::enable_if<
sizeof(T) <= sizeof(unsigned int)),
size_t>::type
popcount(T x) {
return size_t(detail::popcount(x));
return size_t(__builtin_popcount(x));
}
template <class T>
......@@ -225,7 +224,7 @@ inline typename std::enable_if<
sizeof(T) <= sizeof(unsigned long long)),
size_t>::type
popcount(T x) {
return size_t(detail::popcountll(x));
return size_t(__builtin_popcountll(x));
}
/**
......
......@@ -63,7 +63,6 @@ nobase_follyinclude_HEADERS = \
detail/AtomicUnorderedMapUtils.h \
detail/AtomicUtils.h \
detail/BitIteratorDetail.h \
detail/BitsDetail.h \
detail/CacheLocality.h \
detail/CachelinePaddedImpl.h \
detail/ChecksumDetail.h \
......@@ -440,7 +439,6 @@ libfollybase_la_SOURCES = \
libfolly_la_SOURCES = \
Assume.cpp \
Bits.cpp \
Checksum.cpp \
ClockGettimeWrappers.cpp \
detail/CacheLocality.cpp \
......
/*
* Copyright 2017 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
namespace folly {
namespace detail {
// If we're targeting an architecture with popcnt support, use
// __builtin_popcount directly, as it's presumably inlined.
// If not, use runtime detection using __attribute__((__ifunc__))
// (see Bits.cpp)
#ifdef _MSC_VER
inline int popcount(unsigned int x) {
return int(__popcnt(x));
}
inline int popcountll(unsigned long long x) {
return int(__popcnt64(x));
}
#elif defined(__POPCNT__)
inline int popcount(unsigned int x) {
return __builtin_popcount(x);
}
inline int popcountll(unsigned long long x) {
return __builtin_popcountll(x);
}
#else /* !__POPCNT__ */
int popcount(unsigned int x);
int popcountll(unsigned long long x);
#endif /* !__POPCNT__ */
} // namespace detail
} // namespace folly
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