https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111077

--- Comment #8 from CVS Commits <cvs-commit at gcc dot gnu.org> ---
The master branch has been updated by Jonathan Wakely <r...@gcc.gnu.org>:

https://gcc.gnu.org/g:dcbec954fcba42d97760c6bd98a4c5618473ec93

commit r14-3625-gdcbec954fcba42d97760c6bd98a4c5618473ec93
Author: Jonathan Wakely <jwak...@redhat.com>
Date:   Wed Aug 23 12:23:37 2023 +0100

    libstdc++: Use a loop in atomic_ref::compare_exchange_strong [PR111077]

    We need to use a loop in std::atomic_ref::compare_exchange_strong in
    order to properly implement the C++20 requirement that padding bits do
    not participate when checking the value for equality. The variable being
    modified by a std::atomic_ref might have an initial value with non-zero
    padding bits, so when the __atomic_compare_exchange built-in returns
    false we need to check whether that was only because of non-equal
    padding bits that are not part of the value representation. If the value
    bits differ, it's just a failed compare-exchange. If the value bits are
    the same, we need to retry the __atomic_compare_exchange using the value
    that was just read by the previous failed call. As noted in the
    comments, it's possible for that second try to also fail due to another
    thread storing the same value but with differences in padding.

    Because it's undefined to access a variable directly while it's held by
    a std::atomic_ref, and because std::atomic_ref will only ever store
    values with zeroed padding, we know that padding bits will never go from
    zero to non-zero during the lifetime of a std::atomic_ref. They can only
    go from an initial non-zero state to zero. This means the loop will
    terminate, rather than looping indefinitely as padding bits flicker on
    and off. In theory users could call __atomic_store etc. directly and
    write a value with non-zero padding bits, but we don't need to support
    that. Users doing that should ensure they do not write non-zero padding,
    to be compatibile with our std::atomic_ref's invariants.

    This isn't a problem for std::atomic<T>::compare_exchange_strong because
    the initial value (and all later stores to the variable) are performed
    by the library, so we ensure that stored values always have padding bits
    cleared. That means we can simply clear the padding bits of the
    'expected' value and we will be comparing two values with equal padding
    bits. This means we don't need the loop for std::atomic, so update the
    __atomic_impl::__compare_exchange function to take a bool parameter that
    says whether it's being used by std::atomic_ref. If not, we can use a
    simpler, non-looping implementation.

    libstdc++-v3/ChangeLog:

            PR libstdc++/111077
            * include/bits/atomic_base.h (__atomic_impl::__compare_exchange):
            Add _AtomicRef non-type template parameter and use a loop if it
            is true.
            (__atomic_impl::compare_exchange_weak): Add _AtomicRef NTTP.
            (__atomic_impl::compare_exchange_strong): Likewise.
            (atomic_ref::compare_exchange_weak): Use true for NTTP.
            (atomic_ref::compare_exchange_strong): Use true for NTTP.
            * testsuite/29_atomics/atomic_ref/compare_exchange_padding.cc:
            Fix test to not rely on atomic_ref::load() to return an object
            with padding preserved.

Reply via email to