On Tue, 2 Nov 2021 at 01:26, Thomas Rodgers <trodg...@redhat.com> wrote:
> This should address Jonathan's feedback and adds support for atomic_ref<T> > >This change implements P0528 which requires that padding bits not >participate in atomic compare exchange operations. All arguments to the >generic template are 'sanitized' by the __builtin_clearpadding intrisic The name of the intrinsic and the word "instrinsic" have typos. >before they are used in comparisons. This alrequires that any stores >also sanitize the incoming value. > >Signed-off-by: Thomas Rodgers <trodg...@redhat.com> > >libstdc++=v3/ChangeLog: Typo > > * include/std/atomic (atomic<T>::atomic(_Tp): clear padding for Unclosed paren. >+#if __has_builtin(__builtin_clear_padding) Instead of checking this built-in at every call site, can't we just make __maybe_has_padding return false if the built-in isn't supported? __clear_padding already handles the case where the built-in isn't supported. >+ template<typename _Tp> >+ constexpr bool >+ __maybe_has_padding() >+ { >+#if __has_builtin(__has_unique_object_representations) >+ return !__has_unique_object_representations(_Tp) >+ && !is_floating_point<_Tp>::value; >+#else >+ return true; >+#endif >+ } So make that: template<typename _Tp> constexpr bool __maybe_has_padding() { #if ! __has_builtin(__builtin_clear_padding) return false; #elif __has_builtin(__has_unique_object_representations) return !__has_unique_object_representations(_Tp) && !is_floating_point<_Tp>::value; #else return true; #endif } >+ if _GLIBCXX14_CONSTEXPR (__atomic_impl::__maybe_has_padding<_Tp>()) >+ { This needs to be _GLIBCXX17_CONSTEXPR (everywhere that `if constexpr` is used). >+ { >+ alignas(_Tp) unsigned char __buf[sizeof(_Tp)]; >+ __builtin_memcpy(__buf, std::__addressof(__e), sizeof(_Tp)); alignas(_Tp) unsigned char __buf[sizeof(_Tp)]; _Tp* __exp = ::new((void*)__buf) _Tp(__e); >+ auto* __exp = __atomic_impl::__clear_padding(*reinterpret_cast<_Tp*>(__buf)); And then you don't need the reinterpret_cast: __exp = __atomic_impl::__clear_padding(__exp); >+ auto* __des = __atomic_impl::__clear_padding(__i); >+ if (__atomic_compare_exchange(std::__addressof(__val), __exp, __des, __weak, >+ int(__s), int(__f))) >+ return true; > template<typename _Tp> > _GLIBCXX_ALWAYS_INLINE void > store(_Tp* __ptr, _Val<_Tp> __t, memory_order __m) noexcept >- { __atomic_store(__ptr, std::__addressof(__t), int(__m)); } >+ { >+#if __has_builtin(__builtin_clear_padding) >+ if _GLIBCXX14_CONSTEXPR (__maybe_has_padding<_Tp>()) >+ __clear_padding(__t); >+#endif >+ __atomic_store(__ptr, std::__addressof(__t), int(__m)); >+ } > All calls to __clear_padding need to be qualified. >+ return __compare_exchange(*__ptr, __expected, __desired, true, >+ __success, __failure); So do calls to __compare_exchange. > > explicit > __atomic_ref(_Tp& __t) : _M_ptr(std::__addressof(__t)) >- { __glibcxx_assert(((uintptr_t)_M_ptr % required_alignment) == 0); } >+ { >+ __glibcxx_assert(((uintptr_t)_M_ptr % required_alignment) == 0); >+#if __cplusplus > 201402L && __has_builtin(__builtin_clear_padding) >+ __builtin_clear_padding(_M_ptr); >+#endif >+ } Is this safe to do? What if multiple threads all create a std::atomic_ref round the same object at once, they'll all try to clear padding, and so race, won't they? I don't think we can clear padding on atomic_ref construction, only on store and RMW operations. >--- a/libstdc++-v3/include/std/atomic >+++ b/libstdc++-v3/include/std/atomic >@@ -228,13 +228,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > atomic& operator=(const atomic&) = delete; > atomic& operator=(const atomic&) volatile = delete; > >-#if __cplusplus > 201703L && __has_builtin(__builtin_clear_padding) > constexpr atomic(_Tp __i) noexcept : _M_i(__i) >- { __builtin_clear_padding(std::__addressof(_M_i)); } >-#else >- constexpr atomic(_Tp __i) noexcept : _M_i(__i) >- { } >+ { >+#if __cplusplus > 201402L && __has_builtin(__builtin_clear_padding) >+ __builtin_clear_padding(std::__addressof(_M_i)); > #endif >+ } > Is this an incremental patch relative to the first one? The changes to this file look correct. >--- /dev/null >+++ b/libstdc++-v3/testsuite/29_atomics/atomic_ref/compare_exchange_padding.cc >@@ -0,0 +1,43 @@ >+// { dg-options "-std=gnu++2a" } >+// { dg-do run { target c++2a } } This new test is using "2a" not "20".