[PATCH] libstdc++: Add mem_order_hle_acquire/release to atomic.h
Jonathan Wakely
jwakely.gcc@gmail.com
Fri Nov 9 19:56:00 GMT 2012
On 9 November 2012 19:43, Andi Kleen wrote:
>> So please bear with me while I try to understand what these flags are
>> for - I haven't followed the HLE work and don't know where they're
>> documented (if at all.)
>
> I just submitted a patch to document them. There was a gcc-patches
> discussion some time ago.
>
>>
>> Is it valid to call a.store(1, memory_order_hle_acquire) or are they
>> only valid as modifiers on other memory orders?
>
> The compiler currently warns and forces acquire for hle_acquire
> (or release for hle_release)
>
>> If they're not valid on their own then I would suggest the modifies
>> should be a separate type, and overload operator| like so:
>>
>> enum __memory_order_hle_mod
>> {
>> __memory_order_hle_acquire = 0x10000,
>> __memory_order_hle_release = 0x20000
>> };
>>
>> constexpr memory_order
>> operator|(memory_order __m, __memory_order_hle_mod __mod)
>> {
>> return memory_order(__m | __mod);
>> }
>>
>> This ensures users *cannot* call a.store(1,
>> __memory_order_hle_acquire) because it's the wrong type, but they
>
> They would get a warning in any case.
Only if a compile-time constant is used, if it's passed in as a
function parameter it won't be:
extern void clear_it(std::atomic<int>& a, memory_order m);
void clear_it(std::atomic<int>& a, memory_order m)
{
a.clear(m);
}
>> *can* call a.store(1, memory_order_acquire|__memory_order_hle_acquire)
>> because that calls the overloaded operator which returns the right
>> type.
>
> Ok. Thanks.
Here's an untested implementation of that idea:
enum __memory_order_hle_mod
{
__memory_order_hle_mask = 0x0ffff,
__memory_order_hle_acquire = 0x10000,
__memory_order_hle_release = 0x20000
};
constexpr memory_order
operator|(memory_order __m, __memory_order_hle_mod __mod)
{
return memory_order(__m | int(__mod));
}
constexpr memory_order
operator&(memory_order __m, __memory_order_hle_mod __mod)
{
return memory_order(__m & int(__mod));
}
Which would avoid the casts in the member functions:
void
clear(memory_order __m = memory_order_seq_cst) noexcept
{
auto __b = (__m & memory_order_mask);
__glibcxx_assert(__b != memory_order_consume);
__glibcxx_assert(__b != memory_order_acquire);
__glibcxx_assert(__b != memory_order_acq_rel);
__atomic_clear (&_M_i, __m);
}
I assume __b will be completely optimised away when the assertions are
disabled, and we can add __attribute__((unused)) later if needed, to
prevent warnings with -Wsystem-headers
We could define operator^ and |= etc. if they might be needed:
memory_order&
operator|=(memory_order& __m, __memory_order_hle_mod __mod)
{
return __m = memory_order(__m | int(__mod));
}
We could even keep the constexpr on __cmpexch_failure_order if we
wanted (also untested):
constexpr memory_order
__cmpexch_failure_order2(memory_order __m) noexcept
{
return __m == memory_order_acq_rel ? memory_order_acquire
: __m == memory_order_release ? memory_order_relaxed : __m;
}
constexpr memory_order
__cmpexch_failure_order(memory_order __m) noexcept
{
return memory_order(__cmpexch_failure_order2(__m & __memory_order_hle_mask)
| (__m & __memory_order_hle_acquire)
| (__m & __memory_order_hle_release));
}
More information about the Libstdc++
mailing list