mirror of
https://github.com/google/benchmark.git
synced 2024-12-27 04:50:19 +08:00
dfdda57a12
Non-const DoNotOptimize() can't compile when used with some types. Example of code which can't compile: char buffer3[3] = ""; benchmark::DoNotOptimize(buffer3); Error message: error: impossible constraint in 'asm' asm volatile("" : "+r"(value) : : "memory"); Introduced in8545dfb
(Fix DoNotOptimize() GCC copy overhead (#1340) (#1410)) The cause is compiler can't work with the +r constraint for types that can't be placed perfectly in registers. For example, char array[3] can't be perfectly fit in register on x86_64 so it requires placed in memory but constraint doesn't allow that. Solution - Use +m,r constraint for the small objects so the compiler can decide to use register or/and memory - For the big objects +m constraint is used which allows avoiding extra copy bug(see #1340) - The same approach is used for the const version of DoNotOptimize() although the const version works fine with the "r" constraint only. Using mixed r,m constraint looks more general solution. See - Issue #1340 ([BUG] DoNotOptimize() adds overhead with extra copy of argument(gcc)) - Pull request #1410 (Fix DoNotOptimize() GCC copy overhead (#1340) #1410) - Commit8545dfb
(Fix DoNotOptimize() GCC copy overhead (#1340) (#1410))
82 lines
1.9 KiB
C++
82 lines
1.9 KiB
C++
#include <cstdint>
|
|
|
|
#include "benchmark/benchmark.h"
|
|
|
|
namespace {
|
|
#if defined(__GNUC__)
|
|
std::int64_t double_up(const std::int64_t x) __attribute__((const));
|
|
#endif
|
|
std::int64_t double_up(const std::int64_t x) { return x * 2; }
|
|
} // namespace
|
|
|
|
// 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
|
|
|
|
char buffer1[1] = "";
|
|
benchmark::DoNotOptimize(buffer1);
|
|
|
|
char buffer2[2] = "";
|
|
benchmark::DoNotOptimize(buffer2);
|
|
|
|
char buffer3[3] = "";
|
|
benchmark::DoNotOptimize(buffer3);
|
|
|
|
char buffer8[8] = "";
|
|
benchmark::DoNotOptimize(buffer8);
|
|
|
|
char buffer20[20] = "";
|
|
benchmark::DoNotOptimize(buffer20);
|
|
|
|
char buffer1024[1024] = "";
|
|
benchmark::DoNotOptimize(buffer1024);
|
|
benchmark::DoNotOptimize(&buffer1024[0]);
|
|
|
|
const char const_buffer1[1] = "";
|
|
benchmark::DoNotOptimize(const_buffer1);
|
|
|
|
const char const_buffer2[2] = "";
|
|
benchmark::DoNotOptimize(const_buffer2);
|
|
|
|
const char const_buffer3[3] = "";
|
|
benchmark::DoNotOptimize(const_buffer3);
|
|
|
|
const char const_buffer8[8] = "";
|
|
benchmark::DoNotOptimize(const_buffer8);
|
|
|
|
const char const_buffer20[20] = "";
|
|
benchmark::DoNotOptimize(const_buffer20);
|
|
|
|
const char const_buffer1024[1024] = "";
|
|
benchmark::DoNotOptimize(const_buffer1024);
|
|
benchmark::DoNotOptimize(&const_buffer1024[0]);
|
|
|
|
int x = 123;
|
|
benchmark::DoNotOptimize(x);
|
|
benchmark::DoNotOptimize(&x);
|
|
benchmark::DoNotOptimize(x += 42);
|
|
|
|
benchmark::DoNotOptimize(double_up(x));
|
|
|
|
// These tests are to e
|
|
benchmark::DoNotOptimize(BitRef::Make());
|
|
BitRef lval = BitRef::Make();
|
|
benchmark::DoNotOptimize(lval);
|
|
}
|