Skip to content
17 changes: 11 additions & 6 deletions libcxx/include/__atomic/atomic_ref.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,6 @@ struct __get_aligner_instance {

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);
Expand Down Expand Up @@ -108,10 +103,14 @@ struct __atomic_ref_base {

friend struct __atomic_waitable_traits<__atomic_ref_base<_Tp>>;

// require types that are 1, 2, 4, 8, or 16 bytes in length to be aligned to at least their size to be potentially
// used lock-free
static constexpr size_t __min_alignment = (sizeof(_Tp) & (sizeof(_Tp) - 1)) || (sizeof(_Tp) > 16) ? 0 : sizeof(_Tp);

public:
using value_type = _Tp;

static constexpr size_t required_alignment = alignof(_Tp);
static constexpr size_t required_alignment = alignof(_Tp) > __min_alignment ? alignof(_Tp) : __min_alignment;
Copy link
Member

Choose a reason for hiding this comment

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

I think we should calculate the alignment using something like this?

template <class T>
constexpr size_t calc_alignment() {
    size_t align = alignof(T);
    while (align <= alignof(max_align_t)) {
        if (__atomic_always_lock_free(sizeof(T), align))
            return align;
        align *= 2;
    }
    return alignof(T);
}

Copy link
Member

Choose a reason for hiding this comment

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

I really like this, I think this directly translates to what we are actually trying to achieve (which is to calculate the smallest alignment that allows us to be lockfree).

Copy link
Member

Choose a reason for hiding this comment

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

That is not a valid implementation, because it causes the ABI of the type to change depending on the microarchitecture selection.

Copy link
Member

Choose a reason for hiding this comment

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

TIL


// 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
Expand Down Expand Up @@ -218,6 +217,12 @@ struct __atomic_ref_base {
}
_LIBCPP_HIDE_FROM_ABI void notify_one() const noexcept { std::__atomic_notify_one(*this); }
_LIBCPP_HIDE_FROM_ABI void notify_all() const noexcept { std::__atomic_notify_all(*this); }

protected:
typedef _Tp _Aligned_Tp __attribute__((aligned(required_alignment)));
_Aligned_Tp* __ptr_;

_LIBCPP_HIDE_FROM_ABI __atomic_ref_base(_Tp& __obj) : __ptr_(std::addressof(__obj)) {}
};

template <class _Tp>
Expand Down