5

The below code example is from a Chinese blog which introduces the effect of volatile. The left side is the C code; the other is the generated assembly code.

// cordering.c                                gcc -O2 -S -masm=intel cordering.c

int A;
volatile int B;
void foo()                                    mov   eax, DWORD PTR B[rip]
{                                             mov   DWORD PTR B[rip], 0
    A = B + 1;                                add   eax, 1
    B = 0;                                    mov   DWORD PTR A[rip], eax
}                                             ret

As we can see in the assembly code, the side-effect of A is placed after the side-effect of B, even though B is volatile qualified. However, cppreference.com says:

[W]ithin a single thread of execution, volatile accesses cannot be optimized out or reordered with another visible side effect that is sequenced-before or sequenced-after the volatile access.

Here the side-effect of A is sequenced before B, so I think it's illegal for the compiler to do this. Am I right?


As a supplement, the blog said if we want to guarantee the sequence between a volatile and non-volatile type, we need to make both volatile:

// cordering.c                                gcc -O2 -S -masm=intel cordering.c

volatile int A;
volatile int B;
void foo()                                    mov   eax, DWORD PTR B[rip]
{                                             add   eax, 1
    A = B + 1;                                mov   DWORD PTR A[rip], eax
    B = 0;                                    mov   DWORD PTR B[rip], 0
}                                             ret
Boann
  • 48,794
  • 16
  • 117
  • 146
choxsword
  • 3,187
  • 18
  • 44
  • 不是不应该添加图片,而是添加代码图片是不必要的,更何况有中文。 – con ko Apr 14 '18 at 08:27
  • @Constructor 老哥稳。我就是懒得自己手打,而且有汇编的话不知道怎么排版才能跟图片一致。 – choxsword Apr 14 '18 at 08:30
  • @bigxiao markdown很好用的(滑稽),然后汇编的话,在行尾注释吧 – con ko Apr 14 '18 at 08:31
  • 1
    This is an English only site, please don't use other languages. And you should [edit] your question to fix problems – Passer By Apr 14 '18 at 09:38
  • The code looks a lot like C code. Perhaps not the best example if you ask about C++ corner cases? I would stay away from any site trying to teach the non-existent language "C/C++". – Bo Persson Apr 14 '18 at 09:49
  • +1 for editing the question and using english. You could also consider providing a [live example](https://godbolt.org/g/bL4HzY). @BoPersson I'm also extremely frustrated by the amount of people / sites that believe "C/C++" is a thing. – gflegar Apr 14 '18 at 09:59
  • Another interesting observation is that nethier icc nor clang do this reordering, it seems to be gcc-specific. – gflegar Apr 14 '18 at 10:02
  • @PasserBy He said that if he doesn't use picture, he thinks the alignment effect can't be shown perfectly. – con ko Apr 14 '18 at 12:17
  • @Constructor One reason why you should be using english, and I believe PasserBy's link explains perfectly what are the problems with images. I don't think that alignment is that important, and the code can always be supplemented with a link to [godbolt](https://godbolt.org/) to get even better alignment. – gflegar Apr 14 '18 at 12:34
  • @GoranFlegar Yes, you're right. To post high-quality question, one should do as you say. And I just very amazing to find Chinese on this site, so I used Chinese, sorry, I won't do that anymore. – con ko Apr 14 '18 at 12:37

1 Answers1

5

The page you linked says:

Every access (read or write operation, member function call, etc.) made through a glvalue expression of volatile-qualified type is treated as a visible side-effect for the purposes of optimization (that is, within a single thread of execution, volatile accesses cannot be optimized out or reordered with another visible side effect that is sequenced-before or sequenced-after the volatile access.

Thus, if A is not volatile, accesses to A are not treated as visible side-effects, and the second statement doesn't apply (as it doesn't say anything about reordering visible and non-visible accesses).

EDIT: Note that cppreference is not official documentation for C++, but a community effort. I do believe that the intent of the statement in bold was to define what a visible side-effect is, but it is not written clearly.

The definitive reference is the C++ standard (here are some options for getting it). The N4659 standard draft, defines side-effects in [intro.execution], paragraph 14, and visible side-effects through a 2-page chain of definitions in [intro.races]. I am not an expert on the C++ standard, so I cannot decipher what exactly the standard says without significant effort, but you are welcome to give it a try.

However, for an informal explanation of what optimizations the compiler is allowed to do, you can take a look at the as-if rule on cppreference.

EDIT 2: the standard also formally specifies the as-if rule in [intro.execution], paragraph 7:

The least requirements on a conforming implementation are:
(7.1) — Accesses through volatile glvalues are evaluated strictly according to the rules of the abstract machine.
(7.2) — At program termination, all data written into files shall be identical to one of the possible results that execution of the program according to the abstract semantics would have produced.
(7.3) — The input and output dynamics of interactive devices shall take place in such a fashion that prompting output is actually delivered before a program waits for input. What constitutes an interactive device is implementation-defined.

In short, any optimization is valid, as long as the program produces the same output, and the reads and writes to volatile objects happen in the correct order, which holds for your original example.

gflegar
  • 1,583
  • 6
  • 22
  • What does **visible** means here?I'm confused about that. **Visible** to whom? – choxsword Apr 14 '18 at 08:23
  • That's what the bold statement is telling you "visible side-effect" = "access made through an expression of volatile-qualified type", so the expression `A` is not volatile-qualified, and not visible, and `B` is, so it is visible. – gflegar Apr 14 '18 at 08:26
  • So **visible** is just a definition literally and has no other understandable meanings? – choxsword Apr 14 '18 at 08:29
  • That is my understanding, however cppreference is not an official document, and can have errors. See updated answer. – gflegar Apr 14 '18 at 09:28
  • 2
    Trying to translate to plain English: "visible side effect" just means that it was the last side effect to modify that particular object. If the modification hasn't taken place yet, it's not visible. If a later modification to the same object has already taken place, the earlier modification is no longer visible. –  Apr 14 '18 at 22:59
  • @hvd and how do you define "last" (and "later" and "earlier")? I believe this is also something that the standard is trying to define, as it is not clear what it means in a multithreaded setting. Does it mean according to "wall-clock" - i.e. the real time that something happened, or is it according to some partial ordering? – gflegar Apr 14 '18 at 23:03
  • 2
    @GoranFlegar The latter. The *very* short story of what it's saying is that `volatile` doesn't mean you can avoid cross-thread synchronisation, you still need that to make side effects visible. I'm not sure how to translate that to plain English in more detail. –  Apr 14 '18 at 23:11
  • @hvd thanks, I trust you it's not easy to explain (otherwise they wouldn't need 2 pages in the standard for it). For mere mortals (that don't want to write their own compiler), I would say that as-if rule is enough to reason about programs :) – gflegar Apr 14 '18 at 23:19