I have a question regarding the consistency of atomic memory operations
(AMOs) and regular write operations. Imagine the following example:
The memory at location a0 is initially 0. Two harts execute the following
sequence of instructions simultaneously:
Hart 0:
li t0, 10
amo.add t1, t0, (a0)
Hart 1:
li t2, 2
sw t2, (a0)
After both harts have executed these instructions, I see the following
possible outcomes:
- t1=0, (a0)=2
(The AMO was executed before the store operation.) - t1=2, (a0)=12
(The AMO was executed after the store operation.) - t1=0, (a0)=10
(The AMO was translated into a read operation (reading 0) and a
write operation (a0 <-- 10). The store of hart 1 (a0 <-- 2) was
executed between the AMO's read and write operation and therefore
overwritten by it.)
In the third scenario, one might argue that the AMO was not executed
atomically due to the store in between the AMO's read and write. But the
question is: Must AMOs be consistent with regular store operations or only
with other AMOs?
The question is closely linked to the programming model. Is there any
guarantee on the value of a shared memory location that is written using
regular stores? An 'AMO-consistent' write can easily be achieved by using
an amo.swap operation and discarding the return value. Therefore, the
programming model could require writing to shared memory locations only
using AMOs to guarantee consistency. Regular stores might be lost.
A special case of this question concerns the store-conditional. Is it
possible that the result of a successful store-conditional is 'overseen' by
an AMO and therefore lost?
The reason for this question is that some memory controllers and buses do
not offer any ordering guarantee of reads with respect to writes. In such
cases it is very expensive to ensure that no write in flight to the memory
gets overtaken by the read operation of an AMO.