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