4 ms·
> Since I've already provided a concrete example of what you asked for, You... really did not. I asked for code that is correct on x86 or ARM with a consume l
by ajross 3y ago
> Since I've already provided a concrete example of what you asked for,
You... really did not. I asked for code that is correct on x86 or ARM with a consume load and incorrect without.
> I'm instead going to try to tackle head-on what I think is preventing you from understanding
I think I'd understand it much better if you gave me the concrete example that I'm asking for and which you keep saying exists. Frankly at this point I think I'm done being patient and waiting for the explanation in the expectation I'm going to learn something, it's clear it's not going to arrive. Mostly: I don't believe you, I think it's you that are failing to understand the issue and not me, and I'll go on with my more comfortable hardware-level understanding of memory ordering and continue to ignore the pontifications of those in the language standard community. Sorry if that's frustrating.
- jcranmer 3y agoHere's the example: int i = load(p, memory_order_consume); if (i == 3) { int y = x[i]; } If you replace the memory_order_consume with a regular load, or a memory_order_relaxed, your code will be broken, even on x86 or ARM. The compiler can, and in this case likely will (yay constant propagation), rewrite the subsequent load in such a way that it is no longer data-dependent on the atomic load. It is not a compiler bug; if you try to report it as such, the compiler implementers will take one look at your problem report, and tell you that it is your code that is broken, use memory_order_consume. You will similarly get no sympathy from the C or C++ standards committees, for this is precisely why memory_order_consume was invented. > Mostly: I don't believe you, I think it's you that are failing to understand the issue and not me As someone who works on a compiler, and who sits on language standards committees, when I am explaining to you how someone who works on a compiler and who sits on language standards committees will read the standard, it's not because I fail to understand how to do so. I do realize that the way the standards are read and interpreted does not come naturally to most, which is why I gave that long explanation. Perhaps you do not wish to engage with the specification on this level of understanding. That is fine--but a consequence is that you will not be able to properly understand the reason for certain features, like memory_order_consume. At the very least, I hope you can agree to stop spreading misinformation like "the purpose of memory_order_consume is to support the Alpha processor."
- kazinator 3y agoI would hope that this paradigm requires all participating accesses to be annotated: int i = load(p, memory_order_consume); if (i == 3) { int y = load(x[i], memory_order_consume); } it seems like bad design to require ordering between plain loads and annotated loads. We want to identify the two locations that are important, so the compiler can reorder the others however it sees fit, without regard as to their placement w.r.t. those two.
- gpderetta 3y agoNo, loads from x need not be consume nor even need to be atomic. If the thread that last wrote to x and then i never touches x again, there is no possible data race. This is for example the case of for initialization guards.
- kazinator 3y agoOK, so p is here like a lock, and x[] is protected data. Indeed; we don't want to have to do anything special with the data protected by the lock. But accesses to the data must not cross the point where the lock is manipulated; e.g. if i == 3 means we own the lock, so that we may access x, x must not be accessed before that check by an optimization.
- gpderetta 3y agoIf p is like by a lock, the compiler won't reorder the access outside of the lock but it can still take into account that i is a known constant to simplify the address computation of x[i] into x[3]. This is perfectly safe for a mutex protected variable as the mutex acquire will, in addition to the compiler barrier, provide the required hardware barriers. This is is catastrophic, if, instead of relying on an hardware barrier, we rely on a load-load dependency chain originating from i; rewriting x[i] into x[3] break the chain and now, while the compiler might still not reorder the access, the hardware very much can.
- 3y ago