8247910: Improve alignment and power-of-2 utilities using C++14
8238956: Replace powerOfTwo::max_value with std::numeric_limits Reviewed-by: tschatzl, stefank
This commit is contained in:
parent
70cc7fc198
commit
af8c678038
src/hotspot
cpu/zero
share
gc/shared
memory
runtime
services
utilities
test/hotspot/gtest
@ -57,8 +57,8 @@ class InterpreterFrame : public ZeroFrame {
|
||||
protected:
|
||||
enum Layout {
|
||||
istate_off = jf_header_words +
|
||||
(align_up_(sizeof(BytecodeInterpreter),
|
||||
wordSize) >> LogBytesPerWord) - 1,
|
||||
(align_up(sizeof(BytecodeInterpreter),
|
||||
wordSize) >> LogBytesPerWord) - 1,
|
||||
header_words
|
||||
};
|
||||
|
||||
|
@ -113,8 +113,8 @@ protected:
|
||||
|
||||
// N must be a power of 2 for computing modulo via masking.
|
||||
// N must be >= 2 for the algorithm to work at all, though larger is better.
|
||||
// C++11: is_power_of_2 is not (yet) constexpr.
|
||||
STATIC_ASSERT((N >= 2) && ((N & (N - 1)) == 0));
|
||||
STATIC_ASSERT(N >= 2);
|
||||
STATIC_ASSERT(is_power_of_2(N));
|
||||
static const uint MOD_N_MASK = N - 1;
|
||||
|
||||
class Age {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -34,7 +34,7 @@
|
||||
// when the start address is not a multiple of alignment; the second maintains
|
||||
// alignment of starting addresses that happen to be a multiple.
|
||||
#define PADDING_SIZE(type, alignment) \
|
||||
((alignment) + align_up_(sizeof(type), (alignment)))
|
||||
((alignment) + align_up(sizeof(type), (alignment)))
|
||||
|
||||
// Templates to create a subclass padded to avoid cache line sharing. These are
|
||||
// effective only when applied to derived-most (leaf) classes.
|
||||
@ -69,7 +69,7 @@ class PaddedEndImpl<T, /*pad_size*/ 0> : public T {
|
||||
// No padding.
|
||||
};
|
||||
|
||||
#define PADDED_END_SIZE(type, alignment) (align_up_(sizeof(type), (alignment)) - sizeof(type))
|
||||
#define PADDED_END_SIZE(type, alignment) (align_up(sizeof(type), (alignment)) - sizeof(type))
|
||||
|
||||
// More memory conservative implementation of Padded. The subclass adds the
|
||||
// minimal amount of padding needed to make the size of the objects be aligned.
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -36,7 +36,7 @@
|
||||
template <class T, MEMFLAGS flags, size_t alignment>
|
||||
PaddedEnd<T>* PaddedArray<T, flags, alignment>::create_unfreeable(uint length) {
|
||||
// Check that the PaddedEnd class works as intended.
|
||||
STATIC_ASSERT(is_aligned_(sizeof(PaddedEnd<T>), alignment));
|
||||
STATIC_ASSERT(is_aligned(sizeof(PaddedEnd<T>), alignment));
|
||||
|
||||
// Allocate a chunk of memory large enough to allow for some alignment.
|
||||
void* chunk = AllocateHeap(length * sizeof(PaddedEnd<T, alignment>) + alignment, flags);
|
||||
|
@ -37,7 +37,7 @@
|
||||
// parts of the memory system may require additional alignment
|
||||
// and are responsible for those alignments.
|
||||
#ifdef _LP64
|
||||
#define ScaleForWordSize(x) align_down_((x) * 13 / 10, HeapWordSize)
|
||||
#define ScaleForWordSize(x) align_down((x) * 13 / 10, HeapWordSize)
|
||||
#else
|
||||
#define ScaleForWordSize(x) (x)
|
||||
#endif
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -29,7 +29,7 @@
|
||||
#include "utilities/align.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
#define CALC_OBJ_SIZE_IN_TYPE(obj, type) (align_up_(sizeof(obj), sizeof(type))/sizeof(type))
|
||||
#define CALC_OBJ_SIZE_IN_TYPE(obj, type) (align_up(sizeof(obj), sizeof(type))/sizeof(type))
|
||||
|
||||
// Native memory tracking level
|
||||
enum NMT_TrackingLevel {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -25,65 +25,64 @@
|
||||
#ifndef SHARE_UTILITIES_ALIGN_HPP
|
||||
#define SHARE_UTILITIES_ALIGN_HPP
|
||||
|
||||
#include "metaprogramming/enableIf.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
#include "utilities/powerOfTwo.hpp"
|
||||
#include <type_traits>
|
||||
|
||||
// Signed variants of alignment helpers. There are two versions of each, a macro
|
||||
// for use in places like enum definitions that require compile-time constant
|
||||
// expressions and a function for all other places so as to get type checking.
|
||||
|
||||
// Using '(what) & ~align_mask(alignment)' to align 'what' down is broken when
|
||||
// 'alignment' is an unsigned int and 'what' is a wider type. The & operation
|
||||
// will widen the inverted mask, and not sign extend it, leading to a mask with
|
||||
// zeros in the most significant bits. The use of align_mask_widened() solves
|
||||
// this problem.
|
||||
#define align_mask(alignment) ((alignment) - 1)
|
||||
#define widen_to_type_of(what, type_carrier) (true ? (what) : (type_carrier))
|
||||
#define align_mask_widened(alignment, type_carrier) widen_to_type_of(align_mask(alignment), (type_carrier))
|
||||
|
||||
#define align_down_(size, alignment) ((size) & ~align_mask_widened((alignment), (size)))
|
||||
|
||||
#define align_up_(size, alignment) (align_down_((size) + align_mask(alignment), (alignment)))
|
||||
|
||||
#define is_aligned_(size, alignment) (((size) & align_mask(alignment)) == 0)
|
||||
|
||||
// Helpers to align sizes and check for alignment
|
||||
|
||||
template <typename T, typename A>
|
||||
inline T align_up(T size, A alignment) {
|
||||
assert(is_power_of_2(alignment), "must be a power of 2: " UINT64_FORMAT, (uint64_t)alignment);
|
||||
|
||||
T ret = align_up_(size, alignment);
|
||||
assert(is_aligned_(ret, alignment), "must be aligned: " UINT64_FORMAT, (uint64_t)ret);
|
||||
|
||||
return ret;
|
||||
// Compute mask to use for aligning to or testing alignment.
|
||||
// The alignment must be a power of 2. Returns alignment - 1, which is
|
||||
// a mask with all bits set below alignment's single bit.
|
||||
template<typename T, ENABLE_IF(std::is_integral<T>::value)>
|
||||
static constexpr T alignment_mask(T alignment) {
|
||||
assert(is_power_of_2(alignment),
|
||||
"must be a power of 2: " UINT64_FORMAT, (uint64_t)alignment);
|
||||
return alignment - 1;
|
||||
}
|
||||
|
||||
template <typename T, typename A>
|
||||
inline T align_down(T size, A alignment) {
|
||||
assert(is_power_of_2(alignment), "must be a power of 2: " UINT64_FORMAT, (uint64_t)alignment);
|
||||
|
||||
T ret = align_down_(size, alignment);
|
||||
assert(is_aligned_(ret, alignment), "must be aligned: " UINT64_FORMAT, (uint64_t)ret);
|
||||
|
||||
return ret;
|
||||
// Some "integral" constant alignments are defined via enum.
|
||||
template<typename T, ENABLE_IF(std::is_enum<T>::value)>
|
||||
static constexpr auto alignment_mask(T alignment) {
|
||||
return alignment_mask(static_cast<std::underlying_type_t<T>>(alignment));
|
||||
}
|
||||
|
||||
template <typename T, typename A>
|
||||
inline bool is_aligned(T size, A alignment) {
|
||||
assert(is_power_of_2(alignment), "must be a power of 2: " UINT64_FORMAT, (uint64_t)alignment);
|
||||
// Align integers and check for alignment.
|
||||
// The is_integral filtering here is not for disambiguation with the T*
|
||||
// overloads; if those match then they are a better match. Rather, the
|
||||
// is_integral filtering is to prevent back-sliding on the use of enums
|
||||
// as "integral" constants that need aligning.
|
||||
|
||||
return is_aligned_(size, alignment);
|
||||
template<typename T, typename A, ENABLE_IF(std::is_integral<T>::value)>
|
||||
constexpr bool is_aligned(T size, A alignment) {
|
||||
return (size & alignment_mask(alignment)) == 0;
|
||||
}
|
||||
|
||||
template<typename T, typename A, ENABLE_IF(std::is_integral<T>::value)>
|
||||
constexpr T align_down(T size, A alignment) {
|
||||
// Convert mask to T before lognot. Otherwise, if alignment is unsigned
|
||||
// and smaller than T, the result of the lognot will be zero-extended
|
||||
// by integral promotion, and upper bits of size will be discarded.
|
||||
T result = size & ~T(alignment_mask(alignment));
|
||||
assert(is_aligned(result, alignment),
|
||||
"must be aligned: " UINT64_FORMAT, (uint64_t)result);
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename T, typename A, ENABLE_IF(std::is_integral<T>::value)>
|
||||
constexpr T align_up(T size, A alignment) {
|
||||
T adjusted = size + alignment_mask(alignment);
|
||||
return align_down(adjusted, alignment);
|
||||
}
|
||||
|
||||
// Align down with a lower bound. If the aligning results in 0, return 'alignment'.
|
||||
template <typename T, typename A>
|
||||
inline T align_down_bounded(T size, A alignment) {
|
||||
A aligned_size = align_down(size, alignment);
|
||||
return aligned_size > 0 ? aligned_size : alignment;
|
||||
constexpr T align_down_bounded(T size, A alignment) {
|
||||
T aligned_size = align_down(size, alignment);
|
||||
return (aligned_size > 0) ? aligned_size : T(alignment);
|
||||
}
|
||||
|
||||
// Helpers to align pointers and check for alignment.
|
||||
// Align pointers and check for alignment.
|
||||
|
||||
template <typename T, typename A>
|
||||
inline T* align_up(T* ptr, A alignment) {
|
||||
@ -122,7 +121,7 @@ inline bool is_object_aligned(const void* addr) {
|
||||
|
||||
// Pad out certain offsets to jlong alignment, in HeapWord units.
|
||||
template <typename T>
|
||||
inline T align_object_offset(T offset) {
|
||||
constexpr T align_object_offset(T offset) {
|
||||
return align_up(offset, HeapWordsPerLong);
|
||||
}
|
||||
|
||||
|
@ -26,16 +26,17 @@
|
||||
#define SHARE_UTILITIES_POWEROFTWO_HPP
|
||||
|
||||
#include "metaprogramming/enableIf.hpp"
|
||||
#include "metaprogramming/isIntegral.hpp"
|
||||
#include "metaprogramming/isSigned.hpp"
|
||||
#include "utilities/count_leading_zeros.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
|
||||
// Power of two convenience library.
|
||||
|
||||
template <typename T>
|
||||
bool is_power_of_2(T x) {
|
||||
// Returns true iff there exists integer i such that (T(1) << i) == x.
|
||||
template <typename T, ENABLE_IF(std::is_integral<T>::value)>
|
||||
constexpr bool is_power_of_2(T x) {
|
||||
return (x > T(0)) && ((x & (x - 1)) == T(0));
|
||||
}
|
||||
|
||||
@ -55,94 +56,36 @@ inline int exact_log2_long(jlong x) {
|
||||
return bits - count_leading_zeros(x) - 1;
|
||||
}
|
||||
|
||||
// Round down to the closest power of two greater to or equal to the given
|
||||
// value.
|
||||
|
||||
// Signed version: 0 is an invalid input, negative values are invalid
|
||||
template <typename T>
|
||||
inline typename EnableIf<IsSigned<T>::value, T>::type round_down_power_of_2(T value) {
|
||||
STATIC_ASSERT(IsIntegral<T>::value);
|
||||
// Round down to the closest power of two less than or equal to the given value.
|
||||
// precondition: value > 0.
|
||||
template<typename T, ENABLE_IF(std::is_integral<T>::value)>
|
||||
inline T round_down_power_of_2(T value) {
|
||||
assert(value > 0, "Invalid value");
|
||||
uint32_t lz = count_leading_zeros(value);
|
||||
assert(lz < sizeof(T) * BitsPerByte, "Sanity");
|
||||
return T(1) << (sizeof(T) * BitsPerByte - 1 - lz);
|
||||
}
|
||||
|
||||
// Unsigned version: 0 is an invalid input
|
||||
template <typename T>
|
||||
inline typename EnableIf<!IsSigned<T>::value, T>::type round_down_power_of_2(T value) {
|
||||
STATIC_ASSERT(IsIntegral<T>::value);
|
||||
assert(value != 0, "Invalid value");
|
||||
uint32_t lz = count_leading_zeros(value);
|
||||
assert(lz < sizeof(T) * BitsPerByte, "Sanity");
|
||||
return T(1) << (sizeof(T) * BitsPerByte - 1 - lz);
|
||||
}
|
||||
|
||||
// Round up to the closest power of two greater to or equal to
|
||||
// the given value.
|
||||
|
||||
// Signed version: 0 is an invalid input, negative values are invalid,
|
||||
// overflows with assert if value is larger than 2^30 or 2^62 for 32- and
|
||||
// 64-bit integers, respectively
|
||||
template <typename T>
|
||||
inline typename EnableIf<IsSigned<T>::value, T>::type round_up_power_of_2(T value) {
|
||||
STATIC_ASSERT(IsIntegral<T>::value);
|
||||
STATIC_ASSERT(IsSigned<T>::value);
|
||||
// Round up to the closest power of two greater to or equal to the given value.
|
||||
// precondition: value > 0.
|
||||
// precondition: value <= maximum power of two representable by T.
|
||||
template<typename T, ENABLE_IF(std::is_integral<T>::value)>
|
||||
inline T round_up_power_of_2(T value) {
|
||||
assert(value > 0, "Invalid value");
|
||||
const T max_value = std::numeric_limits<T>::max();
|
||||
assert(value <= (max_value - (max_value >> 1)), "Overflow");
|
||||
if (is_power_of_2(value)) {
|
||||
return value;
|
||||
}
|
||||
uint32_t lz = count_leading_zeros(value);
|
||||
assert(lz < sizeof(T) * BitsPerByte, "Sanity");
|
||||
assert(lz > 1, "Will overflow");
|
||||
return T(1) << (sizeof(T) * BitsPerByte - lz);
|
||||
}
|
||||
|
||||
// Unsigned version: 0 is an invalid input, overflows with assert if value
|
||||
// is larger than 2^31 or 2^63 for 32- and 64-bit integers, respectively
|
||||
template <typename T>
|
||||
inline typename EnableIf<!IsSigned<T>::value, T>::type round_up_power_of_2(T value) {
|
||||
STATIC_ASSERT(IsIntegral<T>::value);
|
||||
STATIC_ASSERT(!IsSigned<T>::value);
|
||||
assert(value != 0, "Invalid value");
|
||||
if (is_power_of_2(value)) {
|
||||
return value;
|
||||
}
|
||||
uint32_t lz = count_leading_zeros(value);
|
||||
assert(lz < sizeof(T) * BitsPerByte, "Sanity");
|
||||
assert(lz > 0, "Will overflow");
|
||||
return T(1) << (sizeof(T) * BitsPerByte - lz);
|
||||
}
|
||||
|
||||
// Helper function to get the maximum positive value. Implemented here
|
||||
// since using std::numeric_limits<T>::max() seems problematic on some
|
||||
// platforms.
|
||||
|
||||
template <typename T> T max_value() {
|
||||
if (IsSigned<T>::value) {
|
||||
// Highest positive power of two expressible in the type
|
||||
uint64_t val = static_cast<T>(1) << (sizeof(T) * BitsPerByte - 2);
|
||||
// Fill lower bits with ones
|
||||
val |= val >> 1;
|
||||
val |= val >> 2;
|
||||
val |= val >> 4;
|
||||
if (sizeof(T) >= 2) val |= val >> 8;
|
||||
if (sizeof(T) >= 4) val |= val >> 16;
|
||||
if (sizeof(T) == 8) val |= val >> 32;
|
||||
return (T)val;
|
||||
} else {
|
||||
return ~(static_cast<T>(0));
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the next power of two greater than the given value.
|
||||
|
||||
// Accepts 0 (returns 1), overflows with assert if value is larger than
|
||||
// or equal to 2^31 (signed: 2^30) or 2^63 (signed: 2^62), for 32-
|
||||
// and 64-bit integers, respectively
|
||||
template <typename T>
|
||||
// precondition: if signed, value >= 0.
|
||||
// precondition: value < maximum power of two representable by T.
|
||||
template <typename T, ENABLE_IF(std::is_integral<T>::value)>
|
||||
inline T next_power_of_2(T value) {
|
||||
assert(value != max_value<T>(), "Overflow");
|
||||
assert(value < std::numeric_limits<T>::max(), "Overflow");
|
||||
return round_up_power_of_2(value + 1);
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -153,7 +153,7 @@ static intx calc_expected(julong small_xss_input) {
|
||||
assert(small_xss_input <= max_julong / 2, "Sanity");
|
||||
|
||||
// Match code in arguments.cpp
|
||||
julong julong_ret = align_up_(small_xss_input, K) / K;
|
||||
julong julong_ret = align_up(small_xss_input, K) / K;
|
||||
assert(julong_ret <= (julong)max_intx, "Overflow: " JULONG_FORMAT, julong_ret);
|
||||
return (intx)julong_ret;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -25,21 +25,82 @@
|
||||
#include "utilities/align.hpp"
|
||||
#include "utilities/formatBuffer.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
#include <limits>
|
||||
#include "unittest.hpp"
|
||||
|
||||
#include <limits>
|
||||
|
||||
// A few arbitrarily chosen values to test the align functions on.
|
||||
static uint64_t values[] = {1, 3, 10, 345, 1023, 1024, 1025, 23909034, INT_MAX, uint64_t(-1) / 2, uint64_t(-1) / 2 + 100, uint64_t(-1)};
|
||||
static constexpr uint64_t values[] = {1, 3, 10, 345, 1023, 1024, 1025, 23909034, INT_MAX, uint64_t(-1) / 2, uint64_t(-1) / 2 + 100, uint64_t(-1)};
|
||||
|
||||
template <typename T>
|
||||
static T max_alignment() {
|
||||
static constexpr T max_alignment() {
|
||||
T max = std::numeric_limits<T>::max();
|
||||
return max ^ (max >> 1);
|
||||
}
|
||||
|
||||
#define log(...) SCOPED_TRACE(err_msg(__VA_ARGS__).buffer())
|
||||
|
||||
struct StaticTestAlignmentsResult {
|
||||
uint64_t _value;
|
||||
uint64_t _alignment;
|
||||
int _status; // 0: success, > 0 indicates which failure case
|
||||
constexpr StaticTestAlignmentsResult(uint64_t value, uint64_t alignment, int status) :
|
||||
_value(value), _alignment(alignment), _status(status) {}
|
||||
};
|
||||
|
||||
// Structure copied from test_alignments runtime test (below).
|
||||
template<typename T, typename A>
|
||||
static constexpr StaticTestAlignmentsResult
|
||||
static_test_alignments_aux(A alignment) {
|
||||
using Result = StaticTestAlignmentsResult;
|
||||
|
||||
for ( ; alignment > 0; alignment >>= 1) {
|
||||
for (size_t i = 0; i < ARRAY_SIZE(values); ++i) {
|
||||
// Test align up
|
||||
uint64_t up = align_up(values[i], alignment);
|
||||
if (0 < up && up < uint64_t(std::numeric_limits<T>::max())) {
|
||||
T value = T(values[i]);
|
||||
if (align_up(uint64_t(value), alignment) != up) {
|
||||
return Result(values[i], alignment, 1);
|
||||
} else if (align_up(value, alignment) < value) {
|
||||
return Result(values[i], alignment, 2);
|
||||
}
|
||||
}
|
||||
|
||||
// Test align down
|
||||
uint64_t down = align_down(values[i], alignment);
|
||||
if (down <= uint64_t(std::numeric_limits<T>::max())) {
|
||||
T value = T(values[i]);
|
||||
if (uint64_t(align_down(value, alignment)) != down) {
|
||||
return Result(values[i], alignment, 3);
|
||||
} else if (align_down(value, alignment) > value) {
|
||||
return Result(values[i], alignment, 4);
|
||||
}
|
||||
}
|
||||
|
||||
// Test is aligned
|
||||
bool is = is_aligned(values[i], alignment);
|
||||
if (values[i] <= uint64_t(std::numeric_limits<T>::max())) {
|
||||
T value = T(values[i]);
|
||||
if (is_aligned(value, alignment) != is) {
|
||||
return Result(values[i], alignment, 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return Result(T(), A(), 0);
|
||||
}
|
||||
|
||||
template<typename T, typename A>
|
||||
static void static_test_alignments() {
|
||||
constexpr StaticTestAlignmentsResult result
|
||||
= static_test_alignments_aux<T>(max_alignment<A>());
|
||||
|
||||
EXPECT_EQ(0, result._status)
|
||||
<< "value = " << result._value
|
||||
<< ", alignment = " << result._alignment
|
||||
<< ", status = " << result._status;
|
||||
}
|
||||
|
||||
template <typename T, typename A>
|
||||
static void test_alignments() {
|
||||
log("### Test: %c" SIZE_FORMAT " " UINT64_FORMAT " : %c" SIZE_FORMAT " " UINT64_FORMAT " ###\n",
|
||||
@ -54,7 +115,7 @@ static void test_alignments() {
|
||||
log("--- Value: " UINT64_FORMAT "\n", values[i]);
|
||||
|
||||
// Test align up
|
||||
const uint64_t up = align_up_(values[i], (uint64_t)alignment);
|
||||
const uint64_t up = align_up(values[i], alignment);
|
||||
if (0 < up && up <= (uint64_t)std::numeric_limits<T>::max()) {
|
||||
log("Testing align_up: alignment: 0x" UINT64_FORMAT_X " value: 0x" UINT64_FORMAT_X " expected: 0x" UINT64_FORMAT_X "\n", (uint64_t)alignment, values[i], up);
|
||||
|
||||
@ -62,14 +123,12 @@ static void test_alignments() {
|
||||
|
||||
// Check against uint64_t version
|
||||
ASSERT_EQ(align_up((uint64_t)value, alignment), up);
|
||||
// Check inline function vs macro
|
||||
ASSERT_EQ(align_up(value, alignment), align_up_(value, alignment));
|
||||
// Sanity check
|
||||
ASSERT_GE(align_up(value, alignment), value);
|
||||
}
|
||||
|
||||
// Test align down
|
||||
const uint64_t down = align_down_(values[i], (uint64_t)alignment);
|
||||
const uint64_t down = align_down(values[i], alignment);
|
||||
if (down <= (uint64_t)std::numeric_limits<T>::max()) {
|
||||
log("Testing align_down: alignment: 0x" UINT64_FORMAT_X " value: 0x" UINT64_FORMAT_X " expected: 0x" UINT64_FORMAT_X "\n", (uint64_t)alignment, values[i], down);
|
||||
|
||||
@ -77,14 +136,12 @@ static void test_alignments() {
|
||||
|
||||
// Check against uint64_t version
|
||||
ASSERT_EQ((uint64_t)align_down(value, alignment), down);
|
||||
// Check inline function vs macro
|
||||
ASSERT_EQ(align_down(value, alignment), align_down_(value, alignment));
|
||||
// Sanity check
|
||||
ASSERT_LE(align_down(value, alignment), value);
|
||||
}
|
||||
|
||||
// Test is aligned
|
||||
const bool is = is_aligned_(values[i], (uint64_t)alignment);
|
||||
const bool is = is_aligned(values[i], alignment);
|
||||
if (values[i] <= (uint64_t)std::numeric_limits<T>::max()) {
|
||||
log("Testing is_aligned: alignment: 0x" UINT64_FORMAT_X " value: 0x" UINT64_FORMAT_X " expected: %s\n", (uint64_t)alignment, values[i], is ? "true" : "false");
|
||||
|
||||
@ -92,14 +149,14 @@ static void test_alignments() {
|
||||
|
||||
// Check against uint64_t version
|
||||
ASSERT_EQ(is_aligned(value, alignment), is);
|
||||
// Check inline function vs macro
|
||||
ASSERT_EQ(is_aligned(value, alignment), is_aligned_(value, alignment));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static_test_alignments<T, A>();
|
||||
}
|
||||
|
||||
TEST(Align, functions_and_macros) {
|
||||
TEST(Align, alignments) {
|
||||
// Test the alignment functions with different type combinations.
|
||||
|
||||
test_alignments<int64_t, uint8_t>();
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -27,6 +27,7 @@
|
||||
#include "utilities/population_count.hpp"
|
||||
#include "utilities/powerOfTwo.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
#include <limits>
|
||||
#include "unittest.hpp"
|
||||
|
||||
#define BITS_IN_BYTE_ARRAY_SIZE 256
|
||||
@ -51,8 +52,8 @@ const uint8_t test_popcnt_bitsInByte[BITS_IN_BYTE_ARRAY_SIZE] = {
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void sparse() {
|
||||
const T max_val = max_value<T>();
|
||||
static void sparse() {
|
||||
const T max_val = std::numeric_limits<T>::max();
|
||||
|
||||
// Step through the entire input range from a random starting point,
|
||||
// verify population_count return values against the lookup table
|
||||
@ -95,4 +96,4 @@ TEST(population_count, sparse32) {
|
||||
}
|
||||
TEST(population_count, sparse64) {
|
||||
sparse<uint64_t>();
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -25,20 +25,57 @@
|
||||
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
#include "utilities/powerOfTwo.hpp"
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
#include "unittest.hpp"
|
||||
|
||||
template <typename T> T max_pow2() {
|
||||
T max_val = max_value<T>();
|
||||
template <typename T> static constexpr T max_pow2() {
|
||||
T max_val = std::numeric_limits<T>::max();
|
||||
return max_val - (max_val >> 1);
|
||||
}
|
||||
|
||||
struct StaticTestIsPowerOf2Result {
|
||||
uint64_t _value;
|
||||
int _status; // 0: success, > 0 indicates which failure case
|
||||
constexpr StaticTestIsPowerOf2Result(uint64_t value, int status) :
|
||||
_value(value), _status(status) {}
|
||||
};
|
||||
|
||||
// Structure copied from test_is_power_of_2 runtime test (below).
|
||||
template<typename T>
|
||||
static constexpr StaticTestIsPowerOf2Result static_test_is_power_of_2_aux(T v) {
|
||||
using Result = StaticTestIsPowerOf2Result;
|
||||
for ( ; v > 0; v >>= 1) {
|
||||
if (!is_power_of_2(v)) {
|
||||
return Result(v, 1);
|
||||
} else if ((v > 2) && is_power_of_2(T(v - 1))) {
|
||||
return Result(v, 2);
|
||||
} else if ((v > 1) && is_power_of_2(T(v + 1))) {
|
||||
return Result(v, 3);
|
||||
}
|
||||
}
|
||||
return Result(v, 0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void static_test_is_power_of_2() {
|
||||
constexpr StaticTestIsPowerOf2Result result
|
||||
= static_test_is_power_of_2_aux(max_pow2<T>());
|
||||
|
||||
EXPECT_EQ(0, result._status)
|
||||
<< "value = " << result._value << ", status = " << result._status;
|
||||
}
|
||||
|
||||
template <typename T> static void test_is_power_of_2() {
|
||||
EXPECT_FALSE(is_power_of_2(T(0)));
|
||||
EXPECT_FALSE(is_power_of_2(~T(0)));
|
||||
|
||||
if (IsSigned<T>::value) {
|
||||
EXPECT_FALSE(is_power_of_2(std::numeric_limits<T>::min()));
|
||||
}
|
||||
static_assert(!is_power_of_2(T(0)), "");
|
||||
static_assert(!is_power_of_2(~T(0)), "");
|
||||
|
||||
// Should be false regardless of whether T is signed or unsigned.
|
||||
EXPECT_FALSE(is_power_of_2(std::numeric_limits<T>::min()));
|
||||
static_assert(!is_power_of_2(std::numeric_limits<T>::min()), "");
|
||||
|
||||
// Test true
|
||||
for (T i = max_pow2<T>(); i > 0; i = (i >> 1)) {
|
||||
@ -54,6 +91,8 @@ template <typename T> static void test_is_power_of_2() {
|
||||
for (T i = max_pow2<T>(); i > 1; i = (i >> 1)) {
|
||||
EXPECT_FALSE(is_power_of_2(i + 1)) << "value = " << T(i + 1);
|
||||
}
|
||||
|
||||
static_test_is_power_of_2<T>();
|
||||
}
|
||||
|
||||
TEST(power_of_2, is_power_of_2) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user