Commit 93bfabc8 by Eric Committed by Dominic Hamon

Fix #342: DoNotOptimize causes compile errors on older GCC versions. (#398)

* 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
parent 15e9ebaf
...@@ -231,7 +231,13 @@ BENCHMARK_UNUSED static int stream_init_anchor = InitializeStreams(); ...@@ -231,7 +231,13 @@ BENCHMARK_UNUSED static int stream_init_anchor = InitializeStreams();
#ifndef BENCHMARK_HAS_NO_INLINE_ASSEMBLY #ifndef BENCHMARK_HAS_NO_INLINE_ASSEMBLY
template <class Tp> template <class Tp>
inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp const& value) { 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"); 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 // Force the compiler to flush pending writes to global memory. Acts as an
// effective read/write barrier // effective read/write barrier
......
# Enable the tests # Enable the tests
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
include(CheckCXXCompilerFlag)
# NOTE: Some tests use `<cassert>` to perform the test. Therefore we must # NOTE: Some tests use `<cassert>` to perform the test. Therefore we must
# strip -DNDEBUG from the default CMake flags in DEBUG mode. # strip -DNDEBUG from the default CMake flags in DEBUG mode.
...@@ -75,6 +76,11 @@ compile_benchmark_test(skip_with_error_test) ...@@ -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) add_test(skip_with_error_test skip_with_error_test --benchmark_min_time=0.01)
compile_benchmark_test(donotoptimize_test) 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) add_test(donotoptimize_test donotoptimize_test --benchmark_min_time=0.01)
compile_benchmark_test(fixture_test) compile_benchmark_test(fixture_test)
......
...@@ -9,6 +9,22 @@ std::uint64_t double_up(const std::uint64_t x) __attribute__((const)); ...@@ -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; } 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*[]) { int main(int, char*[]) {
// this test verifies compilation of DoNotOptimize() for some types // this test verifies compilation of DoNotOptimize() for some types
...@@ -29,5 +45,8 @@ int main(int, char*[]) { ...@@ -29,5 +45,8 @@ int main(int, char*[]) {
benchmark::DoNotOptimize(double_up(x)); benchmark::DoNotOptimize(double_up(x));
return 0; // These tests are to e
benchmark::DoNotOptimize(BitRef::Make());
BitRef lval = BitRef::Make();
benchmark::DoNotOptimize(lval);
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment