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