1 //===-- Memory utils --------------------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef LLVM_LIBC_SRC_MEMORY_UTILS_H 10 #define LLVM_LIBC_SRC_MEMORY_UTILS_H 11 12 #include "src/string/memory_utils/cacheline_size.h" 13 14 #include <stddef.h> // size_t 15 #include <stdint.h> // intptr_t / uintptr_t 16 17 namespace __llvm_libc { 18 19 // Return whether `value` is zero or a power of two. is_power2_or_zero(size_t value)20static constexpr bool is_power2_or_zero(size_t value) { 21 return (value & (value - 1U)) == 0; 22 } 23 24 // Return whether `value` is a power of two. is_power2(size_t value)25static constexpr bool is_power2(size_t value) { 26 return value && is_power2_or_zero(value); 27 } 28 29 // Compile time version of log2 that handles 0. log2(size_t value)30static constexpr size_t log2(size_t value) { 31 return (value == 0 || value == 1) ? 0 : 1 + log2(value / 2); 32 } 33 34 // Returns the first power of two preceding value or value if it is already a 35 // power of two (or 0 when value is 0). le_power2(size_t value)36static constexpr size_t le_power2(size_t value) { 37 return value == 0 ? value : 1ULL << log2(value); 38 } 39 40 // Returns the first power of two following value or value if it is already a 41 // power of two (or 0 when value is 0). ge_power2(size_t value)42static constexpr size_t ge_power2(size_t value) { 43 return is_power2_or_zero(value) ? value : 1ULL << (log2(value) + 1); 44 } 45 offset_from_last_aligned(const void * ptr)46template <size_t alignment> intptr_t offset_from_last_aligned(const void *ptr) { 47 static_assert(is_power2(alignment), "alignment must be a power of 2"); 48 return reinterpret_cast<uintptr_t>(ptr) & (alignment - 1U); 49 } 50 offset_to_next_aligned(const void * ptr)51template <size_t alignment> intptr_t offset_to_next_aligned(const void *ptr) { 52 static_assert(is_power2(alignment), "alignment must be a power of 2"); 53 // The logic is not straightforward and involves unsigned modulo arithmetic 54 // but the generated code is as fast as it can be. 55 return -reinterpret_cast<uintptr_t>(ptr) & (alignment - 1U); 56 } 57 58 // Returns the offset from `ptr` to the next cache line. offset_to_next_cache_line(const void * ptr)59static inline intptr_t offset_to_next_cache_line(const void *ptr) { 60 return offset_to_next_aligned<LLVM_LIBC_CACHELINE_SIZE>(ptr); 61 } 62 63 } // namespace __llvm_libc 64 65 #endif // LLVM_LIBC_SRC_MEMORY_UTILS_H 66