From 74e82e822f55871a969b1642019d57639d9a4eb4 Mon Sep 17 00:00:00 2001 From: Albert Pretorius Date: Wed, 25 May 2016 07:31:20 +0100 Subject: [PATCH] Force DoNotOptimize operand to memory for both gcc and clang --- AUTHORS | 1 + CONTRIBUTORS | 1 + include/benchmark/benchmark_api.h | 10 ++++----- test/CMakeLists.txt | 3 +++ test/donotoptimize_test.cc | 36 +++++++++++++++++++++++++++++++ 5 files changed, 45 insertions(+), 6 deletions(-) create mode 100644 test/donotoptimize_test.cc diff --git a/AUTHORS b/AUTHORS index 7ddffd8c..0f93e01d 100644 --- a/AUTHORS +++ b/AUTHORS @@ -8,6 +8,7 @@ # # Please keep the list sorted. +Albert Pretorius Arne Beer Christopher Seymour David Coeurjolly diff --git a/CONTRIBUTORS b/CONTRIBUTORS index af402921..4bff126f 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -22,6 +22,7 @@ # # Please keep the list sorted. +Albert Pretorius Arne Beer Billy Robert O'Neal III Chris Kennelly diff --git a/include/benchmark/benchmark_api.h b/include/benchmark/benchmark_api.h index 9bf38a8e..4167553f 100644 --- a/include/benchmark/benchmark_api.h +++ b/include/benchmark/benchmark_api.h @@ -210,20 +210,18 @@ Benchmark* RegisterBenchmarkInternal(Benchmark*); // expression from being optimized away by the compiler. This function is // intented to add little to no overhead. // See: http://stackoverflow.com/questions/28287064 -#if defined(__clang__) && defined(__GNUC__) +#if defined(__GNUC__) // TODO(ericwf): Clang has a bug where it tries to always use a register // even if value must be stored in memory. This causes codegen to fail. // To work around this we remove the "r" modifier so the operand is always // loaded into memory. +// GCC also has a bug where it complains about inconsistent operand constraints +// when "+rm" is used for a type larger than can fit in a register or two. +// For now force the operand to memory for both GCC and Clang. template inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp const& value) { asm volatile("" : "+m" (const_cast(value))); } -#elif defined(__GNUC__) -template -inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp const& value) { - asm volatile("" : "+rm" (const_cast(value))); -} #else template inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp const& value) { diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 7d75c112..247c6300 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -39,6 +39,9 @@ add_test(diagnostics_test diagnostics_test --benchmark_min_time=0.01) 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) +add_test(donotoptimize_test donotoptimize_test --benchmark_min_time=0.01) + compile_benchmark_test(fixture_test) add_test(fixture_test fixture_test --benchmark_min_time=0.01) diff --git a/test/donotoptimize_test.cc b/test/donotoptimize_test.cc new file mode 100644 index 00000000..e4453fbb --- /dev/null +++ b/test/donotoptimize_test.cc @@ -0,0 +1,36 @@ +#include "benchmark/benchmark.h" + +#include + +namespace { +#if defined(__GNUC__) + std::uint64_t double_up(const std::uint64_t x) __attribute__ ((const)); +#endif + std::uint64_t double_up(const std::uint64_t x) { + return x * 2; + } +} + +int main(int, char*[]) { + + // this test verifies compilation of DoNotOptimize() for some types + + char buffer8[8]; + benchmark::DoNotOptimize(buffer8); + + char buffer20[20]; + benchmark::DoNotOptimize(buffer20); + + char buffer1024[1024]; + benchmark::DoNotOptimize(buffer1024); + benchmark::DoNotOptimize(&buffer1024[0]); + + int x = 123; + benchmark::DoNotOptimize(x); + benchmark::DoNotOptimize(&x); + benchmark::DoNotOptimize(x += 42); + + benchmark::DoNotOptimize(double_up(x)); + + return 0; +}