On Sun, Jun 06, 2021 at 11:04:49AM -0700, Linus Torvalds wrote: > On Sun, Jun 6, 2021 at 4:56 AM Segher Boessenkool > <segher@xxxxxxxxxxxxxxxxxxx> wrote: > > > > And that is a simple fact, since the same assembler code (at the same > > spot in the program) will do the same thing no matter how that ended up > > there. > > The thing is, that's exactl;y what gcc violates. > > The example - you may not have been cc'd personally on that one - was > something like > > if (READ_ONCE(a)) { > barrier(); > WRITE_ONCE(b,1); > } else { > barrier(); > WRITE_ONCE(b, 1); > } > > and currently because gcc thinks "same exact code", it will actually > optimize this to (pseudo-asm): > > LD A > "empty asm" > ST $1,B > > which is very much NOT equivalent to > > LD A > BEQ over > "empty asm" > ST $1,B > JMP join > > over: > "empty asm" > ST $1,B > > join: > > and that's the whole point of the barriers. > > It's not equivalent exactly because of memory ordering. In the first > case, there is no ordering on weak architectures. In the second case, > there is always an ordering, because of CPU consistency guarantees. > > And no, gcc doesn't understand about memory ordering. But that's > exactly why we use inline asms. > > > And the compiler always is allowed to duplicate, join, delete, you name > > it, inline assembler code. The only thing that it cares about is > > semantics of the code, just like for any other code. > > See, but it VIOLATES the semantics of the code. > > You can't join those two empty asm's (and then remove the branch), > because the semantics of the code really aren't the same any more if > you do. Truly. To be fair, the same argument applies even without the asm code. The compiler will translate if (READ_ONCE(a)) WRITE_ONCE(b, 1); else WRITE_ONCE(b, 1); to LD A ST $1,B intstead of LD A BEQ over ST $1,B JMP join over: ST $1,B join: And these two are different for the same memory ordering reasons as above. Alan