[llvm-dev] Adding sanity to the Atomics implementation

Craig, Ben via llvm-dev llvm-dev at lists.llvm.org
Thu Jan 28 07:41:06 PST 2016


I don't have much of substance to add, but I will say that I like the 
proposal (I too prefer Alternative A).  When adding C11 atomic support 
for hexagon, I found it surprising that support for the __sync_* was 
implemented completely differently than the C11 atomics.

On 1/27/2016 1:55 PM, James Knight via llvm-dev wrote:
> Right now, the atomics implementation in clang is a bit of a mess. It 
> has three basically completely distinct code-paths:
>
>  1. There's the legacy __sync_* builtins, which clang lowers directly
>     to atomic IR instructions. Then, the llvm atomic IR instructions
>     themselves can sometimes emit libcalls to __sync_* library
>     functions (which are basically undocumented, and users are often
>     responsible for implementing themselves if they need it).
>  2. There's the new __atomic_* builtins, which clang will, depending
>     on size and alignment and target, lower either to a libcall to a
>     "standardized-by-GCC
>     <https://gcc.gnu.org/wiki/Atomic/GCCMM/LIbrary>" __atomic_*
>     library function (implemented by libatomic), or, to the atomic IR
>     instructions. (Also covered by the same code is the __c11_atomic_*
>     builtins, which are almost-identical clang-specific aliases of the
>     __atomic_* builtins.)
>  3. There's the C11 "_Atomic" type modifier and some OpenMP stuff,
>     which clang lowers into atomic IR or libcalls to __atomic_*
>     library functions, via almost completely separate code from #2.
>     (Note: doesn't apply to C++ std::atomic<>, which gets implemented
>     with the builtins instead). Beyond just a lot of duplicated logic
>     in the code, the _Atomic impl is kinda broken: sometimes it emits
>     llvm IR instructions directly (letting things fall back to
>     __sync_* calls), and sometimes it checks if it should emit a
>     libcall first (falling back to __atomic_* calls). That's pretty
>     bad behavior.
>
>
> I'd like to make a proposal for cleaning this mess up.
>
> BTW, as a sidenote...
> One thing that's important to remember: at least on the C/C++ level, 
> if you support lock-free atomic-ops for a given size/alignment, /ALL/ 
> the atomic ops for that size/alignment must be lock-free. This 
> property is usually quite easy, because you'll have either LL/SC or 
> CAS instructions, which can be used to implement any other operation. 
> However, many older CPU models support atomic load, store, and 
> exchange operations, but are missing any way to do an atomic 
> compare-and-swap. This is true for at least ARMv5, SPARCv8, and Intel 
> 80386. When your minimum CPU is set to such a cpu model, all atomic 
> operations must be done via libcall -- it's not acceptable for 
> atomic_store to emit an atomic "store" instruction, but 
> atomic_fetch_add to require a libcall which gets implemented with a 
> lock. If that were to happen, then atomic_fetch_add could not actually 
> be made atomic versus a simultaneous atomic_store.
>
>
> So anyhow, there's basically two paths I think we could take for 
> cleanup. I like "Alternative A" below better, but would be interested 
> to hear if others have reasons to think the other would be preferable 
> for some reason.
>
> /Both/ alternatives I've suggested will have the effect that the 
> __sync_* builtins in clang will now lower to __atomic_* function calls 
> on platforms without inline atomics (or for unsupported sizes), and 
> C11 atomics will stop being schizophrenic. Clang will cease to ever 
> emit a call to a __sync_* function from any of its builtins or 
> language support. *This could theoretically cause an incompatibility 
> on some target. *
>
> However, I think it ought to be pretty safe: I can't imagine anyone 
> who will use an upgraded compiler has __sync_* functions implemented 
> for their platform, but doesn't have the __atomic_* library functions 
> implemented. The __atomic_* builtins (which already use those library 
> calls) are in widespread use, notably, both in libstdc++ and libc++, 
> as well as in a lot of third-party code. IMO it's worth having that 
> potential incompatibility, in order to simplify the situation for 
> users (only one set of atomic library calls to worry about), and to 
> have a single code-path for atomics in the compiler.
>
>
>
> *Alternative A*: Move all atomic libcall emission into LLVM
>
> In this alternative, LLVM will be responsible for lowering all atomic 
> operations (to inline code or libcalls as appropriate) for all three 
> code-paths listed at the beginning. Clang will emit no libcalls for 
> atomic operations itself.
>
>
> A1) In LLVM: when lowering "store atomic", "load atomic", "atomicrmw", 
> and "cmpxchg" instructions that aren't supported by the target, emit 
> libcalls to the new __atomic_* functions, (rather than the current 
> behavior of calling the legacy __sync_* functions.)
>
> Additionally, I'd like to move the decision to emit a libcall into 
> AtomicExpandPass, and remove the ability to use Expand in ISel to 
> create a libcall for ISD::ATOMIC_*. Putting the decision there allows 
> querying the target, up front, for its supported sizes, before any 
> other lowering decisions (either other parts of AtomicExpandPass and 
> in ISel). When choosing whether to inline or libcall, only the size 
> and alignment of the operation should be considered, and not the 
> operation itself, or the type. This will ensure that the "all or none" 
> property is adhered to.
>
> (Q: what about the implementation of 
> __atomic_is_lock_free/__atomic_always_lock_free in clang? The clang 
> frontend can't query target information from the llvm backend, can it? 
> Is there some other way to expose the information of what sizes are 
> supported by a backend so that the clang builtins -- the latter of 
> which must be a C++ constant expression -- can also use it? Or...just 
> continue duplicating the info in both places, as is done today...)
>
> A2) In clang, start removing the code that knows how to do optimized 
> library call lowering for atomics -- always emit llvm atomic ops. 
> Except for one case: clang will still need to emit library calls 
> itself for data not aligned naturally for its size. The LLVM atomic 
> instructions currently will not handle unaligned data, but unaligned 
> data is allowed for the four "slab of memory" builtins (__atomic_load, 
> __atomic_store, __atomic_compare_exchange, and __atomic_exchange).
>
> A3) In LLVM, add "align" attributes to cmpxchg and atomicrmw, and 
> allow specifying "align" values for "load atomic" and "store atomic" 
> (where the attribute currently exists but cannot be used). LLVM will 
> then be able to lower misaligned accesses to library calls. In clang, 
> get rid of special case for directly emitting libcalls for misaligned 
> atomics, and lower to llvm instructions there, as well.
>
> A4) Hopefully, now, the three codepaths in clang will be sufficiently 
> the same (as they're all now just creating llvm atomic instructions) 
> that they can be trivially merged, or else they are so trivial that 
> the remaining duplication is not worthwhile to merge.
>
>
>
>
>
> *Alternative B*: Move all libcall emission for atomics into Clang.
>
> In this alternative, LLVM will /never/ emit atomic libcalls from the 
> atomic IR instructions. If the operation requested is not possible on 
> a given target, that is an error. So, the cleanups here are to get 
> clang to stop emitting LLVM IR atomics that cannot be lowered without 
> libcalls.
>
> B1) In Clang: have the legacy __sync_* builtins become essentially 
> aliases for the __atomic_* builtins (thus they will emit calls to 
> __atomic_* library functions when applicable).
>
> B2) In Clang: Have the C11 _Atomic type support and openmp stuff call 
> into the __atomic builtins' code to do their dirty work, instead of 
> having its own separate implementation.
>
> B3) After those two changes, I believe clang will only ever emit 
> atomic IR instructions when they can be lowered. So then, in LLVM: get 
> rid of the fallback to libcalls to __sync_* from the atomic IR 
> instructions. If an atomic IR operation is requested and not 
> implementable lock-free, it will be an error, with no fallback.
>
>
>
> _______________________________________________
> LLVM Developers mailing list
> llvm-dev at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev

-- 
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20160128/02c89579/attachment-0001.html>


More information about the llvm-dev mailing list