[cfe-dev] atomic intrinsics
John McCall
rjmccall at apple.com
Fri Oct 15 18:05:07 PDT 2010
On Oct 15, 2010, at 5:03 PM, Howard Hinnant wrote:
> Thanks for looking at this John.
>
> On Oct 15, 2010, at 7:21 PM, John McCall wrote:
>
>> On Oct 7, 2010, at 5:30 PM, Howard Hinnant wrote:
>>> I see what you mean. I'll mention this in the design doc. I believe it will be an issue for any design we choose (A, B, or C).
>>
>>
>> After some thought, I think I personally prefer proposal A, slightly modified such that __atomic_is_lock_free is a pseudofunction like __is_pod().
>
> I see, like:
>
> bool __atomic_is_lock_free(type);
>
> ?
That's what I was thinking.
>> The builtins have exactly those names and are "overloaded"; memory ordering parameters are required to be constant expressions but not necessarily literals.
>
> If the memory orderings are required to be constant expressions, this is really Design B, just with some renaming.
I see what you mean. I hadn't actually realized that the library actually takes these as runtime parameters; that seems very un-C++-ish to me. Certainly it's not very "pay for what you use", although I guess the presumption is that it will quickly optimize to the right thing.
> This is not a problem for libc++. However I've heard rumblings that this won't be ok for the C library. Want to comment Blaine?
Are the committees actually going to agree enough here to permit re-use? The main advantage of requiring the parameters to be constant expressions is that the builtins don't become intimately tied to a specific library. I'm very concerned about building compiler APIs on top of competing and incomplete standards.
If we accept this as a runtime argument, we will invoke undefined behavior on out-of-range enumerators. Is that acceptable to C and C++?
>> Arguments not of fundamental type, or not exactly matching a permitted type for the intrinsic, are not required to be supported by the implementation (so calling swap with a long* and an int, or a Base** and a Derived*, or a ConvertibleToIntPtr and a ConvertibleToInt, may or may not have sensible results).
>
> I'm afraid my spec is ambiguous, sorry. In:
>
> bool __atomic_compare_exchange_strong(type* atomic_obj,
> type* expected, type desired,
> int mem_success, int mem_failure);
>
> It was my intention that in each argument that specifies "type", the types are all required to be the same.
Right, I just clarifying that.
> In C++ templates, this would be:
>
> template <class type>
> bool __atomic_compare_exchange_strong(type* atomic_obj,
> type* expected, type desired,
> int mem_success, int mem_failure);
>
> Concerning arguments "type" that are not scalars: I believe I can handle this in libc++ with some fancy template meta programming, and pass them through to the front end type-punned as scalars if there is a scalar of the appropriate size, and otherwise route them to a library-lock function. I can do this because "type" is a-priori known to be trivially copyable.
Okay. If the libraries need to work with arbitrary trivially-copyable types, we should definitely do that in the builtins instead of in the library. I'm willing to have the builtins take trivially-copyable types.
>> This doesn't strictly matter for you, but we would implement this in Clang by having the frontend do the ABI-compliant lowerings for the locking implementations and then emitting everything that can be done lock-free as an LLVM intrinsic call.
>
> Does this translate to a call to compiler-rt for the locking implementations? I ask because I'm probably going to be the one to implement these in compiler-rt if they are needed.
Multiple calls, I think; an explicit acquire and release call. Unless you think there's some benefit in having your compiler-rt function implement memcpy?
Note that these functions become platform ABI requirements.
John.
More information about the cfe-dev
mailing list