cb66c5d68e
bazel / bazel.ubuntu-latest (push) Failing after 1s
build-and-test-perfcounters / ubuntu-latest.Debug (push) Failing after 0s
build-and-test-perfcounters / ubuntu-latest.Release (push) Failing after 1s
doxygen / Build HTML documentation (push) Failing after 1s
python + Bazel pre-commit checks / pre-commit (push) Failing after 1s
sanitizer / tsan.Debug (push) Failing after 1s
sanitizer / ubsan.Debug (push) Failing after 0s
sanitizer / ubsan.RelWithDebInfo (push) Failing after 1s
build-and-test-min-cmake / ubuntu-latest.min-cmake (push) Failing after 1s
clang-format-lint / check-clang-format (push) Failing after 1s
sanitizer / asan.Debug (push) Failing after 1s
sanitizer / msan.RelWithDebInfo (push) Failing after 1s
clang-tidy / run-clang-tidy (push) Failing after 1s
sanitizer / msan.Debug (push) Failing after 1s
sanitizer / asan.RelWithDebInfo (push) Failing after 0s
sanitizer / tsan.RelWithDebInfo (push) Failing after 0s
test-bindings / Test Rust bindings on ubuntu-latest (push) Failing after 0s
test-bindings / Test Python 3.10 bindings on ubuntu-latest (push) Failing after 0s
test-bindings / Test Python 3.11 bindings on ubuntu-latest (push) Failing after 0s
test-bindings / Test Python 3.12 bindings on ubuntu-latest (push) Failing after 1s
test-bindings / Test Python 3.13 bindings on ubuntu-latest (push) Failing after 0s
build-and-test / macos-latest.Debug.shared.clang++ (push) Has been cancelled
build-and-test / ubuntu-22.04.Debug.shared.clang++ (push) Has been cancelled
build-and-test / ubuntu-24.04.Debug.shared.clang++ (push) Has been cancelled
build-and-test / ubuntu-24.04-arm.Debug.shared.clang++ (push) Has been cancelled
bazel / bazel.macos-latest (push) Has been cancelled
bazel / bazel.windows-latest (push) Has been cancelled
build-and-test-min-cmake / macos-latest.min-cmake (push) Has been cancelled
build-and-test / ubuntu-22.04.Debug.static.clang++ (push) Has been cancelled
build-and-test / macos-latest.Debug.shared.g++ (push) Has been cancelled
build-and-test / ubuntu-22.04.Debug.shared.g++ (push) Has been cancelled
build-and-test / ubuntu-24.04.Debug.shared.g++ (push) Has been cancelled
build-and-test / ubuntu-24.04-arm.Debug.shared.g++ (push) Has been cancelled
build-and-test / macos-latest.Debug.static.g++ (push) Has been cancelled
build-and-test / ubuntu-22.04.Debug.static.g++ (push) Has been cancelled
build-and-test / ubuntu-24.04.Debug.static.g++ (push) Has been cancelled
build-and-test / ubuntu-24.04-arm.Debug.static.g++ (push) Has been cancelled
build-and-test / macos-latest.Release.shared.clang++ (push) Has been cancelled
build-and-test / ubuntu-22.04.Release.shared.clang++ (push) Has been cancelled
build-and-test / ubuntu-24.04.Release.shared.clang++ (push) Has been cancelled
build-and-test / ubuntu-24.04-arm.Release.shared.clang++ (push) Has been cancelled
build-and-test / macos-latest.Release.static.clang++ (push) Has been cancelled
build-and-test / ubuntu-22.04.Release.static.clang++ (push) Has been cancelled
build-and-test / macos-latest.Debug.static.clang++ (push) Has been cancelled
build-and-test / ubuntu-24.04.Debug.static.clang++ (push) Has been cancelled
build-and-test / ubuntu-24.04-arm.Debug.static.clang++ (push) Has been cancelled
build-and-test / macos-latest.Release.static.g++ (push) Has been cancelled
build-and-test / ubuntu-22.04.Release.static.g++ (push) Has been cancelled
build-and-test / windows-2025.Debug.static.VS-18-2025 (push) Has been cancelled
build-and-test / windows-2022.Release.shared.VS-17-2022 (push) Has been cancelled
build-and-test / windows-2022.Release.static.VS-17-2022 (push) Has been cancelled
build-and-test / windows-2025.Release.shared.VS-18-2025 (push) Has been cancelled
build-and-test / windows-2025.Release.static.VS-18-2025 (push) Has been cancelled
build-and-test / windows-latest.Debug.shared.CLANG64 (push) Has been cancelled
build-and-test / windows-latest.Debug.shared.MINGW64 (push) Has been cancelled
build-and-test / windows-latest.Debug.shared.UCRT64 (push) Has been cancelled
build-and-test / windows-latest.Debug.static.CLANG64 (push) Has been cancelled
build-and-test / windows-latest.Debug.static.MINGW64 (push) Has been cancelled
build-and-test / windows-latest.Debug.static.UCRT64 (push) Has been cancelled
build-and-test / ubuntu-24.04.Release.static.clang++ (push) Has been cancelled
build-and-test / ubuntu-24.04-arm.Release.static.clang++ (push) Has been cancelled
build-and-test / macos-latest.Release.shared.g++ (push) Has been cancelled
build-and-test / ubuntu-22.04.Release.shared.g++ (push) Has been cancelled
build-and-test / ubuntu-24.04.Release.shared.g++ (push) Has been cancelled
build-and-test / ubuntu-24.04-arm.Release.shared.g++ (push) Has been cancelled
build-and-test / ubuntu-24.04.Release.static.g++ (push) Has been cancelled
build-and-test / ubuntu-24.04-arm.Release.static.g++ (push) Has been cancelled
build-and-test / windows-2022.Debug.shared.VS-17-2022 (push) Has been cancelled
build-and-test / windows-2022.Debug.static.VS-17-2022 (push) Has been cancelled
build-and-test / windows-2025.Debug.shared.VS-18-2025 (push) Has been cancelled
build-and-test / windows-latest.Release.static.MINGW64 (push) Has been cancelled
build-and-test / windows-latest.Release.static.UCRT64 (push) Has been cancelled
test-bindings / Test Python 3.10 bindings on macos-latest (push) Has been cancelled
test-bindings / Test Python 3.11 bindings on macos-latest (push) Has been cancelled
test-bindings / Test Python 3.12 bindings on macos-latest (push) Has been cancelled
test-bindings / Test Python 3.13 bindings on macos-latest (push) Has been cancelled
build-and-test / windows-latest.Release.shared.CLANG64 (push) Has been cancelled
build-and-test / windows-latest.Release.shared.MINGW64 (push) Has been cancelled
build-and-test / windows-latest.Release.shared.UCRT64 (push) Has been cancelled
build-and-test / windows-latest.Release.static.CLANG64 (push) Has been cancelled
test-bindings / Test Python 3.12 bindings on windows-latest (push) Has been cancelled
test-bindings / Test Python 3.13 bindings on windows-latest (push) Has been cancelled
test-bindings / Test Python 3.10 bindings on windows-latest (push) Has been cancelled
test-bindings / Test Python 3.11 bindings on windows-latest (push) Has been cancelled
test-bindings / Test Rust bindings on macos-latest (push) Has been cancelled
test-bindings / Test Rust bindings on windows-latest (push) Has been cancelled
150 lines
5.2 KiB
Markdown
150 lines
5.2 KiB
Markdown
# Assembly Tests
|
|
|
|
The Benchmark library provides a number of functions whose primary
|
|
purpose in to affect assembly generation, including `DoNotOptimize`
|
|
and `ClobberMemory`. In addition there are other functions,
|
|
such as `KeepRunning`, for which generating good assembly is paramount.
|
|
|
|
For these functions it's important to have tests that verify the
|
|
correctness and quality of the implementation. This requires testing
|
|
the code generated by the compiler.
|
|
|
|
This document describes how the Benchmark library tests compiler output,
|
|
as well as how to properly write new tests.
|
|
|
|
|
|
## Anatomy of a Test
|
|
|
|
Writing a test has two steps:
|
|
|
|
* Write the code you want to generate assembly for.
|
|
* Add `// CHECK` lines to match against the verified assembly.
|
|
|
|
Example:
|
|
```c++
|
|
|
|
// CHECK-LABEL: test_add:
|
|
extern "C" int test_add() {
|
|
extern int ExternInt;
|
|
return ExternInt + 1;
|
|
|
|
// CHECK: movl ExternInt(%rip), %eax
|
|
// CHECK: addl %eax
|
|
// CHECK: ret
|
|
}
|
|
|
|
```
|
|
|
|
#### LLVM Filecheck
|
|
|
|
[LLVM's Filecheck](https://llvm.org/docs/CommandGuide/FileCheck.html)
|
|
is used to test the generated assembly against the `// CHECK` lines
|
|
specified in the tests source file. Please see the documentation
|
|
linked above for information on how to write `CHECK` directives.
|
|
|
|
#### Tips and Tricks:
|
|
|
|
* Tests should match the minimal amount of output required to establish
|
|
correctness. `CHECK` directives don't have to match on the exact next line
|
|
after the previous match, so tests should omit checks for unimportant
|
|
bits of assembly. ([`CHECK-NEXT`](https://llvm.org/docs/CommandGuide/FileCheck.html#the-check-next-directive)
|
|
can be used to ensure a match occurs exactly after the previous match).
|
|
|
|
* The tests are compiled with `-O3 -g0`. So we're only testing the
|
|
optimized output.
|
|
|
|
* The assembly output is further cleaned up using `tools/strip_asm.py`.
|
|
This removes comments, assembler directives, and unused labels before
|
|
the test is run.
|
|
|
|
* The generated and stripped assembly file for a test is output under
|
|
`<build-directory>/test/<test-name>.s`
|
|
|
|
* Filecheck supports using [`CHECK` prefixes](https://llvm.org/docs/CommandGuide/FileCheck.html#cmdoption-check-prefixes)
|
|
to specify lines that should only match in certain situations.
|
|
The Benchmark tests use `CHECK-CLANG` and `CHECK-GNU` for lines that
|
|
are only expected to match Clang or GCC's output respectively. Normal
|
|
`CHECK` lines match against all compilers. (Note: `CHECK-NOT` and
|
|
`CHECK-LABEL` are NOT prefixes. They are versions of non-prefixed
|
|
`CHECK` lines)
|
|
|
|
* Use `extern "C"` to disable name mangling for specific functions. This
|
|
makes them easier to name in the `CHECK` lines.
|
|
|
|
|
|
## Problems Writing Portable Tests
|
|
|
|
Writing tests which check the code generated by a compiler are
|
|
inherently non-portable. Different compilers and even different compiler
|
|
versions may generate entirely different code. The Benchmark tests
|
|
must tolerate this.
|
|
|
|
LLVM Filecheck provides a number of mechanisms to help write
|
|
"more portable" tests; including [matching using regular expressions](https://llvm.org/docs/CommandGuide/FileCheck.html#filecheck-pattern-matching-syntax),
|
|
allowing the creation of [named variables](https://llvm.org/docs/CommandGuide/FileCheck.html#filecheck-variables)
|
|
for later matching, and [checking non-sequential matches](https://llvm.org/docs/CommandGuide/FileCheck.html#the-check-dag-directive).
|
|
|
|
#### Capturing Variables
|
|
|
|
For example, say GCC stores a variable in a register but Clang stores
|
|
it in memory. To write a test that tolerates both cases we "capture"
|
|
the destination of the store, and then use the captured expression
|
|
to write the remainder of the test.
|
|
|
|
```c++
|
|
// CHECK-LABEL: test_div_no_op_into_shr:
|
|
extern "C" void test_div_no_op_into_shr(int value) {
|
|
int divisor = 2;
|
|
benchmark::DoNotOptimize(divisor); // hide the value from the optimizer
|
|
return value / divisor;
|
|
|
|
// CHECK: movl $2, [[DEST:.*]]
|
|
// CHECK: idivl [[DEST]]
|
|
// CHECK: ret
|
|
}
|
|
```
|
|
|
|
#### Using Regular Expressions to Match Differing Output
|
|
|
|
Often tests require testing assembly lines which may subtly differ
|
|
between compilers or compiler versions. A common example of this
|
|
is matching stack frame addresses. In this case regular expressions
|
|
can be used to match the differing bits of output. For example:
|
|
|
|
<!-- {% raw %} -->
|
|
```c++
|
|
int ExternInt;
|
|
struct Point { int x, y, z; };
|
|
|
|
// CHECK-LABEL: test_store_point:
|
|
extern "C" void test_store_point() {
|
|
Point p{ExternInt, ExternInt, ExternInt};
|
|
benchmark::DoNotOptimize(p);
|
|
|
|
// CHECK: movl ExternInt(%rip), %eax
|
|
// CHECK: movl %eax, -{{[0-9]+}}(%rsp)
|
|
// CHECK: movl %eax, -{{[0-9]+}}(%rsp)
|
|
// CHECK: movl %eax, -{{[0-9]+}}(%rsp)
|
|
// CHECK: ret
|
|
}
|
|
```
|
|
<!-- {% endraw %} -->
|
|
|
|
## Current Requirements and Limitations
|
|
|
|
The tests require Filecheck to be installed along the `PATH` of the
|
|
build machine. Otherwise the tests will be disabled.
|
|
|
|
Additionally, as mentioned in the previous section, codegen tests are
|
|
inherently non-portable. Currently the tests are limited to:
|
|
|
|
* x86_64 targets.
|
|
* Compiled with GCC or Clang
|
|
|
|
Further work could be done, at least on a limited basis, to extend the
|
|
tests to other architectures and compilers (using `CHECK` prefixes).
|
|
|
|
Furthermore, the tests fail for builds which specify additional flags
|
|
that modify code generation, including `--coverage` or `-fsanitize=`.
|
|
|