In Chandler Carruth's CppCon 2015 talk he introduces two magical functions for defeating the optimizer without any extra performance penalties.
For reference, here are the functions (using GNU-style inline assembly):
void escape(void* p)
{
asm volatile("" : : "g"(p) : "memory");
}
void clobber()
{
asm volatile("" : : : "memory");
}
It works on any compiler which supports GNU-style inline assembly (GCC, Clang, Intel's compiler, possibly others). However, he mentions it doesn't work in MSVC.
Examining Google Benchmark's implementation, it seems they use a reinterpret cast to a volatile const char&
and passes it to a function hidden in a different translation unit on non-gcc/clang compilers.
template <class Tp>
inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp const& value) {
internal::UseCharPointer(&reinterpret_cast<char const volatile&>(value));
}
// some other translation unit
void UseCharPointer(char const volatile*) {}
However, there are two concerns I have with this:
- I'm potentially incurring a function call
- There is the possibility a "clever" link-time optimizer might recognize UseCharPointer is small, inline it, then discard all the code I wanted kept around, or a "clever" optimizer might be allowed to perform other re-orderings I don't want it to.
Is there any lower-level equivalent in MSVC to the GNU-style assembly functions? Or is this the best it gets on MSVC?