Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Must an unused volatile parameter be honoured?

Tags:

c++

c

gcc

If I call a function which has a volatile parameter, and that parameter is not used, must the compiler nonetheless produce the parameter?

void consume( volatile int ) { }

...

consume( some_expr );

GCC does honour this, but I'm uncertain if the wording of volatile in the standards requires this. In my opinion GCC is doing the right thing -- this is logically an assignment to a volatile variable and thus should not be omitted (according to 1.9-8 of the c++ standard)

NOTE: The purpose of this is to prevent the optimizer from removing the evaluation of code. That is, it forces some_expr to be evaluated. It allows the expression to be optimized, but ensures it is actually performed.

I've add C and C++ as tags as the answer to both interests me should there be any differences. I don't think there would be however.

ANSWER: I've picked the first one as I believe it is the correct practical realization of the standard. However, Steve's philosophical viewpoint is very interesting and may in fact mean the standard is ambiguous.

like image 653
edA-qa mort-ora-y Avatar asked Apr 12 '12 12:04

edA-qa mort-ora-y


2 Answers

The unnamed argument of consume cannot be read, since it's unnamed. However, it is initialized, and that initialization (with some_expr) is a visible side-effect. Therefore the compiler may not optimize the initialization out.

Whether this requires the actual evalution of some_expr is another matter. In general that is not a visible side-effect, but it could be if some_expr contains volatile sub-expressions.

[edit] Please note that the "unnamed" part can occur in two places. The caller in general has no way to know whether a parameter is named (let alone used) E.g.

void consume( volatile int x);
consume( some_expr );
// other .cpp
void consume( volatile int ) { } // Same function.
like image 95
MSalters Avatar answered Nov 16 '22 23:11

MSalters


It's possible to argue the opposite, but I think an implementation may omit accesses to automatic volatile objects, provided that they otherwise make no difference to the program and provided also that it either forbids the programmer from observing the stack (via unmapped or read-only pages, debuggers and so on), or at least warns that doing so won't always have the effect you expect. An unnamed parameter fits that description.

The reason is that the "as-if" rule talks about visible side-effects, and says that volatile accesses are visible side-effects. But if the program itself doesn't depend in any way on them, then the standard doesn't say that the object must actually be located "on the stack". The standard allows it to be in a special memory location provided by the hardware, that cannot be read by any means, only written to, and writing to it has no physical effect on the hardware. Since that's permitted, it seems absurd to say it's "required by the standard" that this no-effect write actually goes ahead. How would anyone know? The standard doesn't mandate that there must be instructions in the binary to perform the write, it mandates that the magic, unreadable secret object must assume a particular value. If I claim it has that value, you can't prove I'm wrong :-)

It's not possible to write a conforming program that relies on such a volatile access actually occurring, or to detect whether or not some_expr was evaluated. Really it's between you and your debugger whether it was computed or not. I've seen debuggers go wrong for less.

So, I think an implementation is allowed to break its own debugger, just as it's allowed not to provide a working debugger at all. I don't immediately see why it would want to. In practice I'd expect that marking the parameter volatile has about the same effect as moving the definition of the function somewhere the optimizer can't find it -- it will act to ensure that the value could be used.

like image 40
Steve Jessop Avatar answered Nov 16 '22 22:11

Steve Jessop