__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16 not defined on aarch64

Richard Earnshaw (lists) Richard.Earnshaw@arm.com
Thu Jun 29 14:04:00 GMT 2017

On 29/06/17 11:14, Andrew Haley wrote:
> On 29/06/17 10:40, Alexander Monakov wrote:
>> On Thu, 29 Jun 2017, Andrew Haley wrote:
>>> I think I now properly understand Richard Earnshaw's point: that we
>>> *do* support a full set of atomic primitives for 16-byte types via
>>> libatomic, but for them to work as a sequentially-consistent set we
>>> must use the same locking scheme for all of them.  It's ugly, and
>>> horrible for anyone who simply wants a double-word CAS, but it is what
>>> it is.  We can't use LDXP because it isn't atomic on its own, and the
>>> ARM manual is quite explicit about this.  Anyone who wants to use
>>> a real compare-and-swap-16 is on their own.
>> Note that there's no 'atomic read' primitive among __sync builtins, so
>> IMO it gives a way out: expose native doubleword cas via __sync_compare_and_swap,
>> use a locking scheme for its __atomic counterpart.
> So it does.  Good idea.  Although documenting the incompatibility between
> __atomic and __sync might be rather problematic.  :-)

[Beware: straw man.  I haven't had time to think this through into all
the corners; it's quite possible that I've missed something fundamental.]

I really don't think it's a good idea to try to overload the different
operations onto one data type.


If we had a /new/ data type that was type-incompatible with the existing
type and which could also be guaranteed never to be located in a
read-only data section, even if const, then we could define lockless
operations on the new type that would be safe by construction.  That
would then permit CAS to work and for all reads to work atomically by
using a LDXP/STXP loop.

Compilers would still recognize and enforce _at the language level_
constness, but at the implementation level the NULL STXP operation
(which only succeeds if the value isn't being accessed by another
thread) would still execute correctly.

Implementing this in the compiler would need a new data type (at least a
new type qualifier) so that conversions between the two types could not
be accidental; and a new set of primitives would need to be defined to
operate on the new type.  The primitives would look similar to the
existing ones, but would have to be clearly distinct to enforce atomic

Lets say, for the sake of argument, that the new qualifier was called
_Mutable (or perhaps __Mutable, since _Mutable is in the domain of the
language standards).  You'd then get

_Atomic _Mutable int128_t x;

and now the compiler would know never to put such a type in .rodata
(only .data or .bss).

More information about the Gcc-help mailing list