blob: 70aa32130b832e59613dc00252160e1eb4be3545 [file] [log] [blame] [view]
# Writing IL tests for AOT compiler
Usually optimized IL strongly depends on TFA results and which makes it
difficult to test certain AOT optimizations through `run_vm_tests`.
In such cases you can attempt to write an IL test instead. In these tests
test runner will run full AOT pipeline (TFA + `gen_snapshot`), will instruct
`gen_snapshot` to dump flow graphs of specific methods and then run
`pkg/vm/tool/compare_il` helper script to compare expectations. Here is how you
create an IL test.
IL tests are placed in files ending with `_il_test.dart`.
To run an IL test you need to use `tools/test.py` runner with AOT configuration:
```
# Run against ReleaseX64 AOT compiler
$ tools/test.py -n dartkp-linux-release-x64 $path_to_an_il_test
$ tools/test.py -c dartkp -m release $path_to_an_il_test
```
Tests require `gen_snapshot`, `dartaotruntime` and
`vm_platform_strong.dill` to be built for the target configuration.
Each IL test should contain one or more of the functions marked with a
`@pragma('vm:testing:print-flow-graph'[, 'phases filter'])`.
These functions will have their IL dumped at points specified by the
_phases filter_ (if present, `]AllocateRegisters` by default), which follows
the same syntax as `--compiler-passes=` flag and dumped IL will be compared
against the expectations, which are specified programmatically using
`package:vm/testing/il_matchers.dart` helpers. A function named `foo` has
its IL expectations in the function called `matchIL$foo` in the same file.
```dart
import 'package:vm/testing/il_matchers.dart';
@pragma('vm:testing:print-flow-graph')
void foo() {
}
/// Expectations for [foo].
void matchIL$foo(FlowGraph graph) {
graph.match([/* expectations */]);
}
```
Actual matching is done by the `pkg/vm/tool/compare_il` script.
In order to test IL of the inner (local) function, use
`@pragma('vm:testing:match-inner-flow-graph', 'inner name')`.
Specifying a particular phase is not supported for inner closures.
## Example
```dart
@pragma('vm:never-inline')
@pragma('vm:testing:print-flow-graph')
int factorial(int value) => value == 1 ? value : value * factorial(value - 1);
void matchIL$factorial(FlowGraph graph) {
// Expected a graph which starts with GraphEntry block followed by a
// FunctionEntry block. FunctionEntry block should contain a Branch()
// instruction, with EqualityCompare as a comparison.
graph.match([
match.block('Graph'),
match.block('Function', [
match.Branch(match.EqualityCompare(match.any, match.any, kind: '==')),
]),
]);
}
@pragma('vm:testing:match-inner-flow-graph', 'bar')
void foo() {
@pragma('vm:testing:print-flow-graph')
bar() {
}
}
void matchIL$foo_bar(FlowGraph graph) {
// Test IL of local bar() in foo().
}
```