Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
6272ee2
[libc++] make std::atomic works with types with paddings
huixie90 Dec 21, 2023
5e5b628
gcc
huixie90 Jun 7, 2026
bdfc4c9
lint
huixie90 Jun 13, 2026
af90c9a
gcc c++11 ci
huixie90 Jun 21, 2026
1e9d805
Update libcxx/test/std/atomics/atomics.types.generic/padding.pass.cpp
huixie90 Jul 4, 2026
1c047a9
Update libcxx/include/__atomic/support/c11.h
huixie90 Jul 4, 2026
543d559
Update libcxx/include/__atomic/support/common.h
huixie90 Jul 4, 2026
fa10f55
review comments batch 1
huixie90 Jul 4, 2026
7334f3e
batch2
huixie90 Jul 6, 2026
8dfd839
CI
huixie90 Jul 8, 2026
f938e09
review comment
huixie90 Jul 8, 2026
8ff3104
review
huixie90 Jul 8, 2026
0eb7a5e
14
huixie90 Jul 8, 2026
347f6e9
14
huixie90 Jul 8, 2026
b28d7e4
ci
huixie90 Jul 8, 2026
37c72ba
ci
huixie90 Jul 8, 2026
1cc0224
CI
huixie90 Jul 10, 2026
386f7e3
ci
huixie90 Jul 10, 2026
029073a
review
huixie90 Jul 20, 2026
fd55e4b
release notes
huixie90 Jul 20, 2026
f529e02
ci
huixie90 Jul 20, 2026
ddbc06a
ci
huixie90 Jul 20, 2026
f7b6225
debug
huixie90 Jul 20, 2026
8f5626f
Revert "debug"
huixie90 Jul 20, 2026
40c3316
test ci
huixie90 Jul 20, 2026
75b19b2
padding
huixie90 Jul 22, 2026
399acfd
clang22
huixie90 Jul 22, 2026
bc33e49
cxx 03
huixie90 Jul 22, 2026
7b17a5b
ci
huixie90 Jul 22, 2026
5ddfbe6
ci
huixie90 Jul 22, 2026
749277c
ci
huixie90 Jul 22, 2026
5739b6c
ci
huixie90 Jul 22, 2026
2adfb7c
ci
huixie90 Jul 24, 2026
e278047
review
huixie90 Jul 25, 2026
7d841c5
inline
huixie90 Jul 25, 2026
3b63e5c
f
huixie90 Jul 25, 2026
edc991c
Update libcxx/include/__atomic/support/c11.h
huixie90 Jul 27, 2026
6417035
Update libcxx/utils/libcxx/test/features/misc.py
huixie90 Jul 27, 2026
6a15f6a
review
huixie90 Jul 27, 2026
a546c54
ci
huixie90 Jul 27, 2026
5766ff8
rename
huixie90 Jul 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions libcxx/docs/ReleaseNotes/24.rst
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ Implemented Papers
- P3948R1: ``constant_wrapper`` is the only tool needed for passing constant expressions via function arguments (`Github <https://llvm.org/PR189604>`__)
- P3961R1: Less double indirection in ``function_ref`` (RU-220) (`Github <https://llvm.org/PR189606>`__)
- P1901R2: Enabling the Use of ``weak_ptr`` as Keys in Unordered Associative Containers (`Github <https://llvm.org/PR105372>`__)
- P0528R3: The Curious Case of Padding Bits, Featuring Atomic Compare-and-Exchange (`Github <https://llvm.org/PR76180>`__)

