David Brazdil | 2c27f2c | 2015-05-12 18:06:38 +0100 | [diff] [blame] | 1 | Checker is a testing tool which compiles a given test file and compares the |
| 2 | state of the control-flow graph before and after each optimization pass |
| 3 | against a set of assertions specified alongside the tests. |
| 4 | |
David Brazdil | b34c35e | 2015-08-20 11:46:04 +0100 | [diff] [blame] | 5 | Tests are written in Java or Smali, turned into DEX and compiled with the |
| 6 | Optimizing compiler. "Check lines" are assertions formatted as comments of the |
| 7 | source file. They begin with prefix "/// CHECK" or "## CHECK", respectively, |
| 8 | followed by a pattern that the engine attempts to match in the compiler output. |
David Brazdil | 2c27f2c | 2015-05-12 18:06:38 +0100 | [diff] [blame] | 9 | |
| 10 | Assertions are tested in groups which correspond to the individual compiler |
| 11 | passes. Each group of check lines therefore must start with a 'CHECK-START' |
| 12 | header which specifies the output group it should be tested against. The group |
| 13 | name must exactly match one of the groups recognized in the output (they can |
David Brazdil | c2c48ff | 2015-05-15 14:24:31 +0100 | [diff] [blame] | 14 | be listed with the '--list-passes' command-line flag). |
David Brazdil | 2c27f2c | 2015-05-12 18:06:38 +0100 | [diff] [blame] | 15 | |
| 16 | Matching of check lines is carried out in the order of appearance in the |
| 17 | source file. There are three types of check lines: |
David Brazdil | b34c35e | 2015-08-20 11:46:04 +0100 | [diff] [blame] | 18 | - CHECK: Must match an output line which appears in the output group |
| 19 | later than lines matched against any preceeding checks. Output |
| 20 | lines must therefore match the check lines in the same order. |
| 21 | These are referred to as "in-order" checks in the code. |
| 22 | - CHECK-DAG: Must match an output line which appears in the output group |
| 23 | later than lines matched against any preceeding in-order checks. |
| 24 | In other words, the order of output lines does not matter |
| 25 | between consecutive DAG checks. |
| 26 | - CHECK-NOT: Must not match any output line which appears in the output group |
| 27 | later than lines matched against any preceeding checks and |
| 28 | earlier than lines matched against any subsequent checks. |
| 29 | Surrounding non-negative checks (or boundaries of the group) |
| 30 | therefore create a scope within which the assertion is verified. |
| 31 | - CHECK-NEXT: Must match the output line which comes right after the line which |
| 32 | matched the previous check. Cannot be used after any but the |
| 33 | in-order CHECK. |
| 34 | - CHECK-EVAL: Specifies a Python expression which must evaluate to 'True'. |
David Brazdil | 2c27f2c | 2015-05-12 18:06:38 +0100 | [diff] [blame] | 35 | |
| 36 | Check-line patterns are treated as plain text rather than regular expressions |
| 37 | but are whitespace agnostic. |
| 38 | |
| 39 | Actual regex patterns can be inserted enclosed in '{{' and '}}' brackets. If |
| 40 | curly brackets need to be used inside the body of the regex, they need to be |
| 41 | enclosed in round brackets. For example, the pattern '{{foo{2}}}' will parse |
| 42 | the invalid regex 'foo{2', but '{{(fo{2})}}' will match 'foo'. |
| 43 | |
| 44 | Regex patterns can be named and referenced later. A new variable is defined |
David Brazdil | c2c48ff | 2015-05-15 14:24:31 +0100 | [diff] [blame] | 45 | with '<<name:regex>>' and can be referenced with '<<name>>'. Variables are |
David Brazdil | 2c27f2c | 2015-05-12 18:06:38 +0100 | [diff] [blame] | 46 | only valid within the scope of the defining group. Within a group they cannot |
| 47 | be redefined or used undefined. |
| 48 | |
| 49 | Example: |
| 50 | The following assertions can be placed in a Java source file: |
| 51 | |
David Brazdil | b34c35e | 2015-08-20 11:46:04 +0100 | [diff] [blame] | 52 | /// CHECK-START: int MyClass.MyMethod() constant_folding (after) |
| 53 | /// CHECK: <<ID:i\d+>> IntConstant {{11|22}} |
| 54 | /// CHECK: Return [<<ID>>] |
David Brazdil | 2c27f2c | 2015-05-12 18:06:38 +0100 | [diff] [blame] | 55 | |
| 56 | The engine will attempt to match the check lines against the output of the |
| 57 | group named on the first line. Together they verify that the CFG after |
| 58 | constant folding returns an integer constant with value either 11 or 22. |
Alexandre Rames | 5e2c8d3 | 2015-08-06 14:49:28 +0100 | [diff] [blame] | 59 | |
David Brazdil | b34c35e | 2015-08-20 11:46:04 +0100 | [diff] [blame] | 60 | |
| 61 | Of the language constructs above, 'CHECK-EVAL' lines support only referencing of |
| 62 | variables. Any other surrounding text will be passed to Python's `eval` as is. |
| 63 | |
| 64 | Example: |
| 65 | /// CHECK-START: int MyClass.MyMethod() liveness (after) |
| 66 | /// CHECK: InstructionA liveness:<<VarA:\d+>> |
| 67 | /// CHECK: InstructionB liveness:<<VarB:\d+>> |
| 68 | /// CHECK-EVAL: <<VarA>> != <<VarB>> |
| 69 | |
| 70 | |
Alexandre Rames | 5e2c8d3 | 2015-08-06 14:49:28 +0100 | [diff] [blame] | 71 | A group of check lines can be made architecture-specific by inserting '-<arch>' |
| 72 | after the 'CHECK-START' keyword. The previous example can be updated to run for |
| 73 | arm64 only with: |
| 74 | |
David Brazdil | b34c35e | 2015-08-20 11:46:04 +0100 | [diff] [blame] | 75 | Example: |
| 76 | /// CHECK-START-ARM64: int MyClass.MyMethod() constant_folding (after) |
| 77 | /// CHECK: <<ID:i\d+>> IntConstant {{11|22}} |
| 78 | /// CHECK: Return [<<ID>>] |