mirror of https://github.com/google/benchmark.git
* Fix #342: DoNotOptimize causes compile errors on older GCC versions. DoNotOptimize uses inline assembly contraints to tell the compiler what the type of the input variable. The 'g' operand allows the input to be any register, memory, or immediate integer operand. However this constraint seems to be too weak on older GCC versions, and certain inputs will cause compile errors. This patch changes the constraint to 'X', which is documented as "any operand whatsoever is allowed". This appears to fix the issues with older GCC versions. However Clang doesn't seem to like "X", and will attempt to put the input into a register even when it can't/shouldn't; causing a compile error. However using "g" seems to work like "X" with GCC, so for this reason Clang still uses "g". * Try alternative formulation to placate GCC
This commit is contained in:
parent
15e9ebaf83
commit
93bfabc8b8
|
@ -231,7 +231,13 @@ BENCHMARK_UNUSED static int stream_init_anchor = InitializeStreams();
|
|||
#ifndef BENCHMARK_HAS_NO_INLINE_ASSEMBLY
|
||||
template <class Tp>
|
||||
inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp const& value) {
|
||||
// Clang doesn't like the 'X' constraint on `value` and certain GCC versions
|
||||
// don't like the 'g' constraint. Attempt to placate them both.
|
||||
#if defined(__clang__)
|
||||
asm volatile("" : : "g"(value) : "memory");
|
||||
#else
|
||||
asm volatile("" : : "i,r,m"(value) : "memory");
|
||||
#endif
|
||||
}
|
||||
// Force the compiler to flush pending writes to global memory. Acts as an
|
||||
// effective read/write barrier
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
# Enable the tests
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
include(CheckCXXCompilerFlag)
|
||||
|
||||
# NOTE: Some tests use `<cassert>` to perform the test. Therefore we must
|
||||
# strip -DNDEBUG from the default CMake flags in DEBUG mode.
|
||||
|
@ -75,6 +76,11 @@ compile_benchmark_test(skip_with_error_test)
|
|||
add_test(skip_with_error_test skip_with_error_test --benchmark_min_time=0.01)
|
||||
|
||||
compile_benchmark_test(donotoptimize_test)
|
||||
# Some of the issues with DoNotOptimize only occur when optimization is enabled
|
||||
check_cxx_compiler_flag(-O3 BENCHMARK_HAS_O3_FLAG)
|
||||
if (BENCHMARK_HAS_O3_FLAG)
|
||||
set_target_properties(donotoptimize_test PROPERTIES COMPILE_FLAGS "-O3")
|
||||
endif()
|
||||
add_test(donotoptimize_test donotoptimize_test --benchmark_min_time=0.01)
|
||||
|
||||
compile_benchmark_test(fixture_test)
|
||||
|
|
|
@ -9,6 +9,22 @@ std::uint64_t double_up(const std::uint64_t x) __attribute__((const));
|
|||
std::uint64_t double_up(const std::uint64_t x) { return x * 2; }
|
||||
}
|
||||
|
||||
// Using DoNotOptimize on types like BitRef seem to cause a lot of problems
|
||||
// with the inline assembly on both GCC and Clang.
|
||||
struct BitRef {
|
||||
int index;
|
||||
unsigned char &byte;
|
||||
|
||||
public:
|
||||
static BitRef Make() {
|
||||
static unsigned char arr[2] = {};
|
||||
BitRef b(1, arr[0]);
|
||||
return b;
|
||||
}
|
||||
private:
|
||||
BitRef(int i, unsigned char& b) : index(i), byte(b) {}
|
||||
};
|
||||
|
||||
int main(int, char*[]) {
|
||||
// this test verifies compilation of DoNotOptimize() for some types
|
||||
|
||||
|
@ -29,5 +45,8 @@ int main(int, char*[]) {
|
|||
|
||||
benchmark::DoNotOptimize(double_up(x));
|
||||
|
||||
return 0;
|
||||
// These tests are to e
|
||||
benchmark::DoNotOptimize(BitRef::Make());
|
||||
BitRef lval = BitRef::Make();
|
||||
benchmark::DoNotOptimize(lval);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue