1 // Copyright 2023 The Pigweed Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not 4 // use this file except in compliance with the License. You may obtain a copy of 5 // the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 // License for the specific language governing permissions and limitations under 13 // the License. 14 #pragma once 15 16 // todo-check: ignore 17 // TODO(fxbug.dev/120998): Once this bug is addressed, this module can likely 18 // be removed and we could just inline the using statements. 19 20 #include <atomic> 21 #include <limits> 22 #include <type_traits> 23 24 namespace pw { 25 26 #if __cplusplus >= 202002L 27 using bit_ceil = std::bit_ceil; 28 #else 29 constexpr size_t countl_zero(size_t x) noexcept { 30 size_t size_digits = std::numeric_limits<size_t>::digits; 31 32 if (sizeof(x) <= sizeof(unsigned int)) 33 return __builtin_clz(static_cast<unsigned int>(x)) - 34 (std::numeric_limits<unsigned int>::digits - size_digits); 35 36 if (sizeof(x) <= sizeof(unsigned long)) 37 return __builtin_clzl(static_cast<unsigned long>(x)) - 38 (std::numeric_limits<unsigned long>::digits - size_digits); 39 40 static_assert(sizeof(x) <= sizeof(unsigned long long)); 41 return __builtin_clzll(static_cast<unsigned long long>(x)) - 42 (std::numeric_limits<unsigned long long>::digits - size_digits); 43 } 44 45 constexpr size_t bit_width(size_t x) noexcept { 46 return std::numeric_limits<size_t>::digits - countl_zero(x); 47 } 48 49 constexpr size_t bit_ceil(size_t x) noexcept { 50 if (x == 0) 51 return 1; 52 return size_t{1} << bit_width(size_t{x - 1}); 53 } 54 #endif 55 56 // The NaturallyAligned class is a wrapper class for ensuring the object is 57 // aligned to a power of 2 bytes greater than or equal to its size. 58 template <typename T> 59 struct [[gnu::aligned(bit_ceil(sizeof(T)))]] NaturallyAligned NaturallyAlignedNaturallyAligned60 : public T{NaturallyAligned() : T(){} NaturallyAligned(const T& t) : 61 T(t){} template <class U> 62 NaturallyAligned(const U& u) : T(u){} NaturallyAligned 63 operator=(T other){return T::operator=(other); 64 } // namespace pw 65 } 66 ; 67 68 // This is a convenience wrapper for ensuring the object held by std::atomic is 69 // naturally aligned. Ensuring the underlying objects's alignment is natural 70 // allows clang to replace libcalls to atomic functions 71 // (__atomic_load/store/exchange/etc) with native instructions when appropriate. 72 // 73 // Example usage: 74 // 75 // // Here std::optional<bool> has a size of 2 but alignment of 1, which would 76 // // normally lower to an __atomic_* libcall, but pw::NaturallyAligned in 77 // // std::atomic tells the compiler to align the object to 2 bytes, which 78 // // satisfies the requirements for replacing __atomic_* with instructions. 79 // pw::AlignedAtomic<std::optional<bool>> mute_enable{}; 80 // 81 template <typename T> 82 using AlignedAtomic = std::atomic<NaturallyAligned<T>>; 83 84 } // namespace pw 85