From a3660c40690252e6bab884108f82e1ca822bc458 Mon Sep 17 00:00:00 2001 From: Matthew Parkinson Date: Wed, 27 Jan 2021 11:58:41 +0000 Subject: [PATCH] Update to use a more efficient power of 2 check. (#274) --- src/ds/address.h | 10 +++++----- src/ds/bits.h | 9 +++++++-- src/ds/helpers.h | 3 +-- src/mem/address_space.h | 2 +- src/mem/sizeclass.h | 2 +- src/pal/pal.h | 3 +-- src/pal/pal_bsd_aligned.h | 2 +- src/pal/pal_freebsd_kernel.h | 2 +- src/pal/pal_posix.h | 2 +- src/pal/pal_windows.h | 4 ++-- 10 files changed, 21 insertions(+), 18 deletions(-) diff --git a/src/ds/address.h b/src/ds/address.h index cc73e49..0d829f2 100644 --- a/src/ds/address.h +++ b/src/ds/address.h @@ -49,7 +49,7 @@ namespace snmalloc template static inline bool is_aligned_block(void* p, size_t size) { - static_assert(bits::next_pow2_const(alignment) == alignment); + static_assert(bits::is_pow2(alignment)); return ((address_cast(p) | size) & (alignment - 1)) == 0; } @@ -62,7 +62,7 @@ namespace snmalloc SNMALLOC_FAST_PATH T* pointer_align_down(void* p) { static_assert(alignment > 0); - static_assert(bits::next_pow2_const(alignment) == alignment); + static_assert(bits::is_pow2(alignment)); if constexpr (alignment == 1) return static_cast(p); else @@ -84,7 +84,7 @@ namespace snmalloc inline T* pointer_align_up(void* p) { static_assert(alignment > 0); - static_assert(bits::next_pow2_const(alignment) == alignment); + static_assert(bits::is_pow2(alignment)); if constexpr (alignment == 1) return static_cast(p); else @@ -106,7 +106,7 @@ namespace snmalloc SNMALLOC_FAST_PATH T* pointer_align_down(void* p, size_t alignment) { SNMALLOC_ASSERT(alignment > 0); - SNMALLOC_ASSERT(bits::next_pow2(alignment) == alignment); + SNMALLOC_ASSERT(bits::is_pow2(alignment)); #if __has_builtin(__builtin_align_down) return static_cast(__builtin_align_down(p, alignment)); #else @@ -123,7 +123,7 @@ namespace snmalloc inline T* pointer_align_up(void* p, size_t alignment) { SNMALLOC_ASSERT(alignment > 0); - SNMALLOC_ASSERT(bits::next_pow2(alignment) == alignment); + SNMALLOC_ASSERT(bits::is_pow2(alignment)); #if __has_builtin(__builtin_align_up) return static_cast(__builtin_align_up(p, alignment)); #else diff --git a/src/ds/bits.h b/src/ds/bits.h index b59773c..b8b6e68 100644 --- a/src/ds/bits.h +++ b/src/ds/bits.h @@ -211,6 +211,11 @@ namespace snmalloc #endif } + constexpr SNMALLOC_FAST_PATH bool is_pow2(size_t x) + { + return (x & (x - 1)) == 0; + } + SNMALLOC_FAST_PATH size_t next_pow2(size_t x) { // Correct for numbers [0..MAX_SIZE >> 1). @@ -244,7 +249,7 @@ namespace snmalloc constexpr SNMALLOC_FAST_PATH size_t align_down(size_t value, size_t alignment) { - SNMALLOC_ASSERT(next_pow2_const(alignment) == alignment); + SNMALLOC_ASSERT(is_pow2(alignment)); size_t align_1 = alignment - 1; value &= ~align_1; @@ -253,7 +258,7 @@ namespace snmalloc constexpr SNMALLOC_FAST_PATH size_t align_up(size_t value, size_t alignment) { - SNMALLOC_ASSERT(next_pow2_const(alignment) == alignment); + SNMALLOC_ASSERT(is_pow2(alignment)); size_t align_1 = alignment - 1; value += align_1; diff --git a/src/ds/helpers.h b/src/ds/helpers.h index a042981..159db49 100644 --- a/src/ds/helpers.h +++ b/src/ds/helpers.h @@ -52,8 +52,7 @@ namespace snmalloc template class Mod { - static_assert( - length == bits::next_pow2_const(length), "Must be a power of two."); + static_assert(bits::is_pow2(length), "Must be a power of two."); private: T value = 0; diff --git a/src/mem/address_space.h b/src/mem/address_space.h index 051830b..9ebfbe3 100644 --- a/src/mem/address_space.h +++ b/src/mem/address_space.h @@ -175,7 +175,7 @@ namespace snmalloc template void* reserve(size_t size) { - SNMALLOC_ASSERT(bits::next_pow2(size) == size); + SNMALLOC_ASSERT(bits::is_pow2(size)); SNMALLOC_ASSERT(size >= sizeof(void*)); if constexpr (pal_supports) diff --git a/src/mem/sizeclass.h b/src/mem/sizeclass.h index 0d39db3..f9c996f 100644 --- a/src/mem/sizeclass.h +++ b/src/mem/sizeclass.h @@ -183,7 +183,7 @@ namespace snmalloc // Client responsible for checking alignment is not zero SNMALLOC_ASSERT(alignment != 0); // Client responsible for checking alignment is a power of two - SNMALLOC_ASSERT(bits::next_pow2(alignment) == alignment); + SNMALLOC_ASSERT(bits::is_pow2(alignment)); return ((alignment - 1) | (size - 1)) + 1; } diff --git a/src/pal/pal.h b/src/pal/pal.h index 7a99e42..b112c94 100644 --- a/src/pal/pal.h +++ b/src/pal/pal.h @@ -76,8 +76,7 @@ namespace snmalloc static constexpr size_t OS_PAGE_SIZE = Pal::page_size; static_assert( - bits::next_pow2_const(OS_PAGE_SIZE) == OS_PAGE_SIZE, - "OS_PAGE_SIZE must be a power of two"); + bits::is_pow2(OS_PAGE_SIZE), "OS_PAGE_SIZE must be a power of two"); static_assert( OS_PAGE_SIZE % Aal::smallest_page_size == 0, "The smallest architectural page size must divide OS_PAGE_SIZE"); diff --git a/src/pal/pal_bsd_aligned.h b/src/pal/pal_bsd_aligned.h index 1d2c515..bb26b07 100644 --- a/src/pal/pal_bsd_aligned.h +++ b/src/pal/pal_bsd_aligned.h @@ -32,7 +32,7 @@ namespace snmalloc static void* reserve_aligned(size_t size) noexcept { // Alignment must be a power of 2. - SNMALLOC_ASSERT(size == bits::next_pow2(size)); + SNMALLOC_ASSERT(bits::is_pow2(size)); SNMALLOC_ASSERT(size >= minimum_alloc_size); size_t log2align = bits::next_pow2_bits(size); diff --git a/src/pal/pal_freebsd_kernel.h b/src/pal/pal_freebsd_kernel.h index 7bab485..084b38b 100644 --- a/src/pal/pal_freebsd_kernel.h +++ b/src/pal/pal_freebsd_kernel.h @@ -62,7 +62,7 @@ namespace snmalloc template static void* reserve_aligned(size_t size) noexcept { - SNMALLOC_ASSERT(size == bits::next_pow2(size)); + SNMALLOC_ASSERT(bits::is_pow2(size)); SNMALLOC_ASSERT(size >= minimum_alloc_size); size_t align = size; diff --git a/src/pal/pal_posix.h b/src/pal/pal_posix.h index db9981f..cca67a6 100644 --- a/src/pal/pal_posix.h +++ b/src/pal/pal_posix.h @@ -212,7 +212,7 @@ namespace snmalloc */ static std::pair reserve_at_least(size_t size) noexcept { - SNMALLOC_ASSERT(size == bits::next_pow2(size)); + SNMALLOC_ASSERT(bits::is_pow2(size)); // Magic number for over-allocating chosen by the Pal // These should be further refined based on experiments. diff --git a/src/pal/pal_windows.h b/src/pal/pal_windows.h index 39e0556..bd53d10 100644 --- a/src/pal/pal_windows.h +++ b/src/pal/pal_windows.h @@ -185,7 +185,7 @@ namespace snmalloc template static void* reserve_aligned(size_t size) noexcept { - SNMALLOC_ASSERT(size == bits::next_pow2(size)); + SNMALLOC_ASSERT(bits::is_pow2(size)); SNMALLOC_ASSERT(size >= minimum_alloc_size); DWORD flags = MEM_RESERVE; @@ -215,7 +215,7 @@ namespace snmalloc # else static std::pair reserve_at_least(size_t size) noexcept { - SNMALLOC_ASSERT(size == bits::next_pow2(size)); + SNMALLOC_ASSERT(bits::is_pow2(size)); // Magic number for over-allocating chosen by the Pal // These should be further refined based on experiments.