[AVR] Improve 8/16 bit atomic operations
authorAyke van Laethem <aykevanlaethem@gmail.com>
Sat, 20 Feb 2021 19:51:38 +0000 (20:51 +0100)
committerAyke van Laethem <aykevanlaethem@gmail.com>
Sat, 24 Jul 2021 12:03:26 +0000 (14:03 +0200)
commit431a9414655ba4825a46e6765ef50a0b4ef7e101
tree24adb5dbf37572ff517180333503129e871e995a
parent8544ce80f881a33a2c4c8e234709d136b52fa4d8
[AVR] Improve 8/16 bit atomic operations

There were some serious issues with atomic operations. This patch should
fix the biggest issues.

For details on the issue take a look at this Compiler Explorer sample:
https://godbolt.org/z/n3ndhn

Code:

    void atomicadd(_Atomic char *val) {
        *val += 5;
    }

Output:

    atomicadd:
        movw    r26, r24
        ldi     r24, 5     ; 'operand' register
        in      r0, 63
        cli
        ld      r24, X     ; load value
        add     r24, r26   ; value += X
        st      X, r24     ; store value back
        out     63, r0
        ret                ; return the wrong value (in r24)

There are various problems with this.

 - The value to add (5) is stored in r24. However, the value to add to
   is loaded in the same register: r24.
 - The `add` instruction adds half of the pointer to the loaded value,
   instead of (attempting to) add the operand with value 5.
 - The output value of the cmpxchg instruction (which is not used in
   this code sample) is the new value with 5 added, not the old value.
   The LangRef specifies that it has to be the old value, before the
   operation.

This patch fixes the first two and leaves the third problem to be fixed
at a later date. I believe atomics were mostly broken before this patch,
with this patch they should become usable as long as you ignore the
output of the atomic operation. In particular it fixes the following
things:

 - It sets the earlyclobber flag for the input ('$operand' operand) so
   that the register allocator puts it in a different register than the
   output value.
 - It fixes a number of issues with the pseudo op expansion pass, for
   example now it adds the $operand field instead of the pointer. This
   fixes most machine instruction verifier issues (other flagged issues
   are unrelated to atomics).

Differential Revision: https://reviews.llvm.org/D97127
llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp
llvm/lib/Target/AVR/AVRInstrInfo.td