I was searching for a programming technique that would ensure variables used for benchmarking (without observable side effects) won't be optimized away by the compiler
This gives some info, but I ended up using folly and the following function
/**
* Call doNotOptimizeAway(var) against variables that you use for
* benchmarking but otherwise are useless. The compiler tends to do a
* good job at eliminating unused variables, and this function fools
* it into thinking var is in fact needed.
*/
#ifdef _MSC_VER
#pragma optimize("", off)
template <class T>
void doNotOptimizeAway(T&& datum) {
datum = datum;
}
#pragma optimize("", on)
#else
template <class T>
void doNotOptimizeAway(T&& datum) {
asm volatile("" : "+r" (datum));
}
#endif
I want to use the above, but I have little understanding of its workings. I'm mostly interested in the non VC++ portion and why/how the line
asm volatile("" : "+r" (datum));
creates a non optimizable context or why is this something one would choose to implement such a thing. Also a comparison between the 2 methods would be interesting (I don't know how pragma optimize
works but it looks like a cleaner solution - non portable though)
There is no standard way to disable optimisations, so if you need to disable optimisations, you're limited to whatever your implementation happens to provide. It doesn't make sense to compare the two approaches unless you find a compiler that supports them both.
Anyway, in GCC,
asm volatile("" : "+r" (datum));
means that unverified assembly code supplied by the user is embedded into the assembly generated by GCC. The first string literal (""
) contains the assembly code to inject. It's empty, so there isn't actually any code that gets emitted at all.
The part after the :
informs GCC about the effect of the assembly code. "+r" (datum)
means that GCC should assume that the assembly code reads and modifies datum
. Even though it doesn't. The reason for that is that any earlier calculations that end up storing a value in datum
cannot be discarded as unnecessary. At the same time, the assembly code itself cannot be discarded as unnecessary, because of the potential modification to datum
. volatile
also marks the assembly code as code that must not be optimised away, as documented here:
GCC's optimizers sometimes discard asm
statements if they determine there is no need for the output variables. Also, the optimizers may move code out of loops if they believe that the code will always return the same result (i.e. none of its input values change between calls). Using the volatile
qualifier disables these optimizations. [...]
It seems a bit much to use two different approaches to prevent the assembly code from being removed, really, but I guess it's best to be sure.
The r
constraint means that the code does not care all that much which register GCC makes available for the assembly code to use, and is documented here:
‘r’
A register operand is allowed provided that it is in a general register.
The +
modifier means that the code may read from and write to datum
, and is documented here:
‘+’
Means that this operand is both read and written by the instruction. [...]