Floating point atomic load and add

Hello,

I'm wondering how I can create an atomic load and add instruction for floating point values. If I use IRBuilder::CreateAtomicRMW() I get the error message: "atomicrmw operand must have integer type".

I am using LLVM 3.4 and the only system I need to support is x86.

I don't think x86 allows you to use a lock prefix on floating point
instructions, just basic arithmetic and cmpxchg. You'll probably need
to put a loop around cmpxchg instructions to emulate it. (and might
well need to cast the pointers to integer type for the cmpxchg, I know
we talked about allowing floats there but I'm not sure it's happened
yet).

Cheers.

Tim.

Quoting Tim Northover <t.p.northover@gmail.com>:

Hmm, ok. Can you briefly expand on how I should emulate this behavior? I
don't understand what you mean by adding a loop around cmpxchg.

Probably easiest to write down in C:

#include <stdatomic.h>
void foo(_Atomic(float) *addr, float increment) {
  float oldval = *addr, newval;
  do {
    newval = oldval + increment;
  } while (__c11_atomic_compare_exchange_weak(
      addr, &oldval, newval, memory_order_seq_cst, memory_order_relaxed));
}

Basically you keep trying to just swap in the new value until you've
managed to do it atomically (or possibly with an intervening ABA
change, but that doesn't matter usually).

Tim.

Got it. Thanks!

Quoting Tim Northover <t.p.northover@gmail.com>:

  } while (__c11_atomic_compare_exchange_weak(
      addr, &oldval, newval, memory_order_seq_cst, memory_order_relaxed));

Actually, I think this condition is inverted. Should be "while
(!_c11...". Sorry about that.

Tim.

As a followup: could I do a "strong" cmpxchg and leave out the loop? (According to atomic_compare_exchange_weak, atomic_compare_exchange_strong, atomic_compare_exchange_weak_explicit, atomic_compare_exchange_strong_explicit - cppreference.com that is preferable when possible).

Here is (my understanding of) the equivalent LLVM:

void emitAtomicFPAdd(Value *ptr, Value *incr) {
   LoadInst *oldval = builder->CreateLoad(ptr);
   Value *newval = builder->CreateAdd(oldval, incr);
   Instruction *cmpxchg =
     builder->CreateAtomicCmpXchg(ptr, oldval, newval,
         AtomicOrdering::SequentiallyConsistent,
         AtomicOrdering::SequentiallyConsistent);
}

Quoting Tim Northover <t.p.northover@gmail.com>:

No. You could do a strong compare and exchange, leaving the loop in;
but a weak one is better here. If you leave the loop out entirely then
if someone else modifies addr between your first load and the cmpxchg
attempt then you won't change it at all: the cmpxchg will fail and
that'll be the end of it.

The difference is that the weak exchange is allowed to fail even if
the comparison means it should have stored. This makes no difference
on x86, but most RISC targets actually implement a strong cmpxchg as a
loop (carrying on until the failure is a real comparison failure
rather than the spurious ones that architecture can generate):

  1. Load addr.
  2. Compare against expected value, abort if it's different.
  3. Try to store new value, failing if anyone else touched addr (even
just to read) between the 1 and now.
  4. If the store failed goto 1.

Using weak cmpxchg skips the final looping step, which is more
efficient for your purposes because you're just going to have to go
around again in your own loop anyway.

Cheers.

Tim.

Hello,

I'm wondering how I can create an atomic load and add instruction for floating point values. If I use IRBuilder::CreateAtomicRMW() I get the error message: "atomicrmw operand must have integer type".

The AtomicRMW instruction doesn't natively support floating point types. You can emulate what you're looking for with a bitcast of the float to an appropriately sized integer, a AtomicRMW on that, and then a bitcast of the result. This would have the result of CASing in the bitpattern of the original float which is probably what you intend.

AtomicRMW operations in the C11 spec are somewhat insane, as they require saving and restoring the FP state in the compare and exchange loop[1]. It’s probably quite difficult to define an AtomicRMW instructions on floating point values in the IR that would have useful semantics. Anything that does atomic operations on floating point values is likely to have some fairly complex language-level semantics.

David

[1] I think that this can possibly be avoided if you use Intel’s transactional memory support to implement the atomic RMW, as the instructions that change the floating point environment will cause a transaction abort, but I’m not 100% sure.