This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of Resolved status.
Section: 32.5.8.2 [atomics.types.operations] Status: Resolved Submitter: Jeffrey Yasskin Opened: 2009-06-16 Last modified: 2016-01-28
Priority: Not Prioritized
View other active issues in [atomics.types.operations].
View all other issues in [atomics.types.operations].
View all issues with Resolved status.
Discussion:
Addresses US 90
The C++0X draft declares all of the functions dealing with atomics (section 32.5.8.2 [atomics.types.operations]) to take volatile arguments. Yet it also says (29.4-3),
[ Note: Many operations are volatile-qualified. The "volatile as device register" semantics have not changed in the standard. This qualification means that volatility is preserved when applying these operations to volatile objects. It does not mean that operations on non-volatile objects become volatile. Thus, volatile qualified operations on non-volatile objects may be merged under some conditions. — end note ]
I was thinking about how to implement this in gcc, and I believe that we'll want to overload most of the functions on volatile and non-volatile. Here's why:
To let the compiler take advantage of the permission
to merge non-volatile atomic operations and reorder atomics in certain,
we'll need to tell the compiler backend
about exactly which atomic operation was used.
So I expect most of the functions of the form atomic_<op>_explicit()
(e.g. atomic_load_explicit
, atomic_exchange_explicit
,
atomic_fetch_add_explicit
, etc.)
to become compiler builtins.
A builtin can tell whether its argument was volatile or not,
so those functions don't really need extra explicit overloads.
However, I don't expect that we'll want to add builtins
for every function in chapter 29,
since most can be implemented in terms of the _explicit
free functions:
class atomic_int {
__atomic_int_storage value;
public:
int fetch_add(int increment, memory_order order = memory_order_seq_cst) volatile {
// &value has type "volatile __atomic_int_storage*".
atomic_fetch_add_explicit(&value, increment, order);
}
...
};
But now this always calls
the volatile builtin version of atomic_fetch_add_explicit()
,
even if the atomic_int
wasn't declared volatile.
To preserve volatility and the compiler's permission to optimize,
I'd need to write:
class atomic_int {
__atomic_int_storage value;
public:
int fetch_add(int increment, memory_order order = memory_order_seq_cst) volatile {
atomic_fetch_add_explicit(&value, increment, order);
}
int fetch_add(int increment, memory_order order = memory_order_seq_cst) {
atomic_fetch_add_explicit(&value, increment, order);
}
...
};
But this is visibly different from the declarations in the standard
because it's now overloaded.
(Consider passing &atomic_int::fetch_add
as a template parameter.)
The implementation may already have permission to add overloads to the member functions:
16.4.6.5 [member.functions] An implementation may declare additional non-virtual member function signatures within a class:
...
- by adding a member function signature for a member function name.
but I don't see an equivalent permission to add overloads to the free functions.
[ 2009-06-16 Lawrence adds: ]
I recommend allowing non-volatile overloads.
[ 2009-10 Santa Cruz: ]
NAD EditorialResolved. Addressed by N2992.
Proposed resolution: