xref: /aosp_15_r20/art/tools/checker/README (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard WorkerChecker is a testing tool which compiles a given test file and compares the
2*795d594fSAndroid Build Coastguard Workerstate of the control-flow graph before and after each optimization pass
3*795d594fSAndroid Build Coastguard Workeragainst a set of statements specified alongside the tests.
4*795d594fSAndroid Build Coastguard Worker
5*795d594fSAndroid Build Coastguard WorkerTests are written in Java or Smali, turned into DEX and compiled with the
6*795d594fSAndroid Build Coastguard WorkerOptimizing compiler. "Check lines" are statements formatted as comments of the
7*795d594fSAndroid Build Coastguard Workersource file. They begin with prefix "/// CHECK" or "## CHECK", respectively,
8*795d594fSAndroid Build Coastguard Workerfollowed by a pattern that the engine attempts to match in the compiler output.
9*795d594fSAndroid Build Coastguard Worker
10*795d594fSAndroid Build Coastguard WorkerStatements are tested in groups which correspond to the individual compiler
11*795d594fSAndroid Build Coastguard Workerpasses. Each group of check lines therefore must start with a 'CHECK-START'
12*795d594fSAndroid Build Coastguard Workerheader which specifies the output group it should be tested against. The group
13*795d594fSAndroid Build Coastguard Workername must exactly match one of the groups recognized in the output (they can
14*795d594fSAndroid Build Coastguard Workerbe listed with the '--list-passes' command-line flag).
15*795d594fSAndroid Build Coastguard Worker
16*795d594fSAndroid Build Coastguard WorkerMatching of check lines is carried out in the order of appearance in the
17*795d594fSAndroid Build Coastguard Workersource file. There are five types of check lines. Branching instructions are
18*795d594fSAndroid Build Coastguard Workeralso supported and documented later in this file.
19*795d594fSAndroid Build Coastguard Worker - CHECK:      Must match an output line which appears in the output group
20*795d594fSAndroid Build Coastguard Worker               later than lines matched against any preceding checks. Output
21*795d594fSAndroid Build Coastguard Worker               lines must therefore match the check lines in the same order.
22*795d594fSAndroid Build Coastguard Worker               These are referred to as "in-order" checks in the code.
23*795d594fSAndroid Build Coastguard Worker - CHECK-DAG:  Must match an output line which appears in the output group
24*795d594fSAndroid Build Coastguard Worker               later than lines matched against any preceding in-order checks.
25*795d594fSAndroid Build Coastguard Worker               In other words, the order of output lines does not matter
26*795d594fSAndroid Build Coastguard Worker               between consecutive DAG checks.
27*795d594fSAndroid Build Coastguard Worker - CHECK-NOT:  Must not match any output line which appears in the output group
28*795d594fSAndroid Build Coastguard Worker               later than lines matched against any preceding checks and
29*795d594fSAndroid Build Coastguard Worker               earlier than lines matched against any subsequent checks.
30*795d594fSAndroid Build Coastguard Worker               Surrounding non-negative checks (or boundaries of the group)
31*795d594fSAndroid Build Coastguard Worker               therefore create a scope within which the statement is verified.
32*795d594fSAndroid Build Coastguard Worker - CHECK-NEXT: Must match the output line which comes right after the line which
33*795d594fSAndroid Build Coastguard Worker               matched the previous check. Can only be used after a CHECK or
34*795d594fSAndroid Build Coastguard Worker               another CHECK-NEXT.
35*795d594fSAndroid Build Coastguard Worker - CHECK-EVAL: Specifies a Python expression which must evaluate to 'True'.
36*795d594fSAndroid Build Coastguard Worker
37*795d594fSAndroid Build Coastguard WorkerCheck-line patterns are treated as plain text rather than regular expressions
38*795d594fSAndroid Build Coastguard Workerbut are whitespace agnostic.
39*795d594fSAndroid Build Coastguard Worker
40*795d594fSAndroid Build Coastguard WorkerActual regex patterns can be inserted enclosed in '{{' and '}}' brackets. If
41*795d594fSAndroid Build Coastguard Workercurly brackets need to be used inside the body of the regex, they need to be
42*795d594fSAndroid Build Coastguard Workerenclosed in round brackets. For example, the pattern '{{foo{2}}}' will parse
43*795d594fSAndroid Build Coastguard Workerthe invalid regex 'foo{2', but '{{(fo{2})}}' will match 'foo'.
44*795d594fSAndroid Build Coastguard Worker
45*795d594fSAndroid Build Coastguard WorkerRegex patterns can be named and referenced later. A new variable is defined
46*795d594fSAndroid Build Coastguard Workerwith '<<name:regex>>' and can be referenced with '<<name>>'. Variables are
47*795d594fSAndroid Build Coastguard Workeronly valid within the scope of the defining group. Within a group they cannot
48*795d594fSAndroid Build Coastguard Workerbe redefined or used undefined.
49*795d594fSAndroid Build Coastguard Worker
50*795d594fSAndroid Build Coastguard WorkerExample:
51*795d594fSAndroid Build Coastguard Worker  The following statements can be placed in a Java source file:
52*795d594fSAndroid Build Coastguard Worker
53*795d594fSAndroid Build Coastguard Worker  /// CHECK-START: int MyClass.MyMethod() constant_folding (after)
54*795d594fSAndroid Build Coastguard Worker  /// CHECK:         <<ID:i\d+>>  IntConstant {{11|22}}
55*795d594fSAndroid Build Coastguard Worker  /// CHECK:                      Return [<<ID>>]
56*795d594fSAndroid Build Coastguard Worker
57*795d594fSAndroid Build Coastguard Worker  The engine will attempt to match the check lines against the output of the
58*795d594fSAndroid Build Coastguard Worker  group named on the first line. Together they verify that the CFG after
59*795d594fSAndroid Build Coastguard Worker  constant folding returns an integer constant with value either 11 or 22.
60*795d594fSAndroid Build Coastguard Worker
61*795d594fSAndroid Build Coastguard Worker
62*795d594fSAndroid Build Coastguard WorkerOf the language constructs above, 'CHECK-EVAL' lines support only referencing of
63*795d594fSAndroid Build Coastguard Workervariables. Any other surrounding text will be passed to Python's `eval` as is.
64*795d594fSAndroid Build Coastguard Worker
65*795d594fSAndroid Build Coastguard WorkerExample:
66*795d594fSAndroid Build Coastguard Worker  /// CHECK-START: int MyClass.MyMethod() liveness (after)
67*795d594fSAndroid Build Coastguard Worker  /// CHECK:         InstructionA liveness:<<VarA:\d+>>
68*795d594fSAndroid Build Coastguard Worker  /// CHECK:         InstructionB liveness:<<VarB:\d+>>
69*795d594fSAndroid Build Coastguard Worker  /// CHECK-EVAL:    <<VarA>> != <<VarB>>
70*795d594fSAndroid Build Coastguard Worker
71*795d594fSAndroid Build Coastguard Worker
72*795d594fSAndroid Build Coastguard WorkerA group of check lines can be made architecture-specific by inserting '-<arch>'
73*795d594fSAndroid Build Coastguard Workerafter the 'CHECK-START' keyword. The previous example can be updated to run for
74*795d594fSAndroid Build Coastguard Workerarm64 only with:
75*795d594fSAndroid Build Coastguard Worker
76*795d594fSAndroid Build Coastguard WorkerExample:
77*795d594fSAndroid Build Coastguard Worker  /// CHECK-START-ARM64: int MyClass.MyMethod() constant_folding (after)
78*795d594fSAndroid Build Coastguard Worker  /// CHECK:         <<ID:i\d+>>  IntConstant {{11|22}}
79*795d594fSAndroid Build Coastguard Worker  /// CHECK:                      Return [<<ID>>]
80*795d594fSAndroid Build Coastguard Worker
81*795d594fSAndroid Build Coastguard WorkerFor convenience, several architectures can be specified as set after the
82*795d594fSAndroid Build Coastguard Worker'CHECK-START' keyword. Any listed architecture will match in that case,
83*795d594fSAndroid Build Coastguard Workerthereby avoiding to repeat the check lines if some, but not all architectures
84*795d594fSAndroid Build Coastguard Workermatch. An example line looks like:
85*795d594fSAndroid Build Coastguard Worker
86*795d594fSAndroid Build Coastguard Worker  /// CHECK-START-{X86_64,ARM,ARM64}: int MyClass.MyMethod() constant_folding (after)
87*795d594fSAndroid Build Coastguard Worker
88*795d594fSAndroid Build Coastguard Worker
89*795d594fSAndroid Build Coastguard WorkerBranching is possible thanks to the following statements:
90*795d594fSAndroid Build Coastguard Worker - CHECK-IF:
91*795d594fSAndroid Build Coastguard Worker - CHECK-ELIF:
92*795d594fSAndroid Build Coastguard Worker - CHECK-ELSE:
93*795d594fSAndroid Build Coastguard Worker - CHECK-FI:
94*795d594fSAndroid Build Coastguard Worker
95*795d594fSAndroid Build Coastguard WorkerCHECK-IF and CHECK-ELIF take a Python expression as input that will be evaluated by `eval`.
96*795d594fSAndroid Build Coastguard Worker
97*795d594fSAndroid Build Coastguard WorkerA possible use case of branching is to check whether the generated code exploits the instruction
98*795d594fSAndroid Build Coastguard Workerarchitecture features enabled at compile time. For that purpose, you can call the custom made
99*795d594fSAndroid Build Coastguard Workerfunction hasIsaFeature("feature_name").
100*795d594fSAndroid Build Coastguard Worker
101*795d594fSAndroid Build Coastguard WorkerExample:
102*795d594fSAndroid Build Coastguard Worker  /// CHECK-START-ARM64: int other.TestByte.testDotProdComplex(byte[], byte[]) disassembly (after)
103*795d594fSAndroid Build Coastguard Worker  /// CHECK:        VecDotProd
104*795d594fSAndroid Build Coastguard Worker  /// CHECK-IF:     hasIsaFeature("dotprod")
105*795d594fSAndroid Build Coastguard Worker  ///               CHECK:        sdot
106*795d594fSAndroid Build Coastguard Worker  /// CHECK-ELSE:
107*795d594fSAndroid Build Coastguard Worker  ///               CHECK-NOT:    sdot
108*795d594fSAndroid Build Coastguard Worker  /// CHECK-FI:
109*795d594fSAndroid Build Coastguard Worker
110*795d594fSAndroid Build Coastguard WorkerLike CHECK-EVAL, CHECK-IF and CHECK-ELIF support only referencing of variables, defining new
111*795d594fSAndroid Build Coastguard Workervariables as part of the statement input is not allowed. Any other surrounding text will be passed
112*795d594fSAndroid Build Coastguard Workerto Python's `eval` as is. CHECK-ELSE and CHECK-FI must not have any input.
113*795d594fSAndroid Build Coastguard Worker
114*795d594fSAndroid Build Coastguard WorkerExample:
115*795d594fSAndroid Build Coastguard Worker  /// CHECK-START: int MyClass.MyMethod() constant_folding (after)
116*795d594fSAndroid Build Coastguard Worker  /// CHECK:        {{i\d+}} IntConstant <<MyConst:(0|1|2)>>
117*795d594fSAndroid Build Coastguard Worker  /// CHECK-IF:     <<MyConst>> == 0
118*795d594fSAndroid Build Coastguard Worker  ///               CHECK-NEXT:            FooBar01
119*795d594fSAndroid Build Coastguard Worker  /// CHECK-ELIF:   <<MyConst>> == 1
120*795d594fSAndroid Build Coastguard Worker  ///               CHECK-NOT:             FooBar01
121*795d594fSAndroid Build Coastguard Worker  /// CHECK-FI:
122*795d594fSAndroid Build Coastguard Worker
123*795d594fSAndroid Build Coastguard WorkerBranch blocks can contain any statement, including CHECK-NEXT and CHECK-DAG.
124*795d594fSAndroid Build Coastguard WorkerNotice the CHECK-NEXT statement within the IF branch. When a CHECK-NEXT is encountered,
125*795d594fSAndroid Build Coastguard WorkerChecker expects that the previously executed statement was either a CHECK or a CHECK-NEXT.
126*795d594fSAndroid Build Coastguard WorkerThis condition is enforced at runtime, and an error is thrown if it's not respected.
127*795d594fSAndroid Build Coastguard Worker
128*795d594fSAndroid Build Coastguard WorkerStatements inside branches can define new variables. If a new variable gets defined inside a branch
129*795d594fSAndroid Build Coastguard Worker(of any depth, since nested branching is allowed), that variable will become global within the scope
130*795d594fSAndroid Build Coastguard Workerof the defining group. In other words, it will be valid everywhere after its definition within the
131*795d594fSAndroid Build Coastguard Workerblock defined by the CHECK-START statement. The absence of lexical scoping for Checker variables
132*795d594fSAndroid Build Coastguard Workerseems a bit inelegant at first, but is probably more practical.
133*795d594fSAndroid Build Coastguard Worker
134*795d594fSAndroid Build Coastguard WorkerExample:
135*795d594fSAndroid Build Coastguard Worker  /// CHECK-START: void MyClass.FooBar() liveness (after)
136*795d594fSAndroid Build Coastguard Worker  /// CHECK-IF:     os.environ.get('ART_READ_BARRIER_TYPE') != 'TABLELOOKUP'
137*795d594fSAndroid Build Coastguard Worker  ///               CHECK:                 <<MyID:i\d+>> IntConstant 3
138*795d594fSAndroid Build Coastguard Worker  /// CHECK-ELSE:
139*795d594fSAndroid Build Coastguard Worker  ///               CHECK:                 <<MyID:i\d+>> IntConstant 5
140*795d594fSAndroid Build Coastguard Worker  /// CHECK-FI:
141*795d594fSAndroid Build Coastguard Worker  /// CHECK-NEXT:   Return [<<MyID>>]
142*795d594fSAndroid Build Coastguard Worker
143*795d594fSAndroid Build Coastguard WorkerNotice that the variable MyID remained valid outside the branch where it was defined.
144*795d594fSAndroid Build Coastguard WorkerFurthermore, in this example, the definition of MyID depends on which branch gets selected at
145*795d594fSAndroid Build Coastguard Workerruntime. Attempting to re-define a variable or referencing an undefined variable is not allowed,
146*795d594fSAndroid Build Coastguard WorkerChecker will throw a runtime error.
147*795d594fSAndroid Build Coastguard WorkerThe example above also shows how we can use environment variables to perform custom checks.
148*795d594fSAndroid Build Coastguard Worker
149*795d594fSAndroid Build Coastguard WorkerIt is possible to combine IF, (multiple) ELIF and ELSE statements together. Nested branching is
150*795d594fSAndroid Build Coastguard Workeralso supported.
151