According to C++ standards:
An evaluation A carries a dependency to an evaluation B if - the value of A is used as an operand of B, unless:
— B is an invocation of any specialization of std::kill_dependency (29.3), or
— A is the left operand of a built-in logical AND (&&, see 5.14) or logical OR (||, see 5.15) operator, or
— A is the left operand of a conditional (?:, see 5.16) operator, or
— A is the left operand of the built-in comma (,) operator (5.18); (...)
I can understand why the dependency ordered before relationship would stop upon kill_dependency call, but why operators such as logical AND, OR, comma, etc. would also break the dependency chain?
Does it mean the code below has undefined behavior?
//thread1
int y = 2
atomicVal.store(true);
//thread2
auto x = atomicVal.load(std::memory_order_consume);
cout << x && y;
memory_order_consumewas an attempt to expose an asm-level CPU feature for use in C++. (It's temporarily deprecated until it can be reworked to something that compilers can implement in practice, and that doesn't require so muchkill_dependencynoise in the source). Understanding the CPU behaviour is key to understanding the design of the C++ stuff designed to expose it.It's all about data dependencies, not control dependencies like conditional branches. C++11: the difference between memory_order_relaxed and memory_order_consume and [[carries_dependency]] what it means and how to implement have some more details.
e.g. an
add x2, x2, x3instruction can't execute until both its input registers are ready, and neither canldr w1, [x2]perform the load until the address is ready, so ifx2came from another load, it's automatically ordered before this one. (Assuming CPU hardware is designed not to violate cause-and-effect, e.g. by doing value-prediction or whatever DEC Alpha did to violate causality in rare cases). Butcbz w1, reg_was_zerocan be predicted, so it's not sufficient to makereg_was_zero: ldr w3, [x4]wait for a load that produced w1. (This is AArch64 asm, BTW, a weakly-ordered ISA that guarantees dependency-ordering.)Short-circuit evaluation of
||orleft && rightis logically the same as anif(left) right, so branch prediction + speculative execution can be expected to run the right-hand side even if the left-hand side hasn't executed yet. There's no data dependency, only a control dependency.And obviously comma
left, rightdoesn't create any connection at all between the sides, it's basically a way to cramleft; right;into a single expression.Of course, if you use the same variable in both left and right sides, a data-dependency can exist that way, but it's not created by the operator.