// Copyright 2020 Google LLC // SPDX-License-Identifier: Apache-2.0 // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef HIGHWAY_HWY_ALIGNED_ALLOCATOR_H_ #define HIGHWAY_HWY_ALIGNED_ALLOCATOR_H_ // Memory allocator with support for alignment and offsets. #include <algorithm> #include <array> #include <cassert> #include <cstdint> #include <cstring> #include <initializer_list> #include <memory> #include <type_traits> #include <utility> #include <vector> #include "hwy/base.h" #include "hwy/per_target.h" namespace hwy { // Minimum alignment of allocated memory for use in HWY_ASSUME_ALIGNED, which // requires a literal. To prevent false sharing, this should be at least the // L1 cache line size, usually 64 bytes. However, Intel's L2 prefetchers may // access pairs of lines, and M1 L2 and POWER8 lines are also 128 bytes. #define HWY_ALIGNMENT … template <typename T> HWY_API constexpr bool IsAligned(T* ptr, size_t align = HWY_ALIGNMENT) { … } // Pointers to functions equivalent to malloc/free with an opaque void* passed // to them. AllocPtr; FreePtr; // Returns null or a pointer to at least `payload_size` (which can be zero) // bytes of newly allocated memory, aligned to the larger of HWY_ALIGNMENT and // the vector size. Calls `alloc` with the passed `opaque` pointer to obtain // memory or malloc() if it is null. HWY_DLLEXPORT void* AllocateAlignedBytes(size_t payload_size, AllocPtr alloc_ptr = nullptr, void* opaque_ptr = nullptr); // Frees all memory. No effect if `aligned_pointer` == nullptr, otherwise it // must have been returned from a previous call to `AllocateAlignedBytes`. // Calls `free_ptr` with the passed `opaque_ptr` pointer to free the memory; if // `free_ptr` function is null, uses the default free(). HWY_DLLEXPORT void FreeAlignedBytes(const void* aligned_pointer, FreePtr free_ptr, void* opaque_ptr); // Class that deletes the aligned pointer passed to operator() calling the // destructor before freeing the pointer. This is equivalent to the // std::default_delete but for aligned objects. For a similar deleter equivalent // to free() for aligned memory see AlignedFreer(). class AlignedDeleter { … }; // Unique pointer to T with custom aligned deleter. This can be a single // element U or an array of element if T is a U[]. The custom aligned deleter // will call the destructor on U or each element of a U[] in the array case. AlignedUniquePtr; // Aligned memory equivalent of make_unique<T> using the custom allocators // alloc/free with the passed `opaque` pointer. This function calls the // constructor with the passed Args... and calls the destructor of the object // when the AlignedUniquePtr is destroyed. template <typename T, typename... Args> AlignedUniquePtr<T> MakeUniqueAlignedWithAlloc(AllocPtr alloc, FreePtr free, void* opaque, Args&&... args) { … } // Similar to MakeUniqueAlignedWithAlloc but using the default alloc/free // functions. template <typename T, typename... Args> AlignedUniquePtr<T> MakeUniqueAligned(Args&&... args) { … } template <class T> struct AlignedAllocator { … }; template <class T, class V> constexpr bool operator==(const AlignedAllocator<T>&, const AlignedAllocator<V>&) noexcept { … } template <class T, class V> constexpr bool operator!=(const AlignedAllocator<T>&, const AlignedAllocator<V>&) noexcept { … } AlignedVector; // Helpers for array allocators (avoids overflow) namespace detail { // Returns x such that 1u << x == n (if n is a power of two). static inline constexpr size_t ShiftCount(size_t n) { … } template <typename T> T* AllocateAlignedItems(size_t items, AllocPtr alloc_ptr, void* opaque_ptr) { … } } // namespace detail // Aligned memory equivalent of make_unique<T[]> for array types using the // custom allocators alloc/free. This function calls the constructor with the // passed Args... on every created item. The destructor of each element will be // called when the AlignedUniquePtr is destroyed. template <typename T, typename... Args> AlignedUniquePtr<T[]> MakeUniqueAlignedArrayWithAlloc( size_t items, AllocPtr alloc, FreePtr free, void* opaque, Args&&... args) { … } template <typename T, typename... Args> AlignedUniquePtr<T[]> MakeUniqueAlignedArray(size_t items, Args&&... args) { … } // Custom deleter for std::unique_ptr equivalent to using free() as a deleter // but for aligned memory. class AlignedFreer { … }; // Unique pointer to single POD, or (if T is U[]) an array of POD. For non POD // data use AlignedUniquePtr. AlignedFreeUniquePtr; // Allocate an aligned and uninitialized array of POD values as a unique_ptr. // Upon destruction of the unique_ptr the aligned array will be freed. template <typename T> AlignedFreeUniquePtr<T[]> AllocateAligned(const size_t items, AllocPtr alloc, FreePtr free, void* opaque) { … } // Same as previous AllocateAligned(), using default allocate/free functions. template <typename T> AlignedFreeUniquePtr<T[]> AllocateAligned(const size_t items) { … } // A simple span containing data and size of data. template <typename T> class Span { … }; // A multi dimensional array containing an aligned buffer. // // To maintain alignment, the innermost dimension will be padded to ensure all // innermost arrays are aligned. template <typename T, size_t axes> class AlignedNDArray { … }; } // namespace hwy #endif // HIGHWAY_HWY_ALIGNED_ALLOCATOR_H_