Skip to content

Commit c292b60

Browse files
committed
[libc++] Implement P1007R3: std::assume_aligned
This supersedes and incoroporates content from both D108906 and D54966, and also some original content. Co-Authored-by: Marshall Clow <[email protected]> Co-Authored-by: Gonzalo Brito Gadeschi Differential Revision: https://reviews.llvm.org/D118938
1 parent 42229b9 commit c292b60

File tree

14 files changed

+219
-49
lines changed

14 files changed

+219
-49
lines changed

libcxx/docs/FeatureTestMacroTable.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ Status
170170
-------------------------------------------------------------------
171171
``__cpp_lib_array_constexpr`` ``201811L``
172172
------------------------------------------------- -----------------
173-
``__cpp_lib_assume_aligned`` *unimplemented*
173+
``__cpp_lib_assume_aligned`` ``201811L``
174174
------------------------------------------------- -----------------
175175
``__cpp_lib_atomic_flag_test`` ``201907L``
176176
------------------------------------------------- -----------------

libcxx/docs/Status/Cxx20Papers.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@
6666
"`P0919R3 <https://wg21.link/P0919R3>`__","LWG","Heterogeneous lookup for unordered containers","San Diego","|Complete|","12.0"
6767
"`P0972R0 <https://wg21.link/P0972R0>`__","LWG","<chrono> ``zero()``\ , ``min()``\ , and ``max()``\ should be noexcept","San Diego","|Complete|","8.0"
6868
"`P1006R1 <https://wg21.link/P1006R1>`__","LWG","Constexpr in std::pointer_traits","San Diego","|Complete|","8.0"
69-
"`P1007R3 <https://wg21.link/P1007R3>`__","LWG","``std::assume_aligned``\ ","San Diego","* *",""
69+
"`P1007R3 <https://wg21.link/P1007R3>`__","LWG","``std::assume_aligned``\ ","San Diego","|Complete|","15.0"
7070
"`P1020R1 <https://wg21.link/P1020R1>`__","LWG","Smart pointer creation with default initialization","San Diego","* *",""
7171
"`P1032R1 <https://wg21.link/P1032R1>`__","LWG","Misc constexpr bits","San Diego","|Complete|","13.0"
7272
"`P1085R2 <https://wg21.link/P1085R2>`__","LWG","Should Span be Regular?","San Diego","|Complete|","8.0"

libcxx/include/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,7 @@ set(files
291291
__memory/allocator.h
292292
__memory/allocator_arg_t.h
293293
__memory/allocator_traits.h
294+
__memory/assume_aligned.h
294295
__memory/auto_ptr.h
295296
__memory/compressed_pair.h
296297
__memory/concepts.h
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// -*- C++ -*-
2+
//===----------------------------------------------------------------------===//
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#ifndef _LIBCPP___MEMORY_ASSUME_ALIGNED_H
11+
#define _LIBCPP___MEMORY_ASSUME_ALIGNED_H
12+
13+
#include <__assert>
14+
#include <__config>
15+
#include <cstddef>
16+
#include <cstdint>
17+
#include <type_traits> // for is_constant_evaluated()
18+
19+
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
20+
# pragma GCC system_header
21+
#endif
22+
23+
_LIBCPP_BEGIN_NAMESPACE_STD
24+
25+
#if _LIBCPP_STD_VER > 17
26+
27+
template <size_t _Np, class _Tp>
28+
[[nodiscard]]
29+
_LIBCPP_HIDE_FROM_ABI
30+
constexpr _Tp* assume_aligned(_Tp* __ptr) {
31+
static_assert(_Np != 0 && (_Np & (_Np - 1)) == 0,
32+
"std::assume_aligned<N>(p) requires N to be a power of two");
33+
34+
if (is_constant_evaluated()) {
35+
return __ptr;
36+
} else {
37+
_LIBCPP_ASSERT(reinterpret_cast<uintptr_t>(__ptr) % _Np == 0, "Alignment assumption is violated");
38+
return static_cast<_Tp*>(__builtin_assume_aligned(__ptr, _Np));
39+
}
40+
}
41+
42+
#endif // _LIBCPP_STD_VER > 17
43+
44+
_LIBCPP_END_NAMESPACE_STD
45+
46+
#endif // _LIBCPP___MEMORY_ASSUME_ALIGNED_H

libcxx/include/memory

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -828,8 +828,12 @@ template <class T> struct hash<shared_ptr<T> >;
828828
template <class T, class Alloc>
829829
inline constexpr bool uses_allocator_v = uses_allocator<T, Alloc>::value;
830830
831+
// [ptr.align]
831832
void* align(size_t alignment, size_t size, void*& ptr, size_t& space);
832833
834+
template<size_t N, class T>
835+
[[nodiscard]] constexpr T* assume_aligned(T* ptr); // since C++20
836+
833837
} // std
834838
835839
*/
@@ -842,6 +846,7 @@ void* align(size_t alignment, size_t size, void*& ptr, size_t& space);
842846
#include <__memory/allocator.h>
843847
#include <__memory/allocator_arg_t.h>
844848
#include <__memory/allocator_traits.h>
849+
#include <__memory/assume_aligned.h>
845850
#include <__memory/compressed_pair.h>
846851
#include <__memory/concepts.h>
847852
#include <__memory/construct_at.h>
@@ -1130,7 +1135,6 @@ struct __builtin_new_allocator {
11301135
}
11311136
};
11321137

