summaryrefslogtreecommitdiff
path: root/runtime/base/bit_utils.h
diff options
context:
space:
mode:
author buzbee <buzbee@google.com> 2017-03-14 15:30:19 -0700
committer buzbee <buzbee@google.com> 2017-03-16 05:31:59 -0700
commit31afbec96e9f9c8e58778694e74aea7ce55e1378 (patch)
tree1ad1633c75fb6c65fbb25d09fb9dcf92c4a81b8c /runtime/base/bit_utils.h
parentc53528a048e47ef8c51fc5c9667061ebd840adf1 (diff)
ART: Bit intrinsics for Mterp interpreter
Another batch of interpreter intrinisics, mostly around bit manipulation. Also some formatting changes and inclusion of a comprehensive list of recognized intrinisics (to assist with telling what's left to do). Bug: 30933338 Benchmarks: 20% Improvement for Reversi 10% Improvement for Scimark2 3% Improvement for ChessBench Test: ART_TEST_INTERPRETER=true m test-art-host Test: art/tools/run-libcore-tests --host (edited for force -Xint) Note: Added intrinsics have existing test coverage via 082-inline-execute, 123-inline-execute2, 565-checker-rotate, 564-checker-bitcount, 566-checker-signum & 567-checker-compare Change-Id: I29f0386e28eddba37c44f9ced44e7d5f8206bb47
Diffstat (limited to 'runtime/base/bit_utils.h')
-rw-r--r--runtime/base/bit_utils.h113
1 files changed, 97 insertions, 16 deletions
diff --git a/runtime/base/bit_utils.h b/runtime/base/bit_utils.h
index 4041f5e1ed..f536c72bae 100644
--- a/runtime/base/bit_utils.h
+++ b/runtime/base/bit_utils.h
@@ -27,6 +27,22 @@
namespace art {
+// Like sizeof, but count how many bits a type takes. Pass type explicitly.
+template <typename T>
+constexpr size_t BitSizeOf() {
+ static_assert(std::is_integral<T>::value, "T must be integral");
+ using unsigned_type = typename std::make_unsigned<T>::type;
+ static_assert(sizeof(T) == sizeof(unsigned_type), "Unexpected type size mismatch!");
+ static_assert(std::numeric_limits<unsigned_type>::radix == 2, "Unexpected radix!");
+ return std::numeric_limits<unsigned_type>::digits;
+}
+
+// Like sizeof, but count how many bits a type takes. Infers type from parameter.
+template <typename T>
+constexpr size_t BitSizeOf(T /*x*/) {
+ return BitSizeOf<T>();
+}
+
template<typename T>
constexpr int CLZ(T x) {
static_assert(std::is_integral<T>::value, "T must be integral");
@@ -37,6 +53,14 @@ constexpr int CLZ(T x) {
return (sizeof(T) == sizeof(uint32_t)) ? __builtin_clz(x) : __builtin_clzll(x);
}
+// Similar to CLZ except that on zero input it returns bitwidth and supports signed integers.
+template<typename T>
+constexpr int JAVASTYLE_CLZ(T x) {
+ static_assert(std::is_integral<T>::value, "T must be integral");
+ using unsigned_type = typename std::make_unsigned<T>::type;
+ return (x == 0) ? BitSizeOf<T>() : CLZ(static_cast<unsigned_type>(x));
+}
+
template<typename T>
constexpr int CTZ(T x) {
static_assert(std::is_integral<T>::value, "T must be integral");
@@ -48,12 +72,32 @@ constexpr int CTZ(T x) {
return (sizeof(T) == sizeof(uint32_t)) ? __builtin_ctz(x) : __builtin_ctzll(x);
}
+// Similar to CTZ except that on zero input it returns bitwidth and supports signed integers.
+template<typename T>
+constexpr int JAVASTYLE_CTZ(T x) {
+ static_assert(std::is_integral<T>::value, "T must be integral");
+ using unsigned_type = typename std::make_unsigned<T>::type;
+ return (x == 0) ? BitSizeOf<T>() : CTZ(static_cast<unsigned_type>(x));
+}
+
// Return the number of 1-bits in `x`.
template<typename T>
constexpr int POPCOUNT(T x) {
return (sizeof(T) == sizeof(uint32_t)) ? __builtin_popcount(x) : __builtin_popcountll(x);
}
+// Swap bytes.
+template<typename T>
+constexpr T BSWAP(T x) {
+ if (sizeof(T) == sizeof(uint16_t)) {
+ return __builtin_bswap16(x);
+ } else if (sizeof(T) == sizeof(uint32_t)) {
+ return __builtin_bswap32(x);
+ } else {
+ return __builtin_bswap64(x);
+ }
+}
+
// Find the bit position of the most significant bit (0-based), or -1 if there were no bits set.
template <typename T>
constexpr ssize_t MostSignificantBit(T value) {
@@ -169,22 +213,6 @@ inline bool IsAlignedParam(T* x, int n) {
#define DCHECK_ALIGNED_PARAM(value, alignment) \
DCHECK(::art::IsAlignedParam(value, alignment)) << reinterpret_cast<const void*>(value)
-// Like sizeof, but count how many bits a type takes. Pass type explicitly.
-template <typename T>
-constexpr size_t BitSizeOf() {
- static_assert(std::is_integral<T>::value, "T must be integral");
- using unsigned_type = typename std::make_unsigned<T>::type;
- static_assert(sizeof(T) == sizeof(unsigned_type), "Unexpected type size mismatch!");
- static_assert(std::numeric_limits<unsigned_type>::radix == 2, "Unexpected radix!");
- return std::numeric_limits<unsigned_type>::digits;
-}
-
-// Like sizeof, but count how many bits a type takes. Infers type from parameter.
-template <typename T>
-constexpr size_t BitSizeOf(T /*x*/) {
- return BitSizeOf<T>();
-}
-
inline uint16_t Low16Bits(uint32_t value) {
return static_cast<uint16_t>(value);
}
@@ -363,6 +391,59 @@ IterationRange<HighToLowBitIterator<T>> HighToLowBits(T bits) {
HighToLowBitIterator<T>(bits), HighToLowBitIterator<T>());
}
+// Returns value with bit set in lowest one-bit position or 0 if 0. (java.lang.X.lowestOneBit).
+template <typename kind>
+inline static kind LowestOneBitValue(kind opnd) {
+ // Hacker's Delight, Section 2-1
+ return opnd & -opnd;
+}
+
+// Returns value with bit set in hightest one-bit position or 0 if 0. (java.lang.X.highestOneBit).
+template <typename T>
+inline static T HighestOneBitValue(T opnd) {
+ using unsigned_type = typename std::make_unsigned<T>::type;
+ T res;
+ if (opnd == 0) {
+ res = 0;
+ } else {
+ int bit_position = BitSizeOf<T>() - (CLZ(static_cast<unsigned_type>(opnd)) + 1);
+ res = static_cast<T>(UINT64_C(1) << bit_position);
+ }
+ return res;
+}
+
+// Rotate bits.
+template <typename T, bool left>
+inline static T Rot(T opnd, int distance) {
+ int mask = BitSizeOf<T>() - 1;
+ int unsigned_right_shift = left ? (-distance & mask) : (distance & mask);
+ int signed_left_shift = left ? (distance & mask) : (-distance & mask);
+ using unsigned_type = typename std::make_unsigned<T>::type;
+ return (static_cast<unsigned_type>(opnd) >> unsigned_right_shift) | (opnd << signed_left_shift);
+}
+
+// TUNING: use rbit for arm/arm64
+inline static uint32_t ReverseBits32(uint32_t opnd) {
+ // Hacker's Delight 7-1
+ opnd = ((opnd >> 1) & 0x55555555) | ((opnd & 0x55555555) << 1);
+ opnd = ((opnd >> 2) & 0x33333333) | ((opnd & 0x33333333) << 2);
+ opnd = ((opnd >> 4) & 0x0F0F0F0F) | ((opnd & 0x0F0F0F0F) << 4);
+ opnd = ((opnd >> 8) & 0x00FF00FF) | ((opnd & 0x00FF00FF) << 8);
+ opnd = ((opnd >> 16)) | ((opnd) << 16);
+ return opnd;
+}
+
+// TUNING: use rbit for arm/arm64
+inline static uint64_t ReverseBits64(uint64_t opnd) {
+ // Hacker's Delight 7-1
+ opnd = (opnd & 0x5555555555555555L) << 1 | ((opnd >> 1) & 0x5555555555555555L);
+ opnd = (opnd & 0x3333333333333333L) << 2 | ((opnd >> 2) & 0x3333333333333333L);
+ opnd = (opnd & 0x0f0f0f0f0f0f0f0fL) << 4 | ((opnd >> 4) & 0x0f0f0f0f0f0f0f0fL);
+ opnd = (opnd & 0x00ff00ff00ff00ffL) << 8 | ((opnd >> 8) & 0x00ff00ff00ff00ffL);
+ opnd = (opnd << 48) | ((opnd & 0xffff0000L) << 16) | ((opnd >> 16) & 0xffff0000L) | (opnd >> 48);
+ return opnd;
+}
+
} // namespace art
#endif // ART_RUNTIME_BASE_BIT_UTILS_H_