166d00febSPaula Toth //===-- Memory utils --------------------------------------------*- C++ -*-===// 285314e9bSGuillaume Chatelet // 385314e9bSGuillaume Chatelet // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 485314e9bSGuillaume Chatelet // See https://llvm.org/LICENSE.txt for license information. 585314e9bSGuillaume Chatelet // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 685314e9bSGuillaume Chatelet // 785314e9bSGuillaume Chatelet //===----------------------------------------------------------------------===// 885314e9bSGuillaume Chatelet 95f0800ccSSiva Chandra Reddy #ifndef LLVM_LIBC_SRC_MEMORY_UTILS_UTILS_H 105f0800ccSSiva Chandra Reddy #define LLVM_LIBC_SRC_MEMORY_UTILS_UTILS_H 1185314e9bSGuillaume Chatelet 120aea170bSGuillaume Chatelet #include "src/__support/architectures.h" 130aea170bSGuillaume Chatelet 145f0800ccSSiva Chandra Reddy // Cache line sizes for ARM: These values are not strictly correct since 155f0800ccSSiva Chandra Reddy // cache line sizes depend on implementations, not architectures. There 165f0800ccSSiva Chandra Reddy // are even implementations with cache line sizes configurable at boot 175f0800ccSSiva Chandra Reddy // time. 180aea170bSGuillaume Chatelet #if defined(LLVM_LIBC_ARCH_AARCH64) || defined(LLVM_LIBC_ARCH_X86) 195f0800ccSSiva Chandra Reddy #define LLVM_LIBC_CACHELINE_SIZE 64 20*66a6c107SSiva Chandra Reddy #elif defined(LLVM_LIBC_ARCH_ARM) 21*66a6c107SSiva Chandra Reddy #define LLVM_LIBC_CACHELINE_SIZE 32 225f0800ccSSiva Chandra Reddy #else 235f0800ccSSiva Chandra Reddy #error "Unsupported platform for memory functions." 245f0800ccSSiva Chandra Reddy #endif 2585314e9bSGuillaume Chatelet 2685314e9bSGuillaume Chatelet #include <stddef.h> // size_t 2785314e9bSGuillaume Chatelet #include <stdint.h> // intptr_t / uintptr_t 2885314e9bSGuillaume Chatelet 2985314e9bSGuillaume Chatelet namespace __llvm_libc { 3085314e9bSGuillaume Chatelet 3185314e9bSGuillaume Chatelet // Return whether `value` is zero or a power of two. is_power2_or_zero(size_t value)3285314e9bSGuillaume Chateletstatic constexpr bool is_power2_or_zero(size_t value) { 3385314e9bSGuillaume Chatelet return (value & (value - 1U)) == 0; 3485314e9bSGuillaume Chatelet } 3585314e9bSGuillaume Chatelet 3685314e9bSGuillaume Chatelet // Return whether `value` is a power of two. is_power2(size_t value)3785314e9bSGuillaume Chateletstatic constexpr bool is_power2(size_t value) { 3885314e9bSGuillaume Chatelet return value && is_power2_or_zero(value); 3985314e9bSGuillaume Chatelet } 4085314e9bSGuillaume Chatelet 4185314e9bSGuillaume Chatelet // Compile time version of log2 that handles 0. log2(size_t value)4285314e9bSGuillaume Chateletstatic constexpr size_t log2(size_t value) { 4385314e9bSGuillaume Chatelet return (value == 0 || value == 1) ? 0 : 1 + log2(value / 2); 4485314e9bSGuillaume Chatelet } 4585314e9bSGuillaume Chatelet 4685314e9bSGuillaume Chatelet // Returns the first power of two preceding value or value if it is already a 4785314e9bSGuillaume Chatelet // power of two (or 0 when value is 0). le_power2(size_t value)4885314e9bSGuillaume Chateletstatic constexpr size_t le_power2(size_t value) { 4985314e9bSGuillaume Chatelet return value == 0 ? value : 1ULL << log2(value); 5085314e9bSGuillaume Chatelet } 5185314e9bSGuillaume Chatelet 5285314e9bSGuillaume Chatelet // Returns the first power of two following value or value if it is already a 5385314e9bSGuillaume Chatelet // power of two (or 0 when value is 0). ge_power2(size_t value)5485314e9bSGuillaume Chateletstatic constexpr size_t ge_power2(size_t value) { 5585314e9bSGuillaume Chatelet return is_power2_or_zero(value) ? value : 1ULL << (log2(value) + 1); 5685314e9bSGuillaume Chatelet } 5785314e9bSGuillaume Chatelet offset_from_last_aligned(const void * ptr)5804a309ddSGuillaume Chatelettemplate <size_t alignment> intptr_t offset_from_last_aligned(const void *ptr) { 5904a309ddSGuillaume Chatelet static_assert(is_power2(alignment), "alignment must be a power of 2"); 6004a309ddSGuillaume Chatelet return reinterpret_cast<uintptr_t>(ptr) & (alignment - 1U); 6104a309ddSGuillaume Chatelet } 6204a309ddSGuillaume Chatelet offset_to_next_aligned(const void * ptr)6385314e9bSGuillaume Chatelettemplate <size_t alignment> intptr_t offset_to_next_aligned(const void *ptr) { 6485314e9bSGuillaume Chatelet static_assert(is_power2(alignment), "alignment must be a power of 2"); 6585314e9bSGuillaume Chatelet // The logic is not straightforward and involves unsigned modulo arithmetic 6685314e9bSGuillaume Chatelet // but the generated code is as fast as it can be. 6785314e9bSGuillaume Chatelet return -reinterpret_cast<uintptr_t>(ptr) & (alignment - 1U); 6885314e9bSGuillaume Chatelet } 6985314e9bSGuillaume Chatelet 7085314e9bSGuillaume Chatelet // Returns the offset from `ptr` to the next cache line. offset_to_next_cache_line(const void * ptr)7104a309ddSGuillaume Chateletstatic inline intptr_t offset_to_next_cache_line(const void *ptr) { 7285314e9bSGuillaume Chatelet return offset_to_next_aligned<LLVM_LIBC_CACHELINE_SIZE>(ptr); 7385314e9bSGuillaume Chatelet } 7485314e9bSGuillaume Chatelet assume_aligned(T * ptr)755bf47e14SGuillaume Chatelettemplate <size_t alignment, typename T> static T *assume_aligned(T *ptr) { 765bf47e14SGuillaume Chatelet return reinterpret_cast<T *>(__builtin_assume_aligned(ptr, alignment)); 775bf47e14SGuillaume Chatelet } 785bf47e14SGuillaume Chatelet 7985314e9bSGuillaume Chatelet } // namespace __llvm_libc 8085314e9bSGuillaume Chatelet 815f0800ccSSiva Chandra Reddy #endif // LLVM_LIBC_SRC_MEMORY_UTILS_UTILS_H 82