xref: /netbsd-src/external/apache2/llvm/dist/libcxx/utils/google-benchmark/docs/AssemblyTests.md (revision 4d6fc14bc9b0c5bf3e30be318c143ee82cadd108)
1*4d6fc14bSjoerg# Assembly Tests
2*4d6fc14bSjoerg
3*4d6fc14bSjoergThe Benchmark library provides a number of functions whose primary
4*4d6fc14bSjoergpurpose in to affect assembly generation, including `DoNotOptimize`
5*4d6fc14bSjoergand `ClobberMemory`. In addition there are other functions,
6*4d6fc14bSjoergsuch as `KeepRunning`, for which generating good assembly is paramount.
7*4d6fc14bSjoerg
8*4d6fc14bSjoergFor these functions it's important to have tests that verify the
9*4d6fc14bSjoergcorrectness and quality of the implementation. This requires testing
10*4d6fc14bSjoergthe code generated by the compiler.
11*4d6fc14bSjoerg
12*4d6fc14bSjoergThis document describes how the Benchmark library tests compiler output,
13*4d6fc14bSjoergas well as how to properly write new tests.
14*4d6fc14bSjoerg
15*4d6fc14bSjoerg
16*4d6fc14bSjoerg## Anatomy of a Test
17*4d6fc14bSjoerg
18*4d6fc14bSjoergWriting a test has two steps:
19*4d6fc14bSjoerg
20*4d6fc14bSjoerg* Write the code you want to generate assembly for.
21*4d6fc14bSjoerg* Add `// CHECK` lines to match against the verified assembly.
22*4d6fc14bSjoerg
23*4d6fc14bSjoergExample:
24*4d6fc14bSjoerg```c++
25*4d6fc14bSjoerg
26*4d6fc14bSjoerg// CHECK-LABEL: test_add:
27*4d6fc14bSjoergextern "C" int test_add() {
28*4d6fc14bSjoerg    extern int ExternInt;
29*4d6fc14bSjoerg    return ExternInt + 1;
30*4d6fc14bSjoerg
31*4d6fc14bSjoerg    // CHECK: movl ExternInt(%rip), %eax
32*4d6fc14bSjoerg    // CHECK: addl %eax
33*4d6fc14bSjoerg    // CHECK: ret
34*4d6fc14bSjoerg}
35*4d6fc14bSjoerg
36*4d6fc14bSjoerg```
37*4d6fc14bSjoerg
38*4d6fc14bSjoerg#### LLVM Filecheck
39*4d6fc14bSjoerg
40*4d6fc14bSjoerg[LLVM's Filecheck](https://llvm.org/docs/CommandGuide/FileCheck.html)
41*4d6fc14bSjoergis used to test the generated assembly against the `// CHECK` lines
42*4d6fc14bSjoergspecified in the tests source file. Please see the documentation
43*4d6fc14bSjoerglinked above for information on how to write `CHECK` directives.
44*4d6fc14bSjoerg
45*4d6fc14bSjoerg#### Tips and Tricks:
46*4d6fc14bSjoerg
47*4d6fc14bSjoerg* Tests should match the minimal amount of output required to establish
48*4d6fc14bSjoergcorrectness. `CHECK` directives don't have to match on the exact next line
49*4d6fc14bSjoergafter the previous match, so tests should omit checks for unimportant
50*4d6fc14bSjoergbits of assembly. ([`CHECK-NEXT`](https://llvm.org/docs/CommandGuide/FileCheck.html#the-check-next-directive)
51*4d6fc14bSjoergcan be used to ensure a match occurs exactly after the previous match).
52*4d6fc14bSjoerg
53*4d6fc14bSjoerg* The tests are compiled with `-O3 -g0`. So we're only testing the
54*4d6fc14bSjoergoptimized output.
55*4d6fc14bSjoerg
56*4d6fc14bSjoerg* The assembly output is further cleaned up using `tools/strip_asm.py`.
57*4d6fc14bSjoergThis removes comments, assembler directives, and unused labels before
58*4d6fc14bSjoergthe test is run.
59*4d6fc14bSjoerg
60*4d6fc14bSjoerg* The generated and stripped assembly file for a test is output under
61*4d6fc14bSjoerg`<build-directory>/test/<test-name>.s`
62*4d6fc14bSjoerg
63*4d6fc14bSjoerg* Filecheck supports using [`CHECK` prefixes](https://llvm.org/docs/CommandGuide/FileCheck.html#cmdoption-check-prefixes)
64*4d6fc14bSjoergto specify lines that should only match in certain situations.
65*4d6fc14bSjoergThe Benchmark tests use `CHECK-CLANG` and `CHECK-GNU` for lines that
66*4d6fc14bSjoergare only expected to match Clang or GCC's output respectively. Normal
67*4d6fc14bSjoerg`CHECK` lines match against all compilers. (Note: `CHECK-NOT` and
68*4d6fc14bSjoerg`CHECK-LABEL` are NOT prefixes. They are versions of non-prefixed
69*4d6fc14bSjoerg`CHECK` lines)
70*4d6fc14bSjoerg
71*4d6fc14bSjoerg* Use `extern "C"` to disable name mangling for specific functions. This
72*4d6fc14bSjoergmakes them easier to name in the `CHECK` lines.
73*4d6fc14bSjoerg
74*4d6fc14bSjoerg
75*4d6fc14bSjoerg## Problems Writing Portable Tests
76*4d6fc14bSjoerg
77*4d6fc14bSjoergWriting tests which check the code generated by a compiler are
78*4d6fc14bSjoerginherently non-portable. Different compilers and even different compiler
79*4d6fc14bSjoergversions may generate entirely different code. The Benchmark tests
80*4d6fc14bSjoergmust tolerate this.
81*4d6fc14bSjoerg
82*4d6fc14bSjoergLLVM Filecheck provides a number of mechanisms to help write
83*4d6fc14bSjoerg"more portable" tests; including [matching using regular expressions](https://llvm.org/docs/CommandGuide/FileCheck.html#filecheck-pattern-matching-syntax),
84*4d6fc14bSjoergallowing the creation of [named variables](https://llvm.org/docs/CommandGuide/FileCheck.html#filecheck-variables)
85*4d6fc14bSjoergfor later matching, and [checking non-sequential matches](https://llvm.org/docs/CommandGuide/FileCheck.html#the-check-dag-directive).
86*4d6fc14bSjoerg
87*4d6fc14bSjoerg#### Capturing Variables
88*4d6fc14bSjoerg
89*4d6fc14bSjoergFor example, say GCC stores a variable in a register but Clang stores
90*4d6fc14bSjoergit in memory. To write a test that tolerates both cases we "capture"
91*4d6fc14bSjoergthe destination of the store, and then use the captured expression
92*4d6fc14bSjoergto write the remainder of the test.
93*4d6fc14bSjoerg
94*4d6fc14bSjoerg```c++
95*4d6fc14bSjoerg// CHECK-LABEL: test_div_no_op_into_shr:
96*4d6fc14bSjoergextern "C" void test_div_no_op_into_shr(int value) {
97*4d6fc14bSjoerg    int divisor = 2;
98*4d6fc14bSjoerg    benchmark::DoNotOptimize(divisor); // hide the value from the optimizer
99*4d6fc14bSjoerg    return value / divisor;
100*4d6fc14bSjoerg
101*4d6fc14bSjoerg    // CHECK: movl $2, [[DEST:.*]]
102*4d6fc14bSjoerg    // CHECK: idivl [[DEST]]
103*4d6fc14bSjoerg    // CHECK: ret
104*4d6fc14bSjoerg}
105*4d6fc14bSjoerg```
106*4d6fc14bSjoerg
107*4d6fc14bSjoerg#### Using Regular Expressions to Match Differing Output
108*4d6fc14bSjoerg
109*4d6fc14bSjoergOften tests require testing assembly lines which may subtly differ
110*4d6fc14bSjoergbetween compilers or compiler versions. A common example of this
111*4d6fc14bSjoergis matching stack frame addresses. In this case regular expressions
112*4d6fc14bSjoergcan be used to match the differing bits of output. For example:
113*4d6fc14bSjoerg
114*4d6fc14bSjoerg```c++
115*4d6fc14bSjoergint ExternInt;
116*4d6fc14bSjoergstruct Point { int x, y, z; };
117*4d6fc14bSjoerg
118*4d6fc14bSjoerg// CHECK-LABEL: test_store_point:
119*4d6fc14bSjoergextern "C" void test_store_point() {
120*4d6fc14bSjoerg    Point p{ExternInt, ExternInt, ExternInt};
121*4d6fc14bSjoerg    benchmark::DoNotOptimize(p);
122*4d6fc14bSjoerg
123*4d6fc14bSjoerg    // CHECK: movl ExternInt(%rip), %eax
124*4d6fc14bSjoerg    // CHECK: movl %eax, -{{[0-9]+}}(%rsp)
125*4d6fc14bSjoerg    // CHECK: movl %eax, -{{[0-9]+}}(%rsp)
126*4d6fc14bSjoerg    // CHECK: movl %eax, -{{[0-9]+}}(%rsp)
127*4d6fc14bSjoerg    // CHECK: ret
128*4d6fc14bSjoerg}
129*4d6fc14bSjoerg```
130*4d6fc14bSjoerg
131*4d6fc14bSjoerg## Current Requirements and Limitations
132*4d6fc14bSjoerg
133*4d6fc14bSjoergThe tests require Filecheck to be installed along the `PATH` of the
134*4d6fc14bSjoergbuild machine. Otherwise the tests will be disabled.
135*4d6fc14bSjoerg
136*4d6fc14bSjoergAdditionally, as mentioned in the previous section, codegen tests are
137*4d6fc14bSjoerginherently non-portable. Currently the tests are limited to:
138*4d6fc14bSjoerg
139*4d6fc14bSjoerg* x86_64 targets.
140*4d6fc14bSjoerg* Compiled with GCC or Clang
141*4d6fc14bSjoerg
142*4d6fc14bSjoergFurther work could be done, at least on a limited basis, to extend the
143*4d6fc14bSjoergtests to other architectures and compilers (using `CHECK` prefixes).
144*4d6fc14bSjoerg
145*4d6fc14bSjoergFurthermore, the tests fail for builds which specify additional flags
146*4d6fc14bSjoergthat modify code generation, including `--coverage` or `-fsanitize=`.
147