8257985: count_trailing_zeros doesn't handle 64-bit values on 32-bit JVM
Reviewed-by: kbarrett
This commit is contained in:
parent
2ee795d9e4
commit
e69ae07f08
src/hotspot/share/utilities
test/hotspot/gtest/utilities
@ -25,14 +25,18 @@
|
||||
#ifndef SHARE_UTILITIES_COUNT_TRAILING_ZEROS_HPP
|
||||
#define SHARE_UTILITIES_COUNT_TRAILING_ZEROS_HPP
|
||||
|
||||
#include "metaprogramming/enableIf.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
// unsigned count_trailing_zeros(uintx x)
|
||||
// unsigned count_trailing_zeros(T x)
|
||||
|
||||
// Return the number of trailing zeros in x, e.g. the zero-based index
|
||||
// of the least significant set bit in x.
|
||||
// Precondition: x != 0.
|
||||
|
||||
// We implement and support variants for 8, 16, 32 and 64 bit integral types.
|
||||
|
||||
// Dispatch on toolchain to select implementation.
|
||||
|
||||
/*****************************************************************************
|
||||
@ -40,10 +44,12 @@
|
||||
*****************************************************************************/
|
||||
#if defined(TARGET_COMPILER_gcc)
|
||||
|
||||
inline unsigned count_trailing_zeros(uintx x) {
|
||||
STATIC_ASSERT(sizeof(unsigned long) == sizeof(uintx));
|
||||
assert(x != 0, "precondition");
|
||||
return __builtin_ctzl(x);
|
||||
inline unsigned count_trailing_zeros_32(uint32_t x) {
|
||||
return __builtin_ctz(x);
|
||||
}
|
||||
|
||||
inline unsigned count_trailing_zeros_64(uint64_t x) {
|
||||
return __builtin_ctzll(x);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
@ -53,19 +59,27 @@ inline unsigned count_trailing_zeros(uintx x) {
|
||||
|
||||
#include <intrin.h>
|
||||
|
||||
#pragma intrinsic(_BitScanForward)
|
||||
#ifdef _LP64
|
||||
#pragma intrinsic(_BitScanForward64)
|
||||
#else
|
||||
#pragma intrinsic(_BitScanForward)
|
||||
#endif
|
||||
|
||||
inline unsigned count_trailing_zeros(uintx x) {
|
||||
assert(x != 0, "precondition");
|
||||
inline unsigned count_trailing_zeros_32(uint32_t x) {
|
||||
unsigned long index;
|
||||
_BitScanForward(&index, x);
|
||||
return index;
|
||||
}
|
||||
|
||||
inline unsigned count_trailing_zeros_64(uint64_t x) {
|
||||
unsigned long index;
|
||||
#ifdef _LP64
|
||||
_BitScanForward64(&index, x);
|
||||
#else
|
||||
_BitScanForward(&index, x);
|
||||
if (_BitScanForward(&index, static_cast<uint32_t>(x)) == 0) {
|
||||
// no bit found? If so, try the upper dword. Otherwise index already contains the result
|
||||
_BitScanForward(&index, static_cast<uint32_t>(x >> 32));
|
||||
index += 32;
|
||||
}
|
||||
#endif
|
||||
return index;
|
||||
}
|
||||
@ -77,13 +91,12 @@ inline unsigned count_trailing_zeros(uintx x) {
|
||||
|
||||
#include <builtins.h>
|
||||
|
||||
inline unsigned count_trailing_zeros(uintx x) {
|
||||
assert(x != 0, "precondition");
|
||||
#ifdef _LP64
|
||||
return __cnttz8(x);
|
||||
#else
|
||||
inline unsigned count_trailing_zeros_32(uint32_t x) {
|
||||
return __cnttz4(x);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline unsigned count_trailing_zeros_64(uint64_t x) {
|
||||
return __cnttz8(x);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
@ -94,4 +107,15 @@ inline unsigned count_trailing_zeros(uintx x) {
|
||||
|
||||
#endif // Toolchain dispatch
|
||||
|
||||
template<typename T,
|
||||
ENABLE_IF(std::is_integral<T>::value),
|
||||
ENABLE_IF(sizeof(T) <= sizeof(uint64_t))>
|
||||
inline unsigned count_trailing_zeros(T x) {
|
||||
assert(x != 0, "precondition");
|
||||
return (sizeof(x) <= sizeof(uint32_t)) ?
|
||||
count_trailing_zeros_32(static_cast<uint32_t>(x)) :
|
||||
count_trailing_zeros_64(x);
|
||||
}
|
||||
|
||||
|
||||
#endif // SHARE_UTILITIES_COUNT_TRAILING_ZEROS_HPP
|
||||
|
@ -27,31 +27,67 @@
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
#include "unittest.hpp"
|
||||
|
||||
TEST(count_trailing_zeros, one_or_two_set_bits) {
|
||||
|
||||
template <typename T> static void test_one_or_two_set_bits() {
|
||||
unsigned i = 0; // Position of a set bit.
|
||||
for (uintx ix = 1; ix != 0; ix <<= 1, ++i) {
|
||||
unsigned max = sizeof(T) * BitsPerByte;
|
||||
for (T ix = T(1); i < max; ix <<= 1, ++i) {
|
||||
unsigned j = 0; // Position of a set bit.
|
||||
for (uintx jx = 1; jx != 0; jx <<= 1, ++j) {
|
||||
uintx value = ix | jx;
|
||||
for (T jx = T(1); j < max; jx <<= 1, ++j) {
|
||||
T value = ix | jx;
|
||||
EXPECT_EQ(MIN2(i, j), count_trailing_zeros(value))
|
||||
<< "value = " << value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(count_trailing_zeros, high_zeros_low_ones) {
|
||||
uintx value = ~(uintx)0;
|
||||
TEST(count_trailing_zeros, one_or_two_set_bits) {
|
||||
test_one_or_two_set_bits<int8_t>();
|
||||
test_one_or_two_set_bits<int16_t>();
|
||||
test_one_or_two_set_bits<int32_t>();
|
||||
test_one_or_two_set_bits<int64_t>();
|
||||
test_one_or_two_set_bits<uint8_t>();
|
||||
test_one_or_two_set_bits<uint16_t>();
|
||||
test_one_or_two_set_bits<uint32_t>();
|
||||
test_one_or_two_set_bits<uint64_t>();
|
||||
}
|
||||
|
||||
template <typename T> static void test_high_zeros_low_ones() {
|
||||
T value = std::numeric_limits<T>::max();
|
||||
for ( ; value != 0; value >>= 1) {
|
||||
EXPECT_EQ(0u, count_trailing_zeros(value))
|
||||
<< "value = " << value;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(count_trailing_zeros, high_ones_low_zeros) {
|
||||
TEST(count_trailing_zeros, high_zeros_low_ones) {
|
||||
test_high_zeros_low_ones<int8_t>();
|
||||
test_high_zeros_low_ones<int16_t>();
|
||||
test_high_zeros_low_ones<int32_t>();
|
||||
test_high_zeros_low_ones<int64_t>();
|
||||
test_high_zeros_low_ones<uint8_t>();
|
||||
test_high_zeros_low_ones<uint16_t>();
|
||||
test_high_zeros_low_ones<uint32_t>();
|
||||
test_high_zeros_low_ones<uint64_t>();
|
||||
}
|
||||
|
||||
template <typename T> static void test_high_ones_low_zeros() {
|
||||
unsigned i = 0; // Index of least significant set bit.
|
||||
uintx value = ~(uintx)0;
|
||||
for ( ; value != 0; value <<= 1, ++i) {
|
||||
T value = ~T(0);
|
||||
unsigned max = sizeof(T) * BitsPerByte;
|
||||
for ( ; i < max; value <<= 1, ++i) {
|
||||
EXPECT_EQ(i, count_trailing_zeros(value))
|
||||
<< "value = " << value;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(count_trailing_zeros, high_ones_low_zeros) {
|
||||
test_high_ones_low_zeros<int8_t>();
|
||||
test_high_ones_low_zeros<int16_t>();
|
||||
test_high_ones_low_zeros<int32_t>();
|
||||
test_high_ones_low_zeros<int64_t>();
|
||||
test_high_ones_low_zeros<uint8_t>();
|
||||
test_high_ones_low_zeros<uint16_t>();
|
||||
test_high_ones_low_zeros<uint32_t>();
|
||||
test_high_ones_low_zeros<uint64_t>();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user