-
Notifications
You must be signed in to change notification settings - Fork 14.6k
[libc++] Implement P2897R7 aligned_accessor: An mdspan accessor expressing pointer over-alignment #122603
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[libc++] Implement P2897R7 aligned_accessor: An mdspan accessor expressing pointer over-alignment #122603
Changes from all commits
2766103
e36bc1c
1c57f20
68ea167
1db762c
625a421
d2eccee
64f14e7
baefcf9
47d3c56
eda7039
2cd1d28
8376d2f
a863a60
80e4a2d
4abd141
70f331a
ac9792a
c3dfcda
14c4606
a55bef7
9b5ef48
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
// -*- C++ -*- | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
// See https://llvm.org/LICENSE.txt for license information. | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
// | ||
// Kokkos v. 4.0 | ||
// Copyright (2022) National Technology & Engineering | ||
// Solutions of Sandia, LLC (NTESS). | ||
// | ||
// Under the terms of Contract DE-NA0003525 with NTESS, | ||
// the U.S. Government retains certain rights in this software. | ||
// | ||
//===---------------------------------------------------------------------===// | ||
|
||
#ifndef _LIBCPP___MDSPAN_ALIGNED_ACCESSOR_H | ||
#define _LIBCPP___MDSPAN_ALIGNED_ACCESSOR_H | ||
|
||
#include <__config> | ||
#include <__cstddef/size_t.h> | ||
dalg24 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
#include <__mdspan/default_accessor.h> | ||
#include <__memory/assume_aligned.h> | ||
#include <__type_traits/is_abstract.h> | ||
#include <__type_traits/is_array.h> | ||
#include <__type_traits/is_convertible.h> | ||
#include <__type_traits/remove_const.h> | ||
|
||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) | ||
# pragma GCC system_header | ||
#endif | ||
|
||
_LIBCPP_PUSH_MACROS | ||
#include <__undef_macros> | ||
|
||
_LIBCPP_BEGIN_NAMESPACE_STD | ||
|
||
#if _LIBCPP_STD_VER >= 26 | ||
|
||
template <class _ElementType, size_t _ByteAlignment> | ||
struct aligned_accessor { | ||
static_assert(_ByteAlignment != 0 && (_ByteAlignment & (_ByteAlignment - 1)) == 0, | ||
"aligned_accessor: byte alignment must be a power of two"); | ||
static_assert(_ByteAlignment >= alignof(_ElementType), "aligned_accessor: insufficient byte alignment"); | ||
static_assert(!is_array_v<_ElementType>, "aligned_accessor: template argument may not be an array type"); | ||
static_assert(!is_abstract_v<_ElementType>, "aligned_accessor: template argument may not be an abstract class"); | ||
|
||
using offset_policy = default_accessor<_ElementType>; | ||
using element_type = _ElementType; | ||
using reference = _ElementType&; | ||
using data_handle_type = _ElementType*; | ||
|
||
static constexpr size_t byte_alignment = _ByteAlignment; | ||
|
||
_LIBCPP_HIDE_FROM_ABI constexpr aligned_accessor() noexcept = default; | ||
|
||
template <class _OtherElementType, size_t _OtherByteAlignment> | ||
requires(is_convertible_v<_OtherElementType (*)[], element_type (*)[]> && _OtherByteAlignment >= byte_alignment) | ||
_LIBCPP_HIDE_FROM_ABI constexpr aligned_accessor(aligned_accessor<_OtherElementType, _OtherByteAlignment>) noexcept {} | ||
|
||
template <class _OtherElementType> | ||
requires(is_convertible_v<_OtherElementType (*)[], element_type (*)[]>) | ||
_LIBCPP_HIDE_FROM_ABI explicit constexpr aligned_accessor(default_accessor<_OtherElementType>) noexcept {} | ||
|
||
template <class _OtherElementType> | ||
requires(is_convertible_v<element_type (*)[], _OtherElementType (*)[]>) | ||
_LIBCPP_HIDE_FROM_ABI constexpr operator default_accessor<_OtherElementType>() const noexcept { | ||
return {}; | ||
} | ||
|
||
_LIBCPP_HIDE_FROM_ABI constexpr reference access(data_handle_type __p, size_t __i) const noexcept { | ||
return std::assume_aligned<byte_alignment>(__p)[__i]; | ||
} | ||
|
||
_LIBCPP_HIDE_FROM_ABI constexpr typename offset_policy::data_handle_type | ||
offset(data_handle_type __p, size_t __i) const noexcept { | ||
return std::assume_aligned<byte_alignment>(__p) + __i; | ||
} | ||
}; | ||
|
||
#endif // _LIBCPP_STD_VER >= 26 | ||
|
||
_LIBCPP_END_NAMESPACE_STD | ||
|
||
_LIBCPP_POP_MACROS | ||
|
||
#endif // _LIBCPP___MDSPAN_ALIGNED_ACCESSOR_H |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
// -*- C++ -*- | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
// See https://llvm.org/LICENSE.txt for license information. | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#ifndef _LIBCPP___MEMORY_IS_SUFFICIENTLY_ALIGNED_H | ||
#define _LIBCPP___MEMORY_IS_SUFFICIENTLY_ALIGNED_H | ||
|
||
#include <__config> | ||
#include <__cstddef/size_t.h> | ||
#include <cstdint> | ||
|
||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) | ||
# pragma GCC system_header | ||
#endif | ||
|
||
_LIBCPP_BEGIN_NAMESPACE_STD | ||
|
||
#if _LIBCPP_STD_VER >= 26 | ||
|
||
template <size_t _Alignment, class _Tp> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we can just add this to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't have a very strong preference, but IMO it makes more sense to leave it in a separate header since they're really different functionality, even though both relate to "alignment stuff". Not a strong opinion either way, I'd let the author decide on this one. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My slight preference is to keep it in a separate header. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think they're just related as "alignment stuff". There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I don't know that it is implementable. How would you check alignment in a constant expression? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ack, I also don't see how this can be implemented inside a constant expression. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. https://godbolt.org/z/7xGqasbGz is one implementation. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
That's only the implementation for constant evaluation. You need a separate one for the runtime. |
||
_LIBCPP_HIDE_FROM_ABI bool is_sufficiently_aligned(_Tp* __ptr) { | ||
return reinterpret_cast<uintptr_t>(__ptr) % _Alignment == 0; | ||
} | ||
|
||
#endif // _LIBCPP_STD_VER >= 26 | ||
|
||
_LIBCPP_END_NAMESPACE_STD | ||
|
||
#endif // _LIBCPP___MEMORY_IS_SUFFICIENTLY_ALIGNED_H |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
// | ||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
// See https://llvm.org/LICENSE.txt for license information. | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23 | ||
|
||
// <mdspan> | ||
|
||
// template<class ElementType, size_t ByteAlignment> | ||
// class aligned_accessor; | ||
|
||
// ByteAlignement is required to be a power of two and greater or equal to alignof(ElementType). | ||
|
||
#include <mdspan> | ||
|
||
void not_power_of_two() { | ||
// expected-error-re@*:* {{static assertion failed {{.*}}aligned_accessor: byte alignment must be a power of two}} | ||
[[maybe_unused]] std::aligned_accessor<int, 12> acc; | ||
} | ||
|
||
struct alignas(8) S {}; | ||
|
||
void insufficiently_aligned() { | ||
// expected-error-re@*:* {{static assertion failed {{.*}}aligned_accessor: insufficient byte alignment}} | ||
[[maybe_unused]] std::aligned_accessor<S, 4> acc; | ||
} |
Uh oh!
There was an error while loading. Please reload this page.