Index: include/__config =================================================================== --- include/__config +++ include/__config @@ -489,6 +489,10 @@ #define _LIBCPP_HAS_NO_CXX20_CHRONO_LITERALS #endif +#if __has_builtin(__builtin_assume_aligned) +#define _LIBCPP_HAS_BUILTIN_ASSUME_ALIGNED +#endif + #elif defined(_LIBCPP_COMPILER_GCC) #define _ALIGNAS(x) __attribute__((__aligned__(x))) @@ -571,6 +575,8 @@ #define _LIBCPP_HAS_UNIQUE_OBJECT_REPRESENTATIONS #endif +#define _LIBCPP_HAS_BUILTIN_ASSUME_ALIGNED + #define _LIBCPP_ALWAYS_INLINE __attribute__ ((__always_inline__)) #elif defined(_LIBCPP_COMPILER_MSVC) Index: include/memory =================================================================== --- include/memory +++ include/memory @@ -645,6 +645,10 @@ void* align(size_t alignment, size_t size, void*& ptr, size_t& space); +// [ptr.aligned], pointer alignment hint +template + [[nodiscard]] constexpr T* assume_aligned(T* ptr); // C++20 + } // std */ @@ -5581,6 +5585,20 @@ _LIBCPP_FUNC_VIS void* align(size_t __align, size_t __sz, void*& __ptr, size_t& __space); +#if _LIBCPP_STD_VER > 17 +template +_LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY +constexpr _Tp* assume_aligned(_Tp * __p) noexcept +{ +#ifdef _LIBCPP_HAS_BUILTIN_ASSUME_ALIGNED +// return __builtin_assume_aligned(__p, _Sz); + return reinterpret_cast<_Tp*>(__builtin_assume_aligned(__p, _Sz)); +#else + return __p; +#endif +} +#endif // _LIBCPP_STD_VER > 17 + // --- Helper for container swap -- template inline _LIBCPP_INLINE_VISIBILITY Index: test/std/utilities/memory/ptr.align/assume_aligned.fail.cpp =================================================================== --- test/std/utilities/memory/ptr.align/assume_aligned.fail.cpp +++ test/std/utilities/memory/ptr.align/assume_aligned.fail.cpp @@ -0,0 +1,25 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17 + +// #include + +// template +// [[nodiscard]] constexpr T* assume_aligned(T* ptr); + +#include +#include + +#include "test_macros.h" + +int main () +{ + int *p = nullptr; + std::assume_aligned(p, 4); // expected-error {{ignoring return value of function declared with 'nodiscard' attribute}} +} Index: test/std/utilities/memory/ptr.align/assume_aligned.pass.cpp =================================================================== --- test/std/utilities/memory/ptr.align/assume_aligned.pass.cpp +++ test/std/utilities/memory/ptr.align/assume_aligned.pass.cpp @@ -0,0 +1,123 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17 + +// #include + +// template +// [[nodiscard]] constexpr T* assume_aligned(T* ptr); + +#include +#include + +#include "test_macros.h" + +template +constexpr bool is_aligned(T* p, size_t n) +{ return (reinterpret_cast(p) & ((1 << n) - 1)) == 0; } + +template +void test(T *p) +{ + ASSERT_SAME_TYPE(T*, decltype(std::assume_aligned<1, T>(p))); + LIBCPP_ASSERT_NOEXCEPT( std::assume_aligned<1, T>(p)); + assert((p == std::assume_aligned<1>(p))); + + if (is_aligned(p, 2)) + assert((p == std::assume_aligned< 2>(p))); + if (is_aligned(p, 4)) + assert((p == std::assume_aligned< 4>(p))); + if (is_aligned(p, 8)) + assert((p == std::assume_aligned< 8>(p))); + if (is_aligned(p, 16)) + assert((p == std::assume_aligned< 16>(p))); + if (is_aligned(p, 32)) + assert((p == std::assume_aligned< 32>(p))); + if (is_aligned(p, 64)) + assert((p == std::assume_aligned< 64>(p))); + if (is_aligned(p, 128)) + assert((p == std::assume_aligned<128>(p))); +} + +template +constexpr bool constexpr_test(T *p) +{ + ASSERT_SAME_TYPE(T*, decltype(std::assume_aligned<1, T>(p))); + size_t al = alignof(T); + if (p != std::assume_aligned<1>(p)) return false; + if (al >= 2) + if (p != std::assume_aligned<2>(p)) return false; + if (al >= 2) + if (p != std::assume_aligned<2>(p)) return false; + if (al >= 4) + if (p != std::assume_aligned<4>(p)) return false; + if (al >= 8) + if (p != std::assume_aligned<8>(p)) return false; + if (al >= 16) + if (p != std::assume_aligned<16>(p)) return false; + if (al >= 32) + if (p != std::assume_aligned<32>(p)) return false; + if (al >= 64) + if (p != std::assume_aligned<64>(p)) return false; + if (al >= 128) + if (p != std::assume_aligned<128>(p)) return false; + return true; +} + +int i; +long l; +double d; +long double ld; + +struct S {}; +struct alignas( 4) S4 {}; +struct alignas( 8) S8 {}; +struct alignas( 16) S16 {}; +struct alignas( 32) S32 {}; +struct alignas( 64) S64 {}; +struct alignas(128) S128 {}; + +S s; +S4 s4; +S8 s8; +S16 s16; +S32 s32; +S64 s64; +S128 s128; + + +int main () +{ + + test( &i); + test( &l); + test( &d); + test(&ld); + + test(&s); + test(&s4); + test(&s8); + test(&s16); + test(&s32); + test(&s64); + test(&s128); + +// static_assert(constexpr_test( &i), ""); +// static_assert(constexpr_test( &l), ""); +// static_assert(constexpr_test( &d), ""); +// static_assert(constexpr_test(&ld), ""); +// +// static_assert(constexpr_test( &s), ""); +// static_assert(constexpr_test( &s4), ""); +// static_assert(constexpr_test( &s8), ""); +// static_assert(constexpr_test( &s16), ""); +// static_assert(constexpr_test( &s32), ""); +// static_assert(constexpr_test( &s64), ""); +// static_assert(constexpr_test(&s128), ""); +}