1133-
11341138
_LIBCPP_END_NAMESPACE_STD
11351139

11361140
#if defined(_LIBCPP_HAS_PARALLEL_ALGORITHMS) && _LIBCPP_STD_VER >= 17

libcxx/include/module.modulemap

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -713,6 +713,7 @@ module std [system] {
713713
module allocator { private header "__memory/allocator.h" }
714714
module allocator_arg_t { private header "__memory/allocator_arg_t.h" }
715715
module allocator_traits { private header "__memory/allocator_traits.h" }
716+
module assume_aligned { private header "__memory/assume_aligned.h" }
716717
module auto_ptr { private header "__memory/auto_ptr.h" }
717718
module compressed_pair { private header "__memory/compressed_pair.h" }
718719
module concepts { private header "__memory/concepts.h" }

libcxx/include/version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ __cpp_lib_void_t 201411L <type_traits>
288288
#if _LIBCPP_STD_VER > 17
289289
# undef __cpp_lib_array_constexpr
290290
# define __cpp_lib_array_constexpr 201811L
291-
// # define __cpp_lib_assume_aligned 201811L
291+
# define __cpp_lib_assume_aligned 201811L
292292
# define __cpp_lib_atomic_flag_test 201907L
293293
// # define __cpp_lib_atomic_float 201711L
294294
# define __cpp_lib_atomic_lock_free_type_aliases 201907L

libcxx/test/libcxx/private_headers.verify.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,7 @@ END-SCRIPT
322322
#include <__memory/allocator.h> // expected-error@*:* {{use of private header from outside its module: '__memory/allocator.h'}}
323323
#include <__memory/allocator_arg_t.h> // expected-error@*:* {{use of private header from outside its module: '__memory/allocator_arg_t.h'}}
324324
#include <__memory/allocator_traits.h> // expected-error@*:* {{use of private header from outside its module: '__memory/allocator_traits.h'}}
325+
#include <__memory/assume_aligned.h> // expected-error@*:* {{use of private header from outside its module: '__memory/assume_aligned.h'}}
325326
#include <__memory/auto_ptr.h> // expected-error@*:* {{use of private header from outside its module: '__memory/auto_ptr.h'}}
326327
#include <__memory/compressed_pair.h> // expected-error@*:* {{use of private header from outside its module: '__memory/compressed_pair.h'}}
327328
#include <__memory/concepts.h> // expected-error@*:* {{use of private header from outside its module: '__memory/concepts.h'}}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is dual licensed under the MIT and the University of Illinois Open
6+
// Source Licenses. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17
11+
12+
// #include <memory>
13+
14+
// template<size_t N, class T>
15+
// [[nodiscard]] constexpr T* assume_aligned(T* ptr);
16+
17+
// This test checks that we static_assert inside std::assume_aligned<N>(p)
18+
// when N is not a power of two. However, Clang will already emit an error
19+
// in its own __builtin_assume_aligned, so we ignore that additional error
20+
// for the purpose of this test. We also ignore the additional warning about
21+
// remainder by 0 being undefined.
22+
// ADDITIONAL_COMPILE_FLAGS: -Xclang -verify-ignore-unexpected=error -Xclang -verify-ignore-unexpected=warning
23+
24+
#include <memory>
25+
26+
void f() {
27+
int *p = nullptr;
28+
(void)std::assume_aligned<0>(p); // expected-error@*:* {{std::assume_aligned<N>(p) requires N to be a power of two}}
29+
(void)std::assume_aligned<3>(p); // expected-error@*:* {{std::assume_aligned<N>(p) requires N to be a power of two}}
30+
(void)std::assume_aligned<5>(p); // expected-error@*:* {{std::assume_aligned<N>(p) requires N to be a power of two}}
31+
(void)std::assume_aligned<33>(p); // expected-error@*:* {{std::assume_aligned<N>(p) requires N to be a power of two}}
32+
}

libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.compile.pass.cpp

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -300,17 +300,11 @@
300300
# error "__cpp_lib_allocator_traits_is_always_equal should have the value 201411L in c++20"
301301
# endif
302302

303-
# if !defined(_LIBCPP_VERSION)
304-
# ifndef __cpp_lib_assume_aligned
305-
# error "__cpp_lib_assume_aligned should be defined in c++20"
306-
# endif
307-
# if __cpp_lib_assume_aligned != 201811L
308-
# error "__cpp_lib_assume_aligned should have the value 201811L in c++20"
309-
# endif
310-
# else // _LIBCPP_VERSION
311-
# ifdef __cpp_lib_assume_aligned
312-
# error "__cpp_lib_assume_aligned should not be defined because it is unimplemented in libc++!"
313-
# endif
303+
# ifndef __cpp_lib_assume_aligned
304+
# error "__cpp_lib_assume_aligned should be defined in c++20"
305+
# endif
306+
# if __cpp_lib_assume_aligned != 201811L
307+
# error "__cpp_lib_assume_aligned should have the value 201811L in c++20"
314308
# endif
315309

316310
# ifndef __cpp_lib_atomic_value_initialization
@@ -436,17 +430,11 @@
436430
# error "__cpp_lib_allocator_traits_is_always_equal should have the value 201411L in c++2b"
437431
# endif
438432

439-
# if !defined(_LIBCPP_VERSION)
440-
# ifndef __cpp_lib_assume_aligned
441-
# error "__cpp_lib_assume_aligned should be defined in c++2b"
442-
# endif
443-
# if __cpp_lib_assume_aligned != 201811L
444-
# error "__cpp_lib_assume_aligned should have the value 201811L in c++2b"
445-
# endif
446-
# else // _LIBCPP_VERSION
447-
# ifdef __cpp_lib_assume_aligned
448-
# error "__cpp_lib_assume_aligned should not be defined because it is unimplemented in libc++!"
449-
# endif
433+
# ifndef __cpp_lib_assume_aligned
434+
# error "__cpp_lib_assume_aligned should be defined in c++2b"
435+
# endif
436+
# if __cpp_lib_assume_aligned != 201811L
437+
# error "__cpp_lib_assume_aligned should have the value 201811L in c++2b"
450438
# endif
451439

452440
# ifndef __cpp_lib_atomic_value_initialization

libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2446,17 +2446,11 @@
24462446
# error "__cpp_lib_associative_heterogeneous_erasure should not be defined before c++2b"
24472447
# endif
24482448

2449-
# if !defined(_LIBCPP_VERSION)
2450-
# ifndef __cpp_lib_assume_aligned
2451-
# error "__cpp_lib_assume_aligned should be defined in c++20"
2452-
# endif
2453-
# if __cpp_lib_assume_aligned != 201811L
2454-
# error "__cpp_lib_assume_aligned should have the value 201811L in c++20"
2455-
# endif
2456-
# else // _LIBCPP_VERSION
2457-
# ifdef __cpp_lib_assume_aligned
2458-
# error "__cpp_lib_assume_aligned should not be defined because it is unimplemented in libc++!"
2459-
# endif
2449+
# ifndef __cpp_lib_assume_aligned
2450+
# error "__cpp_lib_assume_aligned should be defined in c++20"
2451+
# endif
2452+
# if __cpp_lib_assume_aligned != 201811L
2453+
# error "__cpp_lib_assume_aligned should have the value 201811L in c++20"
24602454
# endif
24612455

24622456
# ifndef __cpp_lib_atomic_flag_test
@@ -3669,17 +3663,11 @@
36693663
# endif
36703664
# endif
36713665

3672-
# if !defined(_LIBCPP_VERSION)
3673-
# ifndef __cpp_lib_assume_aligned
3674-
# error "__cpp_lib_assume_aligned should be defined in c++2b"
3675-
# endif
3676-
# if __cpp_lib_assume_aligned != 201811L
3677-
# error "__cpp_lib_assume_aligned should have the value 201811L in c++2b"
3678-
# endif
3679-
# else // _LIBCPP_VERSION
3680-
# ifdef __cpp_lib_assume_aligned
3681-
# error "__cpp_lib_assume_aligned should not be defined because it is unimplemented in libc++!"
3682-
# endif
3666+
# ifndef __cpp_lib_assume_aligned
3667+
# error "__cpp_lib_assume_aligned should be defined in c++2b"
3668+
# endif
3669+
# if __cpp_lib_assume_aligned != 201811L
3670+
# error "__cpp_lib_assume_aligned should have the value 201811L in c++2b"
36833671
# endif
36843672

36853673
# ifndef __cpp_lib_atomic_flag_test
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is dual licensed under the MIT and the University of Illinois Open
6+
// Source Licenses. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17
11+
12+
// #include <memory>
13+
14+
// template<size_t N, class T>
15+
// [[nodiscard]] constexpr T* assume_aligned(T* ptr);
16+
17+
#include <memory>
18+
19+
void f() {
20+
int *p = nullptr;
21+
std::assume_aligned<4>(p); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
22+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// UNSUPPORTED: c++03, c++11, c++14, c++17
10+
11+
// #include <memory>
12+
13+
// template<size_t N, class T>
14+
// [[nodiscard]] constexpr T* assume_aligned(T* ptr);
15+
16+
#include <memory>
17+
#include <cassert>
18+
#include <cstddef>
19+
20+
#include "test_macros.h"
21+
22+
template <typename T>
23+
constexpr void check(T* p) {
24+
ASSERT_SAME_TYPE(T*, decltype(std::assume_aligned<1>(p)));
25+
constexpr std::size_t alignment = alignof(T);
26+
27+
if constexpr (alignment >= 1)
28+
assert(p == std::assume_aligned<1>(p));
29+
if constexpr (alignment >= 2)
30+
assert(p == std::assume_aligned<2>(p));
31+
if constexpr (alignment >= 4)
32+
assert(p == std::assume_aligned<4>(p));
33+
if constexpr (alignment >= 8)
34+
assert(p == std::assume_aligned<8>(p));
35+
if constexpr (alignment >= 16)
36+
assert(p == std::assume_aligned<16>(p));
37+
if constexpr (alignment >= 32)
38+
assert(p == std::assume_aligned<32>(p));
39+
if constexpr (alignment >= 64)
40+
assert(p == std::assume_aligned<64>(p));
41+
if constexpr (alignment >= 128)
42+
assert(p == std::assume_aligned<128>(p));
43+
}
44+
45+
struct S { };
46+
struct alignas( 4) S4 { };
47+
struct alignas( 8) S8 { };
48+
struct alignas( 16) S16 { };
49+
struct alignas( 32) S32 { };
50+
struct alignas( 64) S64 { };
51+
struct alignas(128) S128 { };
52+
53+
constexpr bool tests() {
54+
char c;
55+
int i;
56+
long l;
57+
double d;
58+
long double ld;
59+
check( &c);
60+
check( &i);
61+
check( &l);
62+
check( &d);
63+
check(&ld);
64+
65+
S s;
66+
S4 s4;
67+
S8 s8;
68+
S16 s16;
69+
S32 s32;
70+
S64 s64;
71+
S128 s128;
72+
check(&s);
73+
check(&s4);
74+
check(&s8);
75+
check(&s16);
76+
check(&s32);
77+
check(&s64);
78+
check(&s128);
79+
80+
return true;
81+
}
82+
83+
int main(int, char**) {
84+
tests();
85+
static_assert(tests());
86+
87+
return 0;
88+
}

libcxx/utils/generate_feature_test_macro_components.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,6 @@ def add_version_header(tc):
103103
"name": "__cpp_lib_assume_aligned",
104104
"values": { "c++20": 201811 },
105105
"headers": ["memory"],
106-
"unimplemented": True,
107106
}, {
108107
"name": "__cpp_lib_atomic_flag_test",
109108
"values": { "c++20": 201907 },

0 commit comments

Comments
 (0)