As a preamble, I want to make it clear that I know that Zig is not C, nor is it beholden to C’s semantics.
That said, some quotes from the C standard:
An access to an object through the use of an lvalue of volatile-qualified type is a volatile access. A volatile access to an object, modifying an object, modifying a file, or calling a function that does an of those operations are all side effects, which are changes in the state of the execution environment.
next:
In the abstract machine, all expressions are valuated as specified by the semantics. 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 through volatile access to an object).
and finally:
Volatile accesses to objects are evaluated strictly according to the rules of the abstract machine.
Accordingly, using volatile
in C to prevent optimization from interfering with benchmarks is fairly commonplace. Naively, I would have done the same.
The language reference for Zig on volatile also refers to the volatile
qualifier making use of a pointer so qualified a side effect.
It also says that volatile is unrelated to concurrency or atomics, and that use for anything other than MMIO is probably a bug.
It’s said that every safety regulation is written in blood, and I’m sure there are good reasons to take pains to make this point. There’s a good article about ways to screw yourself over with volatile, which I managed to find again, it is especially acute about using volatile to try and order atomic operations, which just won’t work. One of the other points is that volatile is buggy on some older compilers, when used to prevent an optimization. But not LLVM.
So the questions which prompted this: is volatile
in Zig meant to deviate from what it means in C (and C++, if it matters)? Does it currently, is this meant to retain the option to make it differ?
Relatedly, is your intention with this warning to steer users toward doNotOptimizeAway for this sort of purpose? Should benchmarks which get deoptimized using volatile, but not with doNotOptimizeAway
, be considered a bug in the latter?
Because the “probably” in the statement about volatile
probably being a bug if it isn’t MMIO is doing some heavy lifting. If the goal is to deoptimize a microbenchmark, and volatile
succeeds in that goal, then the program is performing to requirements.