<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Thu, Jan 28, 2016 at 5:36 PM, Joerg Sonnenberger via llvm-dev <span dir="ltr"><<a href="mailto:llvm-dev@lists.llvm.org" target="_blank">llvm-dev@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><span>On Thu, Jan 28, 2016 at 08:32:31AM -0800, Reid Kleckner via llvm-dev wrote:<br>
> I think Clang should continue to duplicate this information, the same way<br>
> we duplicate target datalayout strings. Other than that, sure, we can let<br>
> LLVM expand IR operations to libcalls. I don't immediately see a problem<br>
> with that.<br>
<br>
</span>Note that a libcall doesn't necessarily mean using locks. </blockquote><div><br></div><div>Yes, and having possibly-lock-free atomics is fine -- __atomic_is_lock_free has a fallback to a libcall if the compiler doesn't know the answer is "true", for that exact reason.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">With one</blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
exception, NetBSD provides lock-free CAS on all platforms for natural<br>
argument sizes. The intersection between platforms with MP support and<br>
platforms without hardware CAS is SPARCv8. Everything else works fine,<br>
even the libcall version.</blockquote><div><br></div><div><div>Indeed, with kernel support (magic restartable sequences, or a syscall), lock-free atomics can be provided for any uniprocessor architecture. So, linux on ARM provides a memory page you can jump to, which contains a normal un-atomic instruction sequence on uniprocessor ARMv5s, or actual ll/sc instructions on ARMv6+. And for the ARMv5 implementation, the kernel arranges to magically restart the nonatomic sequence from the beginning if it's interrupted in the middle, thus making it act as if it were atomic. (<a href="https://lwn.net/Articles/314561/" target="_blank">https://lwn.net/Articles/314561/</a> is a nice explanation). I see that NetBSD has something similar for restartable instruction sequences.<br></div></div><div><div><br></div><div>After some further investigation on how this is all supposed to hang together, I do need to modify my plan slightly. The detail I neglected to take account of earlier is that some platforms don't just have <i>potentially</i> lock-free library functions (e.g., depending on the CPU model you detect at runtime), but rather, can have <i>guaranteed</i> lock-free library functions via this kernel support.</div><div><br></div><div>For any target that has kernel-supported lock-free atomics, the LLVM target should claim those atomic sizes as supported and clang should return true from __atomic_always_lock_free. By claiming them supported as if they were supported by native instructions, AtomicExpandPass will let them through unscathed to ISel.</div><div><br></div><div><div>Then, the change in plan: I actually will preserve the <span style="color:rgb(35,35,35);font-size:12.8px">ability to expand to libcalls from within ISel, for this use-case only. The libcall names for these routines will only be defined on those CPU+OS combinations which implement this functionality.</span></div></div><div><span style="color:rgb(35,35,35);font-size:12.8px"><br></span></div><div>In GCC, the supported-through-kernel atomic ops expand to a __sync_* libcall, which is provided by the compiler runtime support library libgcc.a (on the targets in question). It's not <i>necessary</i> for GCC to emit a libcall, an inline syscall would be fine too sometimes, but currently it always emits a call.</div><div><br></div><div>Like my plan for LLVM, GCC only enables these on some architectures (grep for "init_sync_libfuncs"): Linux OS, on ARM, 68000, Nios2, PA-Risc, and Super-H chips.</div><div><br></div><div><div>Note that unlike with the __atomic_* library calls, these target-specific libcalls <i>are</i> okay to mix and match with CPU instructions since they must be guaranteed lock-free. It is also okay to include potentially multiple copies of the functions into a executable image, since they're stateless, which is why it's okay for them to live in libgcc.a (not libgcc_s.so).</div></div></div><div><br></div><div><div><br></div></div><div><span style="color:rgb(35,35,35);font-size:12.8px">BTW, regarding NetBSD in particular: it appears as though the implementation of the __sync_* functions in its libc sometimes use locks, when the target is built with the generic "</span><font color="#232323"><span style="font-size:12.8px">atomic_init_testset.c" implementation, and then runs on a multiprocessor system. I think that might happen if you compiled your binary for an armv5, but then actually ran it on a multiprocessor armv6+ system? If I've read that right (which I'm not at all sure I have), then llvm can't properly depend on NetBSD's __sync_* functions to be always lock-free, at least at the moment.</span></font></div></div></div></div>