Files
sdk/runtime/docs/infra/il_tests.md
T
Vyacheslav Egorov c97736d594 [vm/compiler] Fix DelayAllocations pass
When looking at a phi use of an allocation, we must consider *all*
inputs that refer to this allocation and not just the first one.

Otherwise, we might end up sinking allocation down to a use that does
not dominate all uses of the allocation.

Fixes https://github.com/flutter/flutter/issues/98466

TEST=runtime/tests/vm/dart{,_2}/flutter_regress_98466_il_test.dart

Cq-Include-Trybots: luci.dart.try:vm-kernel-precomp-linux-debug-x64-try,vm-kernel-precomp-linux-release-x64-try
Change-Id: Iab87b4c225a29a4967eefad56a7e425629ea4b70
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/234361
Reviewed-by: Daco Harkes <dacoharkes@google.com>
Commit-Queue: Slava Egorov <vegorov@google.com>
2022-03-04 10:00:41 +00:00

2.7 KiB

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, dart_precompiled_runtime 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.

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

@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().
}