One of my colleagues came up with an example that breaks at least “if all writes have the same value then use that value”. Using it to break byte requires some creativity.
Consider the following program (two threads running in parallel):
1 {
2 X_na = 1; // meaning "non-atomic write to X"
3 X_na = 0; // consider this the "initialization write"
4 Y_rel = 1; // release-write to Y
5 X_na = 0;
6 }
7 ||
8 {
9 if(Y_acq){ // acquire-read from Y
10 a = X_na;
11 }
12}
When executing line 10, we see two possible writes to pick from (the ones from lines 3 and 5). Both have the same value. However, LLVM can optimize the first thread to remove line 3: That write is redundant because it gets overwritten in line 5, and the fact that there is a release write does not matter because lines 3 and 5 are non-atomic accesses.
We can almost, but not quite get there with bytes. Something not too dissimilar from the above situation can still arise with byte. Like, when I do
let mut buf = BytesMut::with_capacity(1);
buf = BytesMut::with_capacity(1024);
and when the compiler inlines all of that and reuses the same storage for the second buffer, the buf.inner.arc will first be KIND_INLINE and then later KIND_VEC (matching lines 2 and 3 of the example above). If we then send a pointer to the buf away, that will look like lines 4 and 9.
The one thing we do not get, I think, is line 5. We can, I guess trigger an atomic write to buf.inner.arc by doing something with buf that would make it change the pointer, but I am not familiar enough with this data structure to say what that would be and I am also not sure if the optimization mentioned above is still legal when line 5 is changed to be atomic (I asked my colleague).
Still, the fact that you can overwrite an existing BytesMut with a new one means that the KIND of one of these pointers can change, if you consider the entire lifetime of the location it is stored into (which you have to). So it’s not like all writes have the same KIND, just the ones that the non-atomic read can choose from – and as the example above shows, that on its own is not sufficient to make your argument work. It might be that BytesMut does something else that would be a sufficient condition, but it’s certainly more complex than we thought.