Improvements and New Features
-----------------------------
Expand Down
2 changes: 1 addition & 1 deletion libcxx/docs/Status/Cxx20Papers.csv
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"`P0458R2 <https://wg21.link/P0458R2>`__","Checking for Existence of an Element in Associative Containers","2018-06 (Rapperswil)","|Complete|","13","`#104029 <https://github.com/llvm/llvm-project/issues/104029>`__",""
"`P0475R1 <https://wg21.link/P0475R1>`__","LWG 2511: guaranteed copy elision for piecewise construction","2018-06 (Rapperswil)","|Complete|","","`#104031 <https://github.com/llvm/llvm-project/issues/104031>`__",""
"`P0476R2 <https://wg21.link/P0476R2>`__","Bit-casting object representations","2018-06 (Rapperswil)","|Complete|","14","`#104087 <https://github.com/llvm/llvm-project/issues/104087>`__",""
"`P0528R3 <https://wg21.link/P0528R3>`__","The Curious Case of Padding Bits, Featuring Atomic Compare-and-Exchange","2018-06 (Rapperswil)","","","`#99984 <https://github.com/llvm/llvm-project/issues/99984>`__",""
"`P0528R3 <https://wg21.link/P0528R3>`__","The Curious Case of Padding Bits, Featuring Atomic Compare-and-Exchange","2018-06 (Rapperswil)","|Complete|","24","`#99984 <https://github.com/llvm/llvm-project/issues/99984>`__",""
"`P0542R5 <https://wg21.link/P0542R5>`__","Support for contract based programming in C++","2018-06 (Rapperswil)","|Nothing To Do|","n/a","`#104089 <https://github.com/llvm/llvm-project/issues/104089>`__","Pulled at the 2019-07 meeting in Cologne"
"`P0556R3 <https://wg21.link/P0556R3>`__","Integral power-of-2 operations","2018-06 (Rapperswil)","|Complete|","9","`#104090 <https://github.com/llvm/llvm-project/issues/104090>`__",""
"`P0619R4 <https://wg21.link/P0619R4>`__","Reviewing Deprecated Facilities of C++17 for C++20","2018-06 (Rapperswil)","|Complete|","20","`#99985 <https://github.com/llvm/llvm-project/issues/99985>`__","Removed headers are still provided as an extension, but with deprecation warnings."
Expand Down
1 change: 1 addition & 0 deletions libcxx/include/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ set(files
__atomic/atomic_sync_timed.h
__atomic/atomic_waitable_traits.h
__atomic/check_memory_order.h
__atomic/clear_padding.h
__atomic/contention_t.h
__atomic/fence.h
__atomic/floating_point_helper.h
Expand Down
92 changes: 92 additions & 0 deletions libcxx/include/__atomic/clear_padding.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
//===----------------------------------------------------------------------===//
//
// 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___ATOMIC_CLEAR_PADDING_H
#define _LIBCPP___ATOMIC_CLEAR_PADDING_H

#include <__config>
#include <__memory/addressof.h>
#include <__type_traits/conjunction.h>
#include <__type_traits/enable_if.h>
#include <__type_traits/has_unique_object_representation.h>
#include <__type_traits/integral_constant.h>
#include <__type_traits/is_same.h>
#include <__type_traits/negation.h>
#include <__type_traits/remove_cv.h>
#include <__type_traits/remove_cvref.h>
#include <__utility/forward.h>
#include <cstring>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif

_LIBCPP_BEGIN_NAMESPACE_STD

#if __has_builtin(__builtin_clear_padding)

template <class _Tp>
struct __needs_clear_padding
: _And<_Not<integral_constant<bool, __has_unique_object_representations(_Tp)> >,
_Not<is_same<_Tp, float> >,
_Not<is_same<_Tp, double> > > {};

template <class _Tp, __enable_if_t<!__needs_clear_padding<__remove_cvref_t<_Tp> >::value, int> = 0>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Tp& __clear_padding_if_needed(_Tp& __obj) _NOEXCEPT {
return __obj;
}

template <class _Tp, __enable_if_t<__needs_clear_padding<__remove_cvref_t<_Tp> >::value, int> = 0>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Tp& __clear_padding_if_needed(_Tp& __obj) _NOEXCEPT {
return __builtin_is_constant_evaluated() ? __obj : (__builtin_clear_padding(std::addressof(__obj)), __obj);
}

// clang fails to inline the function when the memory order is a constant
template <class _Tp,
class _Up,
class _CasFunc,
__enable_if_t<!__needs_clear_padding<__remove_cvref_t<_Tp> >::value, int> = 0>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE bool
__atomic_cas_with_clear_padding(_Tp* __expected, _Up __value, _CasFunc&& __cas_func) {
return __cas_func(__expected, __value);
}

template <class _Tp,
class _Up,
class _CasFunc,
__enable_if_t<__needs_clear_padding<__remove_cvref_t<_Tp> >::value, int> = 0>
_LIBCPP_HIDE_FROM_ABI bool __atomic_cas_with_clear_padding(_Tp* __expected, _Up __value, _CasFunc&& __cas_func) {
std::__clear_padding_if_needed(__value);
__remove_cvref_t<_Tp> __expected_copy = *__expected;
std::__clear_padding_if_needed(__expected_copy);
if (__cas_func(std::addressof(__expected_copy), __value)) {
return true;
} else {
std::memcpy(__expected, std::addressof(__expected_copy), sizeof(__remove_cvref_t<_Tp>));
return false;
}
}

#else // __has_builtin(__builtin_clear_padding)

template <class _Tp>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Tp& __clear_padding_if_needed(_Tp& __obj) _NOEXCEPT {
return __obj;
}

template <class _Tp, class _Up, class _CasFunc>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE bool
__atomic_cas_with_clear_padding(_Tp* __expected, _Up __value, _CasFunc&& __cas_func) {
return __cas_func(__expected, __value);
}

#endif // __has_builtin(__builtin_clear_padding)

_LIBCPP_END_NAMESPACE_STD

#endif // _LIBCPP___ATOMIC_CLEAR_PADDING_H
66 changes: 49 additions & 17 deletions libcxx/include/__atomic/support/c11.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#ifndef _LIBCPP___ATOMIC_SUPPORT_C11_H
#define _LIBCPP___ATOMIC_SUPPORT_C11_H

#include <__atomic/clear_padding.h>
#include <__atomic/memory_order.h>
#include <__config>
#include <__cstddef/ptrdiff_t.h>
Expand Down Expand Up @@ -36,7 +37,10 @@ struct __cxx_atomic_base_impl {
__cxx_atomic_base_impl() _NOEXCEPT : __a_value() {
}
#endif // _LIBCPP_CXX03_LANG
_LIBCPP_CONSTEXPR explicit __cxx_atomic_base_impl(_Tp __value) _NOEXCEPT : __a_value(__value) {}

_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __cxx_atomic_base_impl(_Tp __value) _NOEXCEPT
: __a_value(std::__clear_padding_if_needed(__value)) {}

_Atomic(_Tp) __a_value;
};

Expand All @@ -52,21 +56,25 @@ _LIBCPP_HIDE_FROM_ABI inline void __cxx_atomic_signal_fence(memory_order __order

template <class _Tp>
_LIBCPP_HIDE_FROM_ABI void __cxx_atomic_init(__cxx_atomic_base_impl<_Tp> volatile* __a, _Tp __val) _NOEXCEPT {
std::__clear_padding_if_needed(__val);
__c11_atomic_init(std::addressof(__a->__a_value), __val);
}
template <class _Tp>
_LIBCPP_HIDE_FROM_ABI void __cxx_atomic_init(__cxx_atomic_base_impl<_Tp>* __a, _Tp __val) _NOEXCEPT {
std::__clear_padding_if_needed(__val);
__c11_atomic_init(std::addressof(__a->__a_value), __val);
}

template <class _Tp>
_LIBCPP_HIDE_FROM_ABI void
__cxx_atomic_store(__cxx_atomic_base_impl<_Tp> volatile* __a, _Tp __val, memory_order __order) _NOEXCEPT {
std::__clear_padding_if_needed(__val);
__c11_atomic_store(std::addressof(__a->__a_value), __val, static_cast<__memory_order_underlying_t>(__order));
}
template <class _Tp>
_LIBCPP_HIDE_FROM_ABI void
__cxx_atomic_store(__cxx_atomic_base_impl<_Tp>* __a, _Tp __val, memory_order __order) _NOEXCEPT {
std::__clear_padding_if_needed(__val);
__c11_atomic_store(std::addressof(__a->__a_value), __val, static_cast<__memory_order_underlying_t>(__order));
}

Expand Down Expand Up @@ -102,12 +110,14 @@ __cxx_atomic_load_inplace(__cxx_atomic_base_impl<_Tp> const* __a, _Tp* __dst, me
template <class _Tp>
_LIBCPP_HIDE_FROM_ABI _Tp
__cxx_atomic_exchange(__cxx_atomic_base_impl<_Tp> volatile* __a, _Tp __value, memory_order __order) _NOEXCEPT {
std::__clear_padding_if_needed(__value);
return __c11_atomic_exchange(
std::addressof(__a->__a_value), __value, static_cast<__memory_order_underlying_t>(__order));
}
template <class _Tp>
_LIBCPP_HIDE_FROM_ABI _Tp
__cxx_atomic_exchange(__cxx_atomic_base_impl<_Tp>* __a, _Tp __value, memory_order __order) _NOEXCEPT {
std::__clear_padding_if_needed(__value);
return __c11_atomic_exchange(
std::addressof(__a->__a_value), __value, static_cast<__memory_order_underlying_t>(__order));
}
Expand All @@ -126,23 +136,34 @@ _LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_strong(
_Tp __value,
memory_order __success,
memory_order __failure) _NOEXCEPT {
return __c11_atomic_compare_exchange_strong(
std::addressof(__a->__a_value),
return std::__atomic_cas_with_clear_padding(
__expected,
__value,
static_cast<__memory_order_underlying_t>(__success),
static_cast<__memory_order_underlying_t>(__to_failure_order(__failure)));
// Use always_inline since Clang fails to inline the lambda, even when the memory order is a constant
[__a, __success, __failure](_Tp* __expected_or_copy, _Tp __value_maybe_padding_cleared) _LIBCPP_ALWAYS_INLINE {

@philnik777 philnik777 Jul 28, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this marked with _LIBCPP_ALWAYS_INLINE?

Edit: Sorry, missed the comment above.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah Ok. Let me know if the comment is unclear. The detailed discussion is here #76180 (comment)

return __c11_atomic_compare_exchange_strong(
std::addressof(__a->__a_value),
__expected_or_copy,
__value_maybe_padding_cleared,
static_cast<__memory_order_underlying_t>(__success),
static_cast<__memory_order_underlying_t>(std::__to_failure_order(__failure)));
});
}
template <class _Tp>
_LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_strong(
__cxx_atomic_base_impl<_Tp>* __a, _Tp* __expected, _Tp __value, memory_order __success, memory_order __failure)
_NOEXCEPT {
return __c11_atomic_compare_exchange_strong(
std::addressof(__a->__a_value),
return std::__atomic_cas_with_clear_padding(
__expected,
__value,
static_cast<__memory_order_underlying_t>(__success),
static_cast<__memory_order_underlying_t>(__to_failure_order(__failure)));
[__a, __success, __failure](_Tp* __expected_or_copy, _Tp __value_maybe_padding_cleared) _LIBCPP_ALWAYS_INLINE {
return __c11_atomic_compare_exchange_strong(
std::addressof(__a->__a_value),
__expected_or_copy,
__value_maybe_padding_cleared,
static_cast<__memory_order_underlying_t>(__success),
static_cast<__memory_order_underlying_t>(std::__to_failure_order(__failure)));
});
}

template <class _Tp>
Expand All @@ -152,23 +173,34 @@ _LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_weak(
_Tp __value,
memory_order __success,
memory_order __failure) _NOEXCEPT {
return __c11_atomic_compare_exchange_weak(
std::addressof(__a->__a_value),
return std::__atomic_cas_with_clear_padding(
__expected,
__value,
static_cast<__memory_order_underlying_t>(__success),
static_cast<__memory_order_underlying_t>(__to_failure_order(__failure)));
[__a, __success, __failure](_Tp* __expected_or_copy, _Tp __value_maybe_padding_cleared) _LIBCPP_ALWAYS_INLINE {
return __c11_atomic_compare_exchange_weak(
std::addressof(__a->__a_value),
__expected_or_copy,
__value_maybe_padding_cleared,
static_cast<__memory_order_underlying_t>(__success),
static_cast<__memory_order_underlying_t>(std::__to_failure_order(__failure)));
});
}

template <class _Tp>
_LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_weak(
__cxx_atomic_base_impl<_Tp>* __a, _Tp* __expected, _Tp __value, memory_order __success, memory_order __failure)
_NOEXCEPT {
return __c11_atomic_compare_exchange_weak(
std::addressof(__a->__a_value),
return std::__atomic_cas_with_clear_padding(
__expected,
__value,
static_cast<__memory_order_underlying_t>(__success),
static_cast<__memory_order_underlying_t>(__to_failure_order(__failure)));
[__a, __success, __failure](_Tp* __expected_or_copy, _Tp __value_maybe_padding_cleared) _LIBCPP_ALWAYS_INLINE {
return __c11_atomic_compare_exchange_weak(
std::addressof(__a->__a_value),
__expected_or_copy,
__value_maybe_padding_cleared,
static_cast<__memory_order_underlying_t>(__success),
static_cast<__memory_order_underlying_t>(std::__to_failure_order(__failure)));
});
}

template <class _Tp>
Expand Down
Loading
Loading