9

I know that generally a modern C++ compiler and processor will perform certain optimizations by sometimes reordering instructions for better performance.

C++11 introduces a sequenced before relation. And if instruction A comes before instruction B in program order, we say that A is sequenced before B.

int data = 0;
bool ready = 0;

// A is sequenced before B
data = 6;      // A
ready = true;  // B

C++11 also defines a requirement for sequenced before relation.

Given any two evaluations A and B, if A is sequenced before B, then the execution of A shall precede the execution of B.

This puzzles me. To me, it conflicts with out-of-order executions because the reordering may break the above required property. E.g., when store to ready happens before store to data.

Does the definition above stop instruction reordering? (I'm pretty sure it's not. But what did I miss?)

Eric Z
  • 14,327
  • 7
  • 45
  • 69
  • 2
    Just a guess: maybe the compiler doesn't try to optimize statements with unknown side-effects (such as certain function calls). Here's a [related thread](http://stackoverflow.com/a/9581666/645270). – keyser Aug 13 '14 at 13:33
  • 4
    This rule applies to the C++ virtual machine, the real machine may internally behave differently as long as its output is indistinguishable to that the virtual machine would provide. – Vality Aug 13 '14 at 13:46

1 Answers1

9

Since "sequenced before" (in this instance) only applies to a single thread:

Sequenced before is an asymmetric, transitive, pair-wise relation between evaluations executed by a single thread [...]

§1.9 [intro.execution]

And since the compiler/CPU can perform whatever transformations they wish provided the code executes as if it followed the standard:

A conforming implementation executing a well-formed program shall produce the same observable behavior as one of the possible executions of the corresponding instance of the abstract machine with the same program and the same input.

§1.9 [intro.execution]

Arbitrary reorderings may (or may not) occur.

Note that special rules apply between threads. See §1.10 [intro.multithread].

  • I guess I don't quite understand how it relates to my question. – Eric Z Aug 13 '14 at 14:10
  • The compiler/CPU can do whatever it wants provided the program **seems** to run as if operations were sequenced according to the rule-in-question. How they are actually sequenced is not relevant, provided an observer cannot tell the difference. – Robert Allan Hennigan Leahy Aug 13 '14 at 14:11
  • 1
    Then how do you explain the quote given by @EricZ? (*Given any two evaluations A and B, if A is sequenced before B, then the execution of A shall precede the execution of B.*) – mtvec Aug 13 '14 at 14:18
  • Did you read my answer? The standard allows implementations to do anything they want, provided the program executes **as if** it executed according to the standard. This is called the [as if rule](http://en.cppreference.com/w/cpp/language/as_if). Click on the link there if the standardese doesn't make sense to you. – Robert Allan Hennigan Leahy Aug 13 '14 at 14:20
  • @Job I think I get to it now, together with Vality's comment above. The rules in the Standard are all based on a C++ virtual machine where there is no reordering. For a real machine, as long as it has the same visible effect as the virtual machine, it's free to reorder. – Eric Z Aug 13 '14 at 14:23
  • 1
    Maybe it helps to realize how it was in the single-threaded pre-C++11 world: The language defines a sequenced order of operations and the compiler is free to reorder them under the _as-if rule_ (that is, the resulting program behaves the same). What changed with C++11 is that you may now have threads that are actually able to observe that the order was changed, so the _as-if_ rule does not apply to them. Resolving this dilemma is quite difficult (even if the compiler does not reorder, the hardware may, so just disallowing it does not accomplish anything), see the cited §1.10. – ComicSansMS Aug 13 '14 at 14:24
  • @RobertAllanHenniganLeahy IIRC, the "as-if" rule only applies to single thread, right? – Eric Z Aug 13 '14 at 14:28
  • @ComicSansMS That history lesson makes a lot of sense! – Eric Z Aug 13 '14 at 14:30
  • It applies to the entire program. The "as-if" rule from the standard is pasted in my answer, and I've also provided a link to the [cppreference article on it](http://en.cppreference.com/w/cpp/language/as_if) (there it is again). – Robert Allan Hennigan Leahy Aug 13 '14 at 14:30
  • @EricZ The _as-if_ rule applies, as always. The only thing that changed is how ordering in a program is defined. In a single-threaded context, there is _sequenced-before_ and nothing else. In a multithreaded context, stuff gets (much) more complicated. – ComicSansMS Aug 13 '14 at 14:31
  • @EricZ: Indeed, you're right. So I guess the simple answer is that your quote talks about execution on the *abstract machine* and not about execution on a real machine. – mtvec Aug 13 '14 at 14:33
  • @Job Exactly! As long as the outputs of that real machine have the same observable behavior as the abstract one, as seen by that single thread itself. Note that other threads may observe a different order, and that's why different synchronization primitives (atomics, barrier, etc) come into play. – Eric Z Aug 13 '14 at 14:37