Add tests to verify assembler output -- Fix DoNotOptimize. (#530)
* Add tests to verify assembler output -- Fix DoNotOptimize.
For things like `DoNotOptimize`, `ClobberMemory`, and even `KeepRunning()`,
it is important exactly what assembly they generate. However, we currently
have no way to test this. Instead it must be manually validated every
time a change occurs -- including a change in compiler version.
This patch attempts to introduce a way to test the assembled output automatically.
It's mirrors how LLVM verifies compiler output, and it uses LLVM FileCheck to run
the tests in a similar way.
The tests function by generating the assembly for a test in CMake, and then
using FileCheck to verify the // CHECK lines in the source file are found
in the generated assembly.
Currently, the tests only run on 64-bit x86 systems under GCC and Clang,
and when FileCheck is found on the system.
Additionally, this patch tries to improve the code gen from DoNotOptimize.
This should probably be a separate change, but I needed something to test.
* Disable assembly tests on Bazel for now
* Link FIXME to github issue
* Fix Tests on OS X
* fix strip_asm.py to work on both Linux and OS X like targets
2018-03-23 22:10:47 +00:00
|
|
|
#include <benchmark/benchmark.h>
|
|
|
|
|
|
|
|
#ifdef __clang__
|
|
|
|
#pragma clang diagnostic ignored "-Wreturn-type"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
|
|
|
|
extern int ExternInt;
|
|
|
|
extern int ExternInt2;
|
|
|
|
extern int ExternInt3;
|
|
|
|
|
|
|
|
inline int Add42(int x) { return x + 42; }
|
|
|
|
|
|
|
|
struct NotTriviallyCopyable {
|
|
|
|
NotTriviallyCopyable();
|
|
|
|
explicit NotTriviallyCopyable(int x) : value(x) {}
|
2021-11-10 16:22:31 +00:00
|
|
|
NotTriviallyCopyable(NotTriviallyCopyable const &);
|
Add tests to verify assembler output -- Fix DoNotOptimize. (#530)
* Add tests to verify assembler output -- Fix DoNotOptimize.
For things like `DoNotOptimize`, `ClobberMemory`, and even `KeepRunning()`,
it is important exactly what assembly they generate. However, we currently
have no way to test this. Instead it must be manually validated every
time a change occurs -- including a change in compiler version.
This patch attempts to introduce a way to test the assembled output automatically.
It's mirrors how LLVM verifies compiler output, and it uses LLVM FileCheck to run
the tests in a similar way.
The tests function by generating the assembly for a test in CMake, and then
using FileCheck to verify the // CHECK lines in the source file are found
in the generated assembly.
Currently, the tests only run on 64-bit x86 systems under GCC and Clang,
and when FileCheck is found on the system.
Additionally, this patch tries to improve the code gen from DoNotOptimize.
This should probably be a separate change, but I needed something to test.
* Disable assembly tests on Bazel for now
* Link FIXME to github issue
* Fix Tests on OS X
* fix strip_asm.py to work on both Linux and OS X like targets
2018-03-23 22:10:47 +00:00
|
|
|
int value;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Large {
|
|
|
|
int value;
|
|
|
|
int data[2];
|
|
|
|
};
|
|
|
|
}
|
|
|
|
// CHECK-LABEL: test_with_rvalue:
|
|
|
|
extern "C" void test_with_rvalue() {
|
|
|
|
benchmark::DoNotOptimize(Add42(0));
|
|
|
|
// CHECK: movl $42, %eax
|
|
|
|
// CHECK: ret
|
|
|
|
}
|
|
|
|
|
|
|
|
// CHECK-LABEL: test_with_large_rvalue:
|
|
|
|
extern "C" void test_with_large_rvalue() {
|
|
|
|
benchmark::DoNotOptimize(Large{ExternInt, {ExternInt, ExternInt}});
|
|
|
|
// CHECK: ExternInt(%rip)
|
|
|
|
// CHECK: movl %eax, -{{[0-9]+}}(%[[REG:[a-z]+]]
|
|
|
|
// CHECK: movl %eax, -{{[0-9]+}}(%[[REG]])
|
|
|
|
// CHECK: movl %eax, -{{[0-9]+}}(%[[REG]])
|
|
|
|
// CHECK: ret
|
|
|
|
}
|
|
|
|
|
|
|
|
// CHECK-LABEL: test_with_non_trivial_rvalue:
|
|
|
|
extern "C" void test_with_non_trivial_rvalue() {
|
|
|
|
benchmark::DoNotOptimize(NotTriviallyCopyable(ExternInt));
|
|
|
|
// CHECK: mov{{l|q}} ExternInt(%rip)
|
|
|
|
// CHECK: ret
|
|
|
|
}
|
|
|
|
|
|
|
|
// CHECK-LABEL: test_with_lvalue:
|
|
|
|
extern "C" void test_with_lvalue() {
|
|
|
|
int x = 101;
|
|
|
|
benchmark::DoNotOptimize(x);
|
|
|
|
// CHECK-GNU: movl $101, %eax
|
|
|
|
// CHECK-CLANG: movl $101, -{{[0-9]+}}(%[[REG:[a-z]+]])
|
|
|
|
// CHECK: ret
|
|
|
|
}
|
|
|
|
|
|
|
|
// CHECK-LABEL: test_with_large_lvalue:
|
|
|
|
extern "C" void test_with_large_lvalue() {
|
|
|
|
Large L{ExternInt, {ExternInt, ExternInt}};
|
|
|
|
benchmark::DoNotOptimize(L);
|
|
|
|
// CHECK: ExternInt(%rip)
|
|
|
|
// CHECK: movl %eax, -{{[0-9]+}}(%[[REG:[a-z]+]])
|
|
|
|
// CHECK: movl %eax, -{{[0-9]+}}(%[[REG]])
|
|
|
|
// CHECK: movl %eax, -{{[0-9]+}}(%[[REG]])
|
|
|
|
// CHECK: ret
|
|
|
|
}
|
|
|
|
|
|
|
|
// CHECK-LABEL: test_with_non_trivial_lvalue:
|
|
|
|
extern "C" void test_with_non_trivial_lvalue() {
|
|
|
|
NotTriviallyCopyable NTC(ExternInt);
|
|
|
|
benchmark::DoNotOptimize(NTC);
|
|
|
|
// CHECK: ExternInt(%rip)
|
|
|
|
// CHECK: movl %eax, -{{[0-9]+}}(%[[REG:[a-z]+]])
|
|
|
|
// CHECK: ret
|
|
|
|
}
|
|
|
|
|
|
|
|
// CHECK-LABEL: test_with_const_lvalue:
|
|
|
|
extern "C" void test_with_const_lvalue() {
|
|
|
|
const int x = 123;
|
|
|
|
benchmark::DoNotOptimize(x);
|
|
|
|
// CHECK: movl $123, %eax
|
|
|
|
// CHECK: ret
|
|
|
|
}
|
|
|
|
|
|
|
|
// CHECK-LABEL: test_with_large_const_lvalue:
|
|
|
|
extern "C" void test_with_large_const_lvalue() {
|
|
|
|
const Large L{ExternInt, {ExternInt, ExternInt}};
|
|
|
|
benchmark::DoNotOptimize(L);
|
|
|
|
// CHECK: ExternInt(%rip)
|
|
|
|
// CHECK: movl %eax, -{{[0-9]+}}(%[[REG:[a-z]+]])
|
|
|
|
// CHECK: movl %eax, -{{[0-9]+}}(%[[REG]])
|
|
|
|
// CHECK: movl %eax, -{{[0-9]+}}(%[[REG]])
|
|
|
|
// CHECK: ret
|
|
|
|
}
|
|
|
|
|
|
|
|
// CHECK-LABEL: test_with_non_trivial_const_lvalue:
|
|
|
|
extern "C" void test_with_non_trivial_const_lvalue() {
|
|
|
|
const NotTriviallyCopyable Obj(ExternInt);
|
|
|
|
benchmark::DoNotOptimize(Obj);
|
|
|
|
// CHECK: mov{{q|l}} ExternInt(%rip)
|
|
|
|
// CHECK: ret
|
|
|
|
}
|
|
|
|
|
|
|
|
// CHECK-LABEL: test_div_by_two:
|
|
|
|
extern "C" int test_div_by_two(int input) {
|
|
|
|
int divisor = 2;
|
|
|
|
benchmark::DoNotOptimize(divisor);
|
|
|
|
return input / divisor;
|
|
|
|
// CHECK: movl $2, [[DEST:.*]]
|
|
|
|
// CHECK: idivl [[DEST]]
|
|
|
|
// CHECK: ret
|
|
|
|
}
|
|
|
|
|
|
|
|
// CHECK-LABEL: test_inc_integer:
|
|
|
|
extern "C" int test_inc_integer() {
|
|
|
|
int x = 0;
|
2021-11-10 16:22:31 +00:00
|
|
|
for (int i = 0; i < 5; ++i) benchmark::DoNotOptimize(++x);
|
Add tests to verify assembler output -- Fix DoNotOptimize. (#530)
* Add tests to verify assembler output -- Fix DoNotOptimize.
For things like `DoNotOptimize`, `ClobberMemory`, and even `KeepRunning()`,
it is important exactly what assembly they generate. However, we currently
have no way to test this. Instead it must be manually validated every
time a change occurs -- including a change in compiler version.
This patch attempts to introduce a way to test the assembled output automatically.
It's mirrors how LLVM verifies compiler output, and it uses LLVM FileCheck to run
the tests in a similar way.
The tests function by generating the assembly for a test in CMake, and then
using FileCheck to verify the // CHECK lines in the source file are found
in the generated assembly.
Currently, the tests only run on 64-bit x86 systems under GCC and Clang,
and when FileCheck is found on the system.
Additionally, this patch tries to improve the code gen from DoNotOptimize.
This should probably be a separate change, but I needed something to test.
* Disable assembly tests on Bazel for now
* Link FIXME to github issue
* Fix Tests on OS X
* fix strip_asm.py to work on both Linux and OS X like targets
2018-03-23 22:10:47 +00:00
|
|
|
// CHECK: movl $1, [[DEST:.*]]
|
|
|
|
// CHECK: {{(addl \$1,|incl)}} [[DEST]]
|
|
|
|
// CHECK: {{(addl \$1,|incl)}} [[DEST]]
|
|
|
|
// CHECK: {{(addl \$1,|incl)}} [[DEST]]
|
|
|
|
// CHECK: {{(addl \$1,|incl)}} [[DEST]]
|
|
|
|
// CHECK-CLANG: movl [[DEST]], %eax
|
|
|
|
// CHECK: ret
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
|
|
|
// CHECK-LABEL: test_pointer_rvalue
|
|
|
|
extern "C" void test_pointer_rvalue() {
|
|
|
|
// CHECK: movl $42, [[DEST:.*]]
|
|
|
|
// CHECK: leaq [[DEST]], %rax
|
|
|
|
// CHECK-CLANG: movq %rax, -{{[0-9]+}}(%[[REG:[a-z]+]])
|
|
|
|
// CHECK: ret
|
|
|
|
int x = 42;
|
|
|
|
benchmark::DoNotOptimize(&x);
|
|
|
|
}
|
|
|
|
|
|
|
|
// CHECK-LABEL: test_pointer_const_lvalue:
|
|
|
|
extern "C" void test_pointer_const_lvalue() {
|
|
|
|
// CHECK: movl $42, [[DEST:.*]]
|
|
|
|
// CHECK: leaq [[DEST]], %rax
|
|
|
|
// CHECK-CLANG: movq %rax, -{{[0-9]+}}(%[[REG:[a-z]+]])
|
|
|
|
// CHECK: ret
|
|
|
|
int x = 42;
|
2021-11-10 16:22:31 +00:00
|
|
|
int *const xp = &x;
|
Add tests to verify assembler output -- Fix DoNotOptimize. (#530)
* Add tests to verify assembler output -- Fix DoNotOptimize.
For things like `DoNotOptimize`, `ClobberMemory`, and even `KeepRunning()`,
it is important exactly what assembly they generate. However, we currently
have no way to test this. Instead it must be manually validated every
time a change occurs -- including a change in compiler version.
This patch attempts to introduce a way to test the assembled output automatically.
It's mirrors how LLVM verifies compiler output, and it uses LLVM FileCheck to run
the tests in a similar way.
The tests function by generating the assembly for a test in CMake, and then
using FileCheck to verify the // CHECK lines in the source file are found
in the generated assembly.
Currently, the tests only run on 64-bit x86 systems under GCC and Clang,
and when FileCheck is found on the system.
Additionally, this patch tries to improve the code gen from DoNotOptimize.
This should probably be a separate change, but I needed something to test.
* Disable assembly tests on Bazel for now
* Link FIXME to github issue
* Fix Tests on OS X
* fix strip_asm.py to work on both Linux and OS X like targets
2018-03-23 22:10:47 +00:00
|
|
|
benchmark::DoNotOptimize(xp);
|
|
|
|
}
|
|
|
|
|
|
|
|
// CHECK-LABEL: test_pointer_lvalue:
|
|
|
|
extern "C" void test_pointer_lvalue() {
|
|
|
|
// CHECK: movl $42, [[DEST:.*]]
|
|
|
|
// CHECK: leaq [[DEST]], %rax
|
|
|
|
// CHECK-CLANG: movq %rax, -{{[0-9]+}}(%[[REG:[a-z+]+]])
|
|
|
|
// CHECK: ret
|
|
|
|
int x = 42;
|
|
|
|
int *xp = &x;
|
|
|
|
benchmark::DoNotOptimize(xp);
|
|
|
|
}
|