[libcxx-commits] [libcxx] [libc++] Implement C++20 atomic_ref (PR #76647)
Louis Dionne via libcxx-commits
libcxx-commits at lists.llvm.org
Tue May 7 13:35:05 PDT 2024
================
@@ -0,0 +1,356 @@
+// -*- 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___ATOMIC_ATOMIC_REF_H
+#define _LIBCPP___ATOMIC_ATOMIC_REF_H
+
+#include <__assert>
+#include <__atomic/atomic_sync.h>
+#include <__atomic/check_memory_order.h>
+#include <__atomic/to_gcc_order.h>
+#include <__concepts/arithmetic.h>
+#include <__concepts/same_as.h>
+#include <__config>
+#include <__memory/addressof.h>
+#include <__type_traits/has_unique_object_representation.h>
+#include <__type_traits/is_trivially_copyable.h>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+
+#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 >= 20
+
+template <class _Tp>
+struct __atomic_ref_base {
+protected:
+ _Tp* __ptr_;
+
+ _LIBCPP_HIDE_FROM_ABI __atomic_ref_base(_Tp& __obj) : __ptr_(std::addressof(__obj)) {}
+
+private:
+ _LIBCPP_HIDE_FROM_ABI static _Tp* __clear_padding(_Tp& __val) noexcept {
+ _Tp* __ptr = std::addressof(__val);
+# if __has_builtin(__builtin_clear_padding)
+ __builtin_clear_padding(__ptr);
+# endif
+ return __ptr;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI static bool __compare_exchange(
+ _Tp* __ptr, _Tp* __expected, _Tp* __desired, bool __is_weak, int __success, int __failure) noexcept {
+ if constexpr (
+# if __has_builtin(__builtin_clear_padding)
+ has_unique_object_representations_v<_Tp> || same_as<_Tp, float> || same_as<_Tp, double>
+# else
+ true // NOLINT(readability-simplify-boolean-expr)
+# endif
+ ) {
+ return __atomic_compare_exchange(__ptr, __expected, __desired, __is_weak, __success, __failure);
+ } else { // _Tp has padding bits and __builtin_clear_padding is available
+ __clear_padding(*__desired);
+ _Tp __copy = *__expected;
+ __clear_padding(__copy);
+ // The algorithm we use here is basically to perform `__atomic_compare_exchange` on the
+ // values until it has either succeeded, or failed because the value representation of the
+ // objects involved was different. This is why we loop around __atomic_compare_exchange:
+ // we basically loop until its failure is caused by the value representation of the objects
+ // being different, not only their object representation.
+ while (true) {
+ _Tp __prev = __copy;
+ if (__atomic_compare_exchange(__ptr, std::addressof(__copy), __desired, __is_weak, __success, __failure)) {
+ return true;
+ }
+ _Tp __curr = __copy;
+ if (std::memcmp(__clear_padding(__prev), __clear_padding(__curr), sizeof(_Tp)) != 0) {
+ // Value representation without padding bits do not compare equal ->
+ // write the current content of *ptr into *expected
+ std::memcpy(__expected, std::addressof(__copy), sizeof(_Tp));
+ return false;
+ }
+ }
+ }
+ }
+
+ friend struct __atomic_waitable_traits<__atomic_ref_base<_Tp>>;
+
+public:
+ using value_type = _Tp;
+
+ static constexpr size_t required_alignment = alignof(_Tp);
+
+ static constexpr bool is_always_lock_free =
+ __atomic_always_lock_free(sizeof(_Tp), reinterpret_cast<void*>(-required_alignment));
----------------
ldionne wrote:
Let's add a comment:
```
// The __atomic_always_lock_free builtin takes into account the alignment of the pointer if provided,
// so we create a fake pointer with a suitable alignment when querying it. Note that we are guaranteed
// that the pointer is going to be aligned properly at runtime because that is a (checked) precondition
// of atomic_ref's constructor.
```
https://github.com/llvm/llvm-project/pull/76647
More information about the libcxx-commits
mailing list