Philip Reames
2014-May-24 21:17 UTC
[LLVMdev] Why can't atomic loads and stores handle floats?
Looking through the documentation, I discovered that atomic loads and stores are only supported for integer types. Can anyone provide some background on this? Why is this true? Currently, given code: std::atomic<float> aFloat; void foo() { float f = atomic_load(&aFloat); .. } Clang generates code like:|| %"struct.std::atomic.2" = type { float } @aFloat = global %"struct.std::atomic.2" zeroinitializer, align 4 define void @foo() { %1 = load atomic i32* bitcast (%"struct.std::atomic.2"* @aFloat to i32*) seq_cst, align 4 %2 = bitcast i32 %1 to float ... } This seems less than ideal. I would expect that we might have to desugar floats into integer & cast operations in the backend, but why is this imposed on the frontend? More generally, is there anyone who is knowledgeable and/or working on atomics and synchronization in LLVM? I've got a number of questions w.r.t. semantics and have found a number of what I believe to be missed optimizations. I'm happy to file the later, but I'd like to talk them over with a knowledgeable party first. Philip -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20140524/d69780f9/attachment.html>
Filip Pizlo
2014-May-24 22:18 UTC
[LLVMdev] Why can't atomic loads and stores handle floats?
What is the downside of the currently generated IR? There ain't nothin' wrong with bitcasts, IMO. -Filip> On May 24, 2014, at 2:17 PM, Philip Reames <listmail at philipreames.com> wrote: > > Looking through the documentation, I discovered that atomic loads and stores are only supported for integer types. Can anyone provide some background on this? Why is this true? > > Currently, given code: > std::atomic<float> aFloat; > void foo() { > float f = atomic_load(&aFloat); > .. > } > > Clang generates code like: > %"struct.std::atomic.2" = type { float } > @aFloat = global %"struct.std::atomic.2" zeroinitializer, align 4 > > define void @foo() { > %1 = load atomic i32* bitcast (%"struct.std::atomic.2"* @aFloat to i32*) seq_cst, align 4 > %2 = bitcast i32 %1 to float > ... > } > > This seems less than ideal. I would expect that we might have to desugar floats into integer & cast operations in the backend, but why is this imposed on the frontend? > > More generally, is there anyone who is knowledgeable and/or working on atomics and synchronization in LLVM? I've got a number of questions w.r.t. semantics and have found a number of what I believe to be missed optimizations. I'm happy to file the later, but I'd like to talk them over with a knowledgeable party first. > > Philip > _______________________________________________ > LLVM Developers mailing list > LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20140524/2e259708/attachment.html>
David Chisnall
2014-May-25 11:31 UTC
[LLVMdev] Why can't atomic loads and stores handle floats?
On 24 May 2014, at 23:18, Filip Pizlo <fpizlo at apple.com> wrote:> What is the downside of the currently generated IR? There ain't nothin' wrong with bitcasts, IMO.It's problematic because it means that you'll end up generating an integer store even if your hardware support load-linked / store-conditional (or cmpxchg) from floating point registers. This means an extra floating point to integer register copy (and the reverse and back if it fails for an atomicrmw loop) and that typically involves some complex pipeline interlocking on modern processors so is very expensive. It also means you need to allocate an extra integer register, even though the underlying hardware may support the original form. You can hack around this a bit in the back end, but you end up with the back end trying to figure out what the front end meant (and, on some architectures, store ordering semantics from integer and floating point registers are different, so this isn't necessarily possible anyway, as you can be turning two constructs that have different semantics to the front and back ends into the same thing in the IR). We're currently unable to express atomic pointer loads and stores on our architecture for a similar reason: the hardware supports separate fat pointer registers, which are wider than the widest integer registers (and interact with tag bits) and implements a load-linked and store-conditional for them, C11 supports atomic operations on pointers, but LLVM IR doesn't (or didn't, not sure if this is fixed now). In short, it's only a problem if you care about architectures outside of ARM and x86. David P.S. To correctly implement C11 semantics for atomic operations on floats, we also need to be able to model floating point environment state, which we can't.
Philip Reames
2014-May-26 18:49 UTC
[LLVMdev] Why can't atomic loads and stores handle floats?
David provided one good answer. I'll give another. The current design pushes complexity into the language frontend for - as far as I know - no good reason. I can say from recent experience that the corner cases around atomics are both surprising and result in odd looking hacks in the frontend. To say this differently, why should marking loads and stores atomic required me to rewrite largish chunks of code around the load or store? There's nothing "wrong" per se with that design, but why complicate a bunch of frontends when a single IR level desugarring pass could preform the same logic? Another answer would be that bitcasts make the IR less readable. They consume memory. Unless handled carefully, they inhibit optimizations. (i.e. if you forget to strip casts in a peephole optimization) When dealing with large IR files from a language where *every* field access is atomic "unordered", the first two are particularly important. p.s. I'm currently operating under the assumption that there is no *technical* reason LLVM could represent atomic loads and stores on floating point types. If this is not true, please correct me. Philip On 05/24/2014 03:18 PM, Filip Pizlo wrote:> What is the downside of the currently generated IR? There ain't > nothin' wrong with bitcasts, IMO. > > -Filip > > On May 24, 2014, at 2:17 PM, Philip Reames <listmail at philipreames.com > <mailto:listmail at philipreames.com>> wrote: > >> Looking through the documentation, I discovered that atomic loads and >> stores are only supported for integer types. Can anyone provide some >> background on this? Why is this true? >> >> Currently, given code: >> std::atomic<float> aFloat; >> void foo() { >> float f = atomic_load(&aFloat); >> .. >> } >> >> Clang generates code like:|| >> %"struct.std::atomic.2" = type { float } >> @aFloat = global %"struct.std::atomic.2" zeroinitializer, align 4 >> >> define void @foo() { >> %1 = load atomic i32* bitcast (%"struct.std::atomic.2"* @aFloat to >> i32*) seq_cst, align 4 >> %2 = bitcast i32 %1 to float >> ... >> } >> >> This seems less than ideal. I would expect that we might have to >> desugar floats into integer & cast operations in the backend, but why >> is this imposed on the frontend? >> >> More generally, is there anyone who is knowledgeable and/or working >> on atomics and synchronization in LLVM? I've got a number of >> questions w.r.t. semantics and have found a number of what I believe >> to be missed optimizations. I'm happy to file the later, but I'd >> like to talk them over with a knowledgeable party first. >> >> Philip >> _______________________________________________ >> LLVM Developers mailing list >> LLVMdev at cs.uiuc.edu <mailto:LLVMdev at cs.uiuc.edu> http://llvm.cs.uiuc.edu >> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20140526/ea492052/attachment.html>