1

The C Standard says

An actual implementation need not evaluate part of an expression if it can deduce that its value is not used and that no needed side effects are produced (including any caused by calling a function or accessing a volatile object)

When is a volatile variable not needed? According to this paragraph, volatile appears to become subject to the as-if rule just like any other non-volatile object.


The answers given in the non-duplicate linked question are not helpful to me as they do not address the above quoted paragraph

  • When is a value considered to be "used"? It appears to be different than "reading the value from an object" because the corresponding access can be omitted, according to the above quote.
  • What is a "needed side effect"?

Refer to the comments below.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • 1
    @alex no. I dont see that quote in that question. **this question is not about volatile in general** – Johannes Schaub - litb Apr 20 '13 at 09:52
  • 2
    That stupid box above my question saying that perhaps an answer may be found in some random volatile question is annoying. How can i remove it? – Johannes Schaub - litb Apr 20 '13 at 09:56
  • @JohannesSchaub-litb I don't see it above the question, but it is still in the right-pane linked list. – WhozCraig Apr 20 '13 at 10:01
  • @JohannesSchaub-litb, could you then provide a better title to your question? – Jens Gustedt Apr 20 '13 at 10:23
  • @jens done, fair point. Please consider reopening it. – Johannes Schaub - litb Apr 21 '13 at 17:33
  • In the mean time I put my answer to a comment: you have to be carefull with words (it is the standard :). That doesn't talk about a variable but about the value. If the **value** is not needed in the expression, the access can be optimized out. If the value is needed a "load" has to take place, even if the compiler can deduce the value. – Jens Gustedt Apr 21 '13 at 21:06
  • @jens an access is defined as either being a write or a read. The paragraph says "including any caused by accessing a volatile object" in conjunction with your interpretation appeara to mean that a write can be optimized away, but a read may not? (Because that would use its value). Sounds a bit odd. Can you please elaborate? – Johannes Schaub - litb May 06 '13 at 22:25
  • Perhaps this comes down to: when is a value "used" and when not? – Johannes Schaub - litb May 06 '13 at 22:28
  • @JohannesSchaub-litb, no a write to a `volatile` can never be optimized away. A write is a "needed" side effect on the underlying object, since it changes it. A read may or many not be a "needed" side effect. It may for example be "needed" if the object represents an IO register or similar, and not needed otherwise. So it is left to the implementation to determine that. – Jens Gustedt May 07 '13 at 08:08
  • @jens that does not appear to be concousive. If the written variable is never accessed again, the write is not needed by the program, right? Where then is the difference to a read? – Johannes Schaub - litb May 07 '13 at 08:50
  • @JohannesSchaub-litb, for `volatile` there is no "never read again" because access to such an object might be asynchronous, e.g in a signal handler, return from a `longjmp`, or by C11, from another thread. The execution model does not allow to speculate on these. For read this is different, even if another part of the program has written to the variable, we might skip a read if we don't use it. We don't control the effects that our write might have to other parts of the program, but we may control the effects that the writes of others have, if we don't use the value. – Jens Gustedt May 07 '13 at 09:49

5 Answers5

1

This part of the standard intents to say that the volatile read in the following code can be removed as it will never be evaluated:

volatile a;
if (0 && a) something();

but not the volatile read in the next one

volatile a;
int b;
b = 0*a;

As a follow up on the discussion around mehrdad's answer: I do think that J.3.10

J.3 Implementation-defined behavior

J.3.10 Qualifiers

— What constitutes an access to an object that has volatile-qualified type (6.7.3).

means that a compiler can define a volatile access to mean nothing and thus allows itself to basically ignore it. Of course it then can not implement any signals either, but it is allowed to ignore the existence of asynchronous signals. The only place where it can not ignore volatile is around a longjmp.

Of course such a choice makes this compiler useless for any serious system development, but some applications don't require it and the standard allows a compliant implementation for such simple architectures and their applications.

Bryan Olivier
  • 5,207
  • 2
  • 16
  • 18
1

I think they're probably referring to situations like

void test(int volatile *y)
{
    int x = *y;
}

int main(void)
{
    test(some_volatile_y);
    return 0;
}

where the load from memory could be optimized away (unevaluated), because its result is not necessarily needed on every implementation. (Of course, on implementations where a memory load can trigger some event, then of course the result is "needed" and cannot be optimized away.)


Thanks to Alex's comment below for pointing out this footnote in the C standard (C99: 6.7.3 Type qualifiers: footnote 114):

A volatile declaration may be used to describe an object corresponding to a memory-mapped input/output port or an object accessed by an asynchronously interrupting function. Actions on objects so declared shall not be ‘‘optimized out’’ by an implementation or reordered except as permitted by the rules for evaluating expressions.

Note that it says may -- it's giving an example. A the clause J.3 then mentions that what constitutes access to an object that has a volatile-qualified type is implementation-defined, which makes sense: the previous clause was an example of what "access" could mean, but it could mean something else depending on the implementation.

So, on implementations where the system knows this can't cause any needed side effect, the volatile access may be removed.

user541686
  • 205,094
  • 128
  • 528
  • 886
  • -1. The volatile in `test()` must be accessed even if its value isn't used/needed. – Alexey Frunze Apr 20 '13 at 09:52
  • @AlexeyFrunze: What does "access" even mean in terms of C's abstract machine? And what makes you think what you said is true? – user541686 Apr 20 '13 at 09:52
  • 1
    But how will the implementation know that the access is not needed? My watchdog may need it. – Johannes Schaub - litb Apr 20 '13 at 09:57
  • @JohannesSchaub-litb: Well your implementation knows what it supports and what it doesn't support -- if it supports watchdog-like behavior, then it already knows it can't optimize this away, because as the implementation knows, the result could clearly be "needed". If not, C simply says that it doesn't prevent it from doing so. (It really wouldn't make sense otherwise -- what sense would it make for C to *force* the implementation to load from memory even when the implementation can prove it can't affect anything?) On the other hand, with whole-program analysis, anything might be provable... – user541686 Apr 20 '13 at 09:59
  • 1
    C99: 6.7.3 Type qualifiers: footnote 114 `A volatile declaration may be used to describe an object corresponding to a memory-mapped input/output port or an object accessed by an asynchronously interrupting function. Actions on objects so declared shall not be ‘‘optimized out’’ by an implementation or reordered except as permitted by the rules for evaluating expressions.` At the same time, J.3 Implementation-defined behavior: `What constitutes an access to an object that has volatile-qualified type`. So, at least you should mention the latter. – Alexey Frunze Apr 20 '13 at 10:02
  • However, it's not entirely clear how to interpret the existence of both clauses. – Alexey Frunze Apr 20 '13 at 10:03
  • @AlexeyFrunze: The first clause just says where volatile "*may* be used", in order to give practical examples. The second clause says that it's the implementation's job to actually define what "access" means -- those were just examples, and they don't necessarily make sense in every implementation. – user541686 Apr 20 '13 at 10:04
  • OK, then use the quotes instead of what you wrote originally. – Alexey Frunze Apr 20 '13 at 10:05
  • It should likely also be noted that 6.7.3.7 dictates "Therefore any expression referring to such an object shall be evaluated strictly according to the rules of the abstract machine, as described in 5.1.2.3." Going there, and in particular, paragraph 4, the very heart of the question. I know most of the peeps on this thread know this, but the interested passer-by may not. – WhozCraig Apr 20 '13 at 10:07
  • If my compiler vendor optimized out the `x = *y;` coming from that function, because `x` is not used, I'd be most disappointed and write a very angry email to their support organization. I don't believe that this is a valid case of "it may be optimized out" - have you actually seen this, and if so, what compiler? – Mats Petersson Apr 20 '13 at 10:15
  • That is better. How about correcting `it has no needed side effects`? 5.1.2.3c2 states `Accessing a volatile object, modifying an object, modifying a file, or calling a function that does any of those operations are all side effects, which are changes in the state of the execution environment.` – Alexey Frunze Apr 20 '13 at 10:18
  • @MatsPetersson: I don't think that (1) the C standard was based on whether you would write an angry email to your compiler vendor, (2) that the existence or lack of a compiler that actually performs the access has any bearing on the meaning of the clause, or that (3) your compiler implementation even falls under the set of implementations which can prove that `x` is not needed to begin with. Like I said above, the implementation has to be able to prove `x` cannot be needed, which may or may not be true depending on the implementation. – user541686 Apr 20 '13 at 10:20
  • @AlexeyFrunze: I reworded it a bit, I think I'll leave it like this. Thanks for the quotes! – user541686 Apr 20 '13 at 10:22
  • 2
    @Mehrdad: I am not objecting to `x` being given a value. But `*y` must be "read", otherwise my watchdog timer may kill my machine, just because `x` is not being used - how do you ensure that a variable that you don't actually need to use gets used. There is definitely a side-effect from `*y` [unless the compiler actually knows what `*y` is pointing at, and can determine from the fact that it is pointing at "regular memory, and a read from that is not doing anything else", but I can't see how a compiler can determine that, unless we're talking REALLY restricted HW] – Mats Petersson Apr 20 '13 at 10:31
  • 1
    @Mats - A compiler can just *know* what the system looks like. If it runs on some special purpose hardware, it might know that all watchdog timers are attached to I/O ports and not ever memory mapped. Then a memory read cannot have a side effect, because it is RAM only. – Bo Persson Apr 20 '13 at 13:17
0

I think the key point here is "evaluate part of an expression". So, if we have:

volatile int *wd_ptr = (volatile int *)0xF9000000;   // My watchdog timer. 

#define FREQUENCY_MULTIPLIER (4.9171E6/1000)

void wd_tickle()
{
    int time_left;

    time_left = (int)*wd_ptr * FREQUENCY_MULTIPLIER; 
    // Side effect of reading the , resets the timer to it's programmed value.
#if WD_DEBUG
    if (time_left < 100000)
    {
        printf("Oops, less than 100000 ticks left on watchdog.\n"
               "Maybe you need to tickle the watchdog a bit more often\n");
    }
#endif
}

Now, the compiler can eliminate the floating point multiplication that we get from calculating time-left, but it MUST NOT remove the access to *wd_ptr.

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
0

When is a volatile variable not needed?

It seems to me that you might be misunderstanding 5.1.2.3p4. If a compiler can prove both of the following, then it can optimise an expression away:

  1. Its value is not used.
  2. No needed side effects are produced (including any caused by calling a function or accessing a volatile object).

In summary, a compiler can't optimise an expression that accesses a volatile object.


Does the compiler decide now whether I need a side effect on a volatile access or not?

The standard decides that, and the compiler decides by being a conforming implementation. 5.1.2.3p6: Accesses to volatile objects are evaluated strictly according to the rules of the abstract machine.

autistic
  • 1
  • 3
  • 35
  • 80
  • It says "no needed access to a volatile obje t is produced" it seems to me. – Johannes Schaub - litb Apr 20 '13 at 10:57
  • Read it that way, if you like. That doesn't change the meaning: In order for a compiler to optimise an expression away, it must be able to deduce that the expression doesn't access volatile objects (among other things). – autistic Apr 20 '13 at 11:06
-1

If I (now) understand the question properly, you're asking why the standard says "needed side effects", and whether that implies that a compliant compiler could elide accesses that it could prove were not "needed" in some way.

My plain reading is simply that they are using "needed side effects" to indicate that side effects are always needed, rather than as a modifier, and that they could have simply eliminated "needed" from the paragraph above without changing the meaning.

(However, I don't have a copy of the standard to confirm whether it identifies whether a side effect can be determined to be "needed" or not. It seems unlikely.)

Malcolm Rowe
  • 747
  • 3
  • 14