FILECHECK(1)
๐ FILECHECK(1) ๐
okay bestie, this is the LLVM manual page for FILECHECK(1) ๐ it's all about the FileCheck tool, so let's get into it โจ
โจ NAME โจ
FileCheck โ a flexible pattern-matching file verifier ๐ฆ
๐ SYNOPSIS ๐
FileCheck match-filename [โcheck-prefix=XXX] [โstrict-whitespace]
๐ DESCRIPTION ๐
okay so FileCheck reads two files, one from standard input and one you pass on the command line, and it uses one of them to verify the other ๐ฅ this is literally the move for the testsuite, which needs to confirm that the output of some tool (e.g. llc) has the info it's supposed to, like a movsd from esp or whatever is giving main character energy ๐
it's kinda like grep, but it's built for matching a bunch of different inputs inside one file, in a specific order ๐ธ
The match-filename file is the one with the patterns to match ๐ the file to verify gets read from standard input unless you use the --input-file option ๐ซถ
๐ OPTIONS ๐
Options get parsed from the environment variable FILECHECK_OPTS and from the command line too ๐
-helpโ prints a summary of all the command line options โจ--check-prefix prefixโ FileCheck goes digging through match-filename for patterns to match ๐ by default those patterns are prefixed withCHECK:๐ if you want a different prefix (maybe the same input file is checking multiple tools or options),--check-prefixlets you pick one or more prefixes, written without the trailing:๐ฆ multiple prefixes are great for tests that change between run options but mostly stay the same ๐ FileCheck doesn't allow duplicate prefixes, even if one is a check prefix and one is a comment prefix (see--comment-prefixesbelow) ๐--check-prefixes prefix1,prefix2,...โ an alias of--check-prefixthat lets you list several prefixes separated by commas ๐ง--comment-prefixes prefix1,prefix2,...โ by default, FileCheck ignores any check prefix in match-filename if it's preceded on the same line byCOM:orRUN:๐ check out the section The โCOM:โ directive for the deets ๐ you can override those default comment prefixes with--comment-prefixesif they don't fit your testing setup ๐ธ tbh, doing that is not recommended in LLVM's LIT-based test suites ๐ those should be way easier to maintain when everyone follows one comment style ๐ if the defaults feel wrong, the better move is proposing a change to the default comment prefixes instead โจ--allow-unused-prefixesโ this one controls what happens when you use more than one prefix (via--check-prefixor--check-prefixes) and some of those prefixes are missing from the test file ๐ฅบ if it's true, that's allowed ๐ if it's false, FileCheck throws an error and lists the missing prefixes ๐ the default is false ๐ซถ--input-file filenameโ the file to check ๐ฅ defaults to stdin--match-full-linesโ by default FileCheck is chill and lets matches happen anywhere on a line ๐ฆ this option makes every positive match cover an entire line ๐ฅ leading and trailing whitespace gets ignored, unless--strict-whitespaceis also specified โจ (heads up: negative matches fromCHECK-NOTare not affected by this option! ๐จ) passing this option is the same as sticking{{^ *}}or{{^}}before, and{{ *$}}or{{$}}after, every positive check pattern ๐ง--strict-whitespaceโ by default FileCheck canonicalizes horizontal whitespace (spaces and tabs), so it ignores those differences, meaning a space will match a tab ๐ซ this flag turns that behaviour off ๐ซ end-of-line sequences get canonicalized to UNIX-style\nin all modes ๐ง--ignore-caseโ the default is case-sensitive matching ๐ this makes FileCheck do case-insensitive matching instead ๐--implicit-check-not check-patternโ adds implicit negative checks for the patterns you give, sitting between your positive checks ๐ต๏ธ you can write stricter tests this way without stuffing them full ofCHECK-NOTs ๐ for example,--implicit-check-not warning:is super useful for testing diagnostic messages from tools that don't have an option likeclang -verify๐จ with this option, FileCheck verifies that the input doesn't contain any warnings that aren't covered by aCHECK:pattern ๐--dump-input <value>โ dumps the input to stderr, with annotations for whatever diagnostics are currently enabled ๐งพ if you use this option more than once, the<value>that shows up earliest in the list below wins ๐ the default isfail๐helpโ explains the input dump and quits ๐alwaysโ always dumps the input ๐ฃfailโ dumps the input on failure โneverโ never dumps the input ๐
--dump-input-context <N>โ in the dump that--dump-inputasks for, prints<N>input lines before and<N>input lines after any lines picked by--dump-input-filter๐ with multiple occurrences, the largest<N>wins ๐ช the default is5๐๏ธ--dump-input-filter <value>โ in the--dump-inputdump, prints only input lines of kind<value>, plus whatever context--dump-input-contextasks for ๐ฏ with multiple occurrences, the<value>that appears earliest in the list below wins ๐ the default iserrorwhen--dump-input=fail, andallwhen--dump-input=always๐allโ all input lines ๐annotation-fullโ input lines with annotations ๐ท๏ธannotationโ input lines with starting points of annotations ๐errorโ input lines with starting points of error annotations ๐จ
--enable-var-scopeโ turns on scope for regex variables ๐ธ variables with names that start with$are considered global and stay set throughout the file ๐ all other variables get undefined after eachCHECK-LABELthey run into ๐งน-D<VAR=VALUE>โ sets a FileCheck pattern variableVARto the valueVALUE, which you can then use inCHECK:lines โจ-D#<FMT>,<NUMVAR>=<NUMERIC EXPRESSION>โ sets a FileCheck numeric variableNUMVARof matching formatFMTto the result of evaluating<NUMERIC EXPRESSION>, which you can use inCHECK:lines ๐ข check out the section FileCheck Numeric Variables and Expressions for the details on supported numeric expressions ๐-versionโ shows the version number of this program ๐ท๏ธ-vโ prints good directive pattern matches ๐ฅฐ but if-dump-input=failor-dump-input=alwaysis set, those matches get added as input annotations instead ๐ฆ-vvโ prints info that helps diagnose internal FileCheck issues ๐ง like discarded overlappingCHECK-DAG:matches, implicit EOF pattern matches, andCHECK-NOT:patterns that don't have matches ๐ต๏ธ it implies-vโจ but if-dump-input=failor-dump-input=alwaysis set, that info gets added as input annotations instead ๐ซถ--allow-deprecated-dag-overlapโ enables overlapping among matches in a group of consecutiveCHECK-DAG:directives ๐
โ ๏ธ this option is deprecated! it's only here for convenience while old tests get migrated to the new non-overlapping CHECK-DAG: implementation ๐ฅฒ
--allow-emptyโ allows checking empty input ๐ซ by default, empty input gets rejected ๐ โโ๏ธ--colorโ uses colours in the output ๐ this is autodetected by default โจ
; X64: pinsrd_1:
; X64: pinsrd $1, %edi, %xmm0
}
Okay so in this one we're checking that we get the right codegen for both 32-bit and 64-bit, and it's giving full coverage โจ๐
๐ The COM: directive ๐
Sometimes you want to turn off a FileCheck directive without deleting it, or you want to leave a comment that mentions a directive by name. That's where COM: comes in, and it makes this so easy ๐ซถ For example, you might have:
; X32: pinsrd_1:
; X32: pinsrd $1, 4(%esp), %xmm0
; COM: FIXME: X64 isn't working correctly yet for this part of codegen, but
; COM: X64 will have something similar to X32:
; COM:
; COM: X64: pinsrd_1:
; COM: X64: pinsrd $1, %edi, %xmm0
Without COM:, you'd have to reword stuff and mangle the directive syntax just so FileCheck doesn't treat those commented X32: and X64: lines as real directives ๐ญ Plus, FileCheck diagnostics have been proposed that might yell at those X64 lines for not having the trailing :, because they'd look like directive typos ๐ Dodging all of that is so tedious for the test author, and mangling the syntax makes the test code way less clear. COM: avoids all of it, no notes ๐ฆ
A few important usage notes, bestie:
COM:sitting inside another directive's pattern does not comment out the rest of the pattern ๐ For example:
; X32: pinsrd $1, 4(%esp), %xmm0 COM: This is part of the X32 pattern!
If you need to temporarily comment out part of a directive's pattern, move it onto another line instead. The reason is that FileCheck parses COM: the same way as any other directive, so only the first directive on the line gets recognized ๐ง
- For the sake of LIT, FileCheck treats
RUN:just likeCOM:๐ If that's not suitable for your test environment, check out--comment-prefixes. - FileCheck does not recognize
COM,RUN, or any user-defined comment prefix as a comment directive if it's combined with one of the usual check directive suffixes, like-NEXT:or-NOT:(we'll get to those below) ๐ Instead, FileCheck treats that combo as plain text. If it needs to work as a comment directive for your test environment, define it that way with--comment-prefixes.
๐ฆ The CHECK-NEXT: directive ๐ฆ
Sometimes you want to match lines and make sure the matches happen on exactly consecutive lines, with no other lines squeezed in between ๐ฅบ In that case, use a CHECK: and a CHECK-NEXT: directive together. If you've got a custom check prefix, just use <PREFIX>-NEXT: instead. Something like this works exactly how you'd expect:
define void @t2(<2 x double>* %r, <2 x double>* %A, double %B) {
%tmp3 = load <2 x double>* %A, align 16
%tmp7 = insertelement <2 x double> undef, double %B, i32 0
%tmp9 = shufflevector <2 x double> %tmp3,
<2 x double> %tmp7,
<2 x i32> < i32 0, i32 2 >
store <2 x double> %tmp9, <2 x double>* %r, align 16
ret void
; CHECK: t2:
; CHECK: movl 8(%esp), %eax
; CHECK-NEXT: movapd (%eax), %xmm0
; CHECK-NEXT: movhpd 12(%esp), %xmm0
; CHECK-NEXT: movl 4(%esp), %eax
; CHECK-NEXT: movapd %xmm0, (%eax)
; CHECK-NEXT: ret
}
Heads up ๐จ CHECK-NEXT: directives will reject the input unless there's exactly one newline between them and the previous directive. And a CHECK-NEXT: can never be the first directive in a file.
๐ธ The CHECK-SAME: directive ๐ธ
Sometimes you want matches to land on the same line as the previous match. For that, pair a CHECK: with a CHECK-SAME: directive ๐ With a custom check prefix, it's <PREFIX>-SAME:.
CHECK-SAME: is seriously powerful when you team it up with CHECK-NOT: (more on that below) โจ For example, this one works like a dream:
!0 = !DILocation(line: 5, scope: !1, inlinedAt: !2)
; CHECK: !DILocation(line: 5,
; CHECK-NOT: column:
; CHECK-SAME: scope: ![[SCOPE:[0-9]+]]
CHECK-SAME: directives will reject the input if there are any newlines between them and the previous directive ๐
โโ๏ธ
It's also super handy for skipping fields you don't care about ๐ Say you're testing a tool that spits out output like this:
Name: foo
Field1: ...
Field2: ...
Field3: ...
Value: 1
Name: bar
Field1: ...
Field2: ...
Field3: ...
Value: 2
Name: baz
Field1: ...
Field2: ...
Field3: ...
Value: 1
To check that foo has the value 1, you might first try this:
CHECK: Name: foo
CHECK: Value: 1{{$}}
But that's a bad test ๐ฌ If foo's value changes, the test would still pass, because the CHECK: Value: 1 line would just latch onto the value from baz. You could add CHECK-NEXT matchers for every FieldN: line to fix it, but that's verbose and you'd have to update it every time Field4 shows up. The succinct move is the CHECK-SAME: matcher:
CHECK: Name: foo
CHECK: Value:
CHECK-SAME: {{ 1$}}
This checks that the next time Value: shows up in the output, it has the value 1 ๐
Note: a CHECK-SAME: cannot be the first directive in a file.
๐ง The CHECK-EMPTY: directive ๐ง
If you need to check that the next line is totally empty, not even whitespace, use the CHECK-EMPTY: directive ๐ซง
declare void @foo()
declare void @bar()
; CHECK: foo
; CHECK-EMPTY:
; CHECK-NEXT: bar
Just like CHECK-NEXT:, this one fails if there's more than one newline before it finds the next blank line, and it can't be the first directive in a file.
๐
โโ๏ธ The CHECK-NOT: directive ๐
โโ๏ธ
The CHECK-NOT: directive makes sure a string does not show up between two matches (or before the first match, or after the last one) ๐ฅ For example, if you want to prove a transformation removed a load, a test like this does the job:
define i8 @coerce_offset0(i32 %V, i32* %P) {
store i32 %V, i32* %P
%P2 = bitcast i32* %P to i8*
%P3 = getelementptr i8* %P2, i32 2
%A = load i8* %P3
ret i8 %A
; CHECK: @coerce_offset0
; CHECK-NOT: load
; CHECK: ret i8
}
๐ The CHECK-COUNT: directive ๐
If you need to match the same pattern over and over, you can just repeat a plain CHECK: as many times as you need ๐
But if that feels boring, you can use a counted check, CHECK-COUNT-<num>:, where <num> is a positive decimal number ๐ It matches the pattern exactly <num> times, no more and no less. With a custom check prefix, use <PREFIX>-COUNT-<num>: for the same effect.
Here's a simple example:
Loop at depth 1
Loop at depth 1
Loop at depth 1
Loop at depth 1
Loop at depth 2
Loop at depth 3
; CHECK-COUNT-6: Loop at depth {{[0-9]+}}
; CHECK-NOT: Loop at depth {{[0-9]+}}
๐ The CHECK-DAG: directive ๐
Sometimes the strings you need to match don't show up in a strictly sequential order. That's when CHECK-DAG: saves the day ๐ฆ It verifies them between two matches (or before the first match, or after the last one). For example, clang emits vtable globals in reverse order, but using CHECK-DAG: we can keep our checks in the natural order:
// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
struct Foo { virtual void method(); };
Foo f; // emit vtable
// CHECK-DAG: @_ZTV3Foo =
struct Bar { virtual void method(); };
Bar b;
// CHECK-DAG: @_ZTV3Bar =
CHECK-NOT: directives can be mixed in with CHECK-DAG: directives to exclude strings between the surrounding CHECK-DAG: directives ๐ The catch is that the surrounding CHECK-DAG: directives can't be reordered. In other words, all the occurrences matching the CHECK-DAG: before CHECK-NOT: must not fall behind occurrences matching the CHECK-DAG: after CHECK-NOT:. For example:
; CHECK-DAG: BEFORE
; CHECK-NOT: NOT
; CHECK-DAG: AFTER
This case will reject input strings where BEFORE occurs after AFTER ๐ซ
With captured variables, CHECK-DAG: can match valid topological orderings of a DAG, with edges going from the definition of a variable to its use ๐ง This is super useful when your tests need to match different output sequences from the instruction scheduler. For example:
; CHECK-DAG: add [[REG1:r[0-9]+]], r1, r2
; CHECK-DAG: add [[REG2:r[0-9]+]], r3, r4
; CHECK: mul r5, [[REG1]], [[REG2]]
In this case, any order of those two add instructions will be allowed โจ
If you're defining and using variables in the same CHECK-DAG: block, be aware that the definition rule can match after its use ๐ณ So, for instance, the code below will pass:
; CHECK-DAG: vmov.32 [[REG2:d[0-9]+]][0]
; CHECK-DAG: vmov.32 [[REG2]][1]
vmov.32 d0[1]
vmov.32 d0[0]
But this other code will not:
; CHECK-DAG: vmov.32 [[REG2:d[0-9]+]][0]
; CHECK-DAG: vmov.32 [[REG2]][1]
vmov.32 d1[1]
vmov.32 d0[0]
โ ๏ธ This can be very useful, but it's also dangerous! For register sequences you need a strong order (read before write, copy before use, and so on). If the definition your test is hunting for doesn't match (because of a bug in the compiler), it might match further away from the use and mask real bugs. ๐ So, to enforce the order in those cases, use a non-DAG directive between the DAG-blocks.
A CHECK-DAG: directive skips matches that overlap the matches of any preceding CHECK-DAG: directives in the same CHECK-DAG: block ๐ซถ This non-overlapping behavior is consistent with other directives, and it's also necessary for handling sets of non-unique strings or patterns. For example, these directives look for unordered log entries for two tasks in a parallel program, like the OpenMP runtime:
// CHECK-DAG: [[THREAD_ID:[0-9]+]]: task_begin
// CHECK-DAG: [[THREAD_ID]]: task_end
//
// CHECK-DAG: [[THREAD_ID:[0-9]+]]: task_begin
// CHECK-DAG: [[THREAD_ID]]: task_end
The second pair of directives is guaranteed not to match the same log entries as the first pair ๐ซถ, even when the patterns are identical and the log text is identical too, because the thread ID manages to get reused. That's the drama ๐ญ
โจ The โCHECK-LABEL:โ directive โจ
Sometimes in a file with multiple tests split into logical blocks, one or more CHECK: directives can accidentally pass by matching lines in a later block ๐. An error usually shows up eventually, but the check that gets blamed may have zero connection to the actual source of the problem. Not it ๐.
To get better error messages, use the CHECK-LABEL: directive ๐. It works exactly like a normal CHECK directive, except FileCheck makes an extra assumption: a line matched by it can't also be matched by any other check in match-filename. It's meant for lines with labels or other unique identifiers. Conceptually, CHECK-LABEL splits the input stream into separate blocks that are each processed independently, so a CHECK: in one block can't match a line in another. And if --enable-var-scope is in effect, all local variables get cleared at the beginning of the block ๐งน.
For example,
define %struct.C* @C_ctor_base(%struct.C* %this, i32 %x) {
entry:
; CHECK-LABEL: C_ctor_base:
; CHECK: mov [[SAVETHIS:r[0-9]+]], r0
; CHECK: bl A_ctor_base
; CHECK: mov r0, [[SAVETHIS]]
%0 = bitcast %struct.C* %this to %struct.A*
%call = tail call %struct.A* @A_ctor_base(%struct.A* %0)
%1 = bitcast %struct.C* %this to %struct.B*
%call2 = tail call %struct.B* @B_ctor_base(%struct.B* %1, i32 %x)
ret %struct.C* %this
}
define %struct.D* @D_ctor_base(%struct.D* %this, i32 %x) {
entry:
; CHECK-LABEL: D_ctor_base:
Using CHECK-LABEL: here means the three CHECK: directives only accept lines from the body of the @C_ctor_base function, even if their patterns match lines found later in the file ๐. Furthermore, if one of those three CHECK: directives fails, FileCheck recovers by continuing to the next block, so multiple test failures can be detected in a single invocation ๐.
There's no requirement that CHECK-LABEL: directives contain strings that correspond to actual syntactic labels in a source or output language. They just have to uniquely match a single line in the file being verified ๐ฆ.
Heads up: CHECK-LABEL: directives cannot contain variable definitions or uses. No exceptions, bestie ๐
โโ๏ธ.
โจ Directive modifiers โจ
A directive modifier can be appended to a directive by following the directive with {<modifier>}, where the only supported value for <modifier> is LITERAL ๐
.
The LITERAL directive modifier performs a literal match. It means the directive won't recognise any regex matching syntax, variable capture, or substitutions. This is useful when the text you want to match would otherwise need excessive escaping ๐. For example, the following performs literal matches instead of treating these as regular expressions:
Input: [[[10, 20]], [[30, 40]]]
Output %r10: [[10, 20]]
Output %r10: [[30, 40]]
; CHECK{LITERAL}: [[[10, 20]], [[30, 40]]]
; CHECK-DAG{LITERAL}: [[30, 40]]
; CHECK-DAG{LITERAL}: [[10, 20]]
โจ FileCheck Regex Matching Syntax โจ
Every FileCheck directive takes a pattern to match. For most uses, fixed string matching is perfectly sufficient ๐. For some things you want something more flexible, so FileCheck lets you write regular expressions inside matching strings, surrounded by double braces: {{yourregex}} ๐ง. FileCheck implements a POSIX regular expression matcher and supports Extended POSIX regular expressions (ERE). Since fixed string matching covers most of what we do, FileCheck is built to mix and match fixed strings with regexes, so you can write stuff like this:
; CHECK: movhpd {{[0-9]+}}(%esp), {{%xmm[0-7]}}
In this case, any offset from the ESP register is allowed, and any xmm register is allowed too ๐.
Regular expressions are wrapped in double braces, so they're visually distinct, and you don't need to escape characters inside the braces like you would in C โจ. In the rare case you want to match double braces explicitly from the input, you can use something ugly like {{[}][}]}} as your pattern ๐. Or, if you're using the repetition count syntax, like [[:xdigit:]]{8} to match exactly 8 hex digits, you need to add parentheses like this: {{([[:xdigit:]]{8})}}, so it doesn't get confused with FileCheck's closing double-brace ๐ซถ.
โจ FileCheck String Substitution Blocks โจ
It's often useful to match a pattern and then verify that it shows up again later in the file ๐. For codegen tests, this lets you allow any register, but also verify that the same register is used consistently later. FileCheck supports string substitution blocks that let you define string variables and substitute them into patterns. Here's a simple example:
; CHECK: test5:
; CHECK: notw [[REGISTER:%[a-z]+]]
; CHECK: andw {{.*}}[[REGISTER]]
The first check line matches the regex %[a-z]+ and captures it into the string variable REGISTER. The second line verifies that whatever is in REGISTER shows up later in the file after an โandwโ ๐ฅ.
FileCheck string substitution blocks are always wrapped in [[ ]] pairs, and string variable names can be formed with the regex [a-zA-Z_][a-zA-Z0-9_]*. If a colon follows the name, it's a definition of the variable. Otherwise, it's a substitution ๐.
FileCheck variables can be defined multiple times, and substitutions always grab the latest value. You can also substitute a variable later on the same line it was defined on. For example:
; CHECK: op [[REG:r[0-9]+]], [[REG]]
This is handy if you want the operands of op to be the same register and don't care exactly which register it is ๐ง .
If --enable-var-scope is in effect, variables whose names start with $ are considered global. All other variables are local. All local variables get undefined at the beginning of each CHECK-LABEL block. Global variables aren't affected by CHECK-LABEL. This makes it way easier to make sure individual tests aren't affected by variables set in preceding tests ๐ธ.
โจ FileCheck Numeric Substitution Blocks โจ
FileCheck also supports numeric substitution blocks, which let you define numeric variables and check for numeric values that satisfy a numeric expression constraint based on those variables, through a numeric substitution ๐ข. This lets CHECK: directives verify a numeric relation between two numbers, like making sure consecutive registers are used ๐ฆ.
The syntax to capture a numeric value is [[#%<fmtspec>,<NUMVAR>:]], where:
%<fmtspec>,is an optional format specifier that sets the number format to match and the minimum number of digits to expect.<NUMVAR>:is an optional definition of variable<NUMVAR>from the captured value.
The syntax of <fmtspec> is #.<precision><conversion specifier>, where:
#is an optional flag for hex values (see<conversion specifier>below) that requires the matched value to be prefixed by0x..<precision>is an optional printf-style precision specifier, where<precision>is the minimum number of digits the matched value must have, expecting leading zeros if needed.<conversion specifier>is an optional scanf-style conversion specifier that sets the number format to match (e.g. hex number). The currently accepted format specifiers are%u,%d,%xand%X. If it's absent, the format specifier defaults to%u.
For example:
; CHECK: mov r[[#REG:]], 0x[[#%.8X,ADDR:]]
would match mov r5, 0x0000FEFE and set REG to the value 5 and ADDR to the value 0xFEFE. Note that because of the precision, it would fail to match mov r5, 0xFEFE ๐
โโ๏ธ.
Since the numeric variable definition is optional, you can also just check that a numeric value is present in a given format. This is useful when the value itself isn't important, for instance:
; CHECK-NOT: mov r0, r[[#]]
This checks that a value is synthesized rather than moved around ๐ .
The syntax of a numeric substitution is [[#%<fmtspec>, <constraint> <expr>]], where:
<fmtspec>is the same format specifier used for defining a variable, but here it describes how a numeric expression value should be matched. If it's absent, both parts of the format specifier are inferred from the matching format of the numeric variable(s) used by the expression constraint, if any. It defaults to%uif no numeric variable is used, meaning the value should be unsigned with no leading zeros. If several numeric variables conflict on format specifiers, the conversion specifier becomes mandatory, but the precision specifier stays optional ๐ค.<constraint>describes how the value to match must relate to the value of the numeric expression. The only currently accepted constraint is==for an exact match, and it's the default if<constraint>isn't provided. No matching constraint must be specified when the<expr>is empty.<expr>is an expression. An expression is recursively defined as:- a numeric operand, or
- an expression followed by an operator and a numeric operand.
A numeric operand is a previously defined numeric variable, an integer literal, or a function. Spaces are accepted before, after, and between any of these elements. Numeric operands have 64-bit precision. Overflow and underflow are rejected. There's no support for operator precedence, but parentheses can be used to change the evaluation order ๐งฎ.
The supported operators are:
+- Returns the sum of its two operands.-- Returns the difference of its two operands.
The syntax of a function call is <name>(<arguments>), where:
nameis a predefined string literal. The accepted values are:add- Returns the sum of its two operands.div- Returns the quotient of its two operands.max- Returns the largest of its two operands.min- Returns the smallest of its two operands.mul- Returns the product of its two operands.sub- Returns the difference of its two operands.
<arguments>is a comma-separated list of expressions.
For example:
; CHECK: load r[[#REG:]], [r0]
; CHECK: load r[[#REG+1]], [r1]
; CHECK: Loading from 0x[[#%x,ADDR:]]
; CHECK-SAME: to 0x[[#ADDR + 7]]
okay so this example would match this text ๐
load r5, [r0]
load r6, [r1]
Loading from 0xa0463440 to 0xa0463447
but it would NOT match this one ๐
load r5, [r0]
load r7, [r1]
Loading from 0xa0463440 to 0xa0463443
Why? Because 7 is not equal to 5 + 1, and a0463443 is not equal to a0463440 + 7. Literally the math ain't mathing ๐
Also, a numeric variable can be set to the result of a numeric expression. In that case, the expression constraint gets checked, and if it passes, the variable gets assigned that value. The unified syntax for both checking an expression and capturing its value into a numeric variable is [[#%<fmtspec>,<NUMVAR>: <constraint> <expr>]], with each element working the way it was described earlier. This is so good for making your testcase self-describing, because you can use variables instead of raw values โจ
; CHECK: mov r[[#REG_OFFSET:]], 0x[[#%X,FIELD_OFFSET:12]]
; CHECK-NEXT: load r[[#]], [r[[#REG_BASE:]], r[[#REG_OFFSET]]]
which would match:
mov r4, 0xC
load r6, [r5, r4]
The --enable-var-scope option has the same effect on numeric variables as it does on string variables ๐ฆ
Important note: In its current implementation, an expression cannot use a numeric variable defined earlier in the same CHECK directive. Be careful with this one, bestie ๐ญ
โจ FileCheck Pseudo Numeric Variables โจ
Sometimes you need to verify output that contains line numbers from the match file, like when you're testing compiler diagnostics. The problem is that this makes your match file kinda fragile, since CHECK: lines hold absolute line numbers in the same file, and those have to get updated every time line numbers shift because of text getting added or deleted ๐ฅฒ
To fix that, FileCheck expressions understand the @LINE pseudo numeric variable. It evaluates to the line number of the CHECK pattern where it's found ๐ธ
So you can park your match patterns right next to the relevant test lines and use relative line number references, like this:
// CHECK: test.cpp:[[# @LINE + 4]]:6: error: expected ';' after top level declarator
// CHECK-NEXT: {{^int a}}
// CHECK-NEXT: {{^ \^}}
// CHECK-NEXT: {{^ ;}}
int a
For the legacy crowd who still use @LINE as a special string variable, FileCheck also accepts these forms with the string substitution block syntax. No spaces inside the brackets, and the offset has to be an integer ๐
[[@LINE]]โ the current line number, no offset[[@LINE+<offset>]]โ the current line number plus an offset[[@LINE-<offset>]]โ the current line number minus an offset
โจ Matching Newline Characters โจ
If you want to match newline characters in regular expressions, use the character class [[:space:]] ๐ง For example, this pattern:
// CHECK: DW_AT_location [DW_FORM_sec_offset] ([[DLOC:0x[0-9a-f]+]]){{[[:space:]].*}}"intd"
matches output of this form (from llvm-dwarfdump):
DW_AT_location [DW_FORM_sec_offset] (0x00000233)
DW_AT_name [DW_FORM_strp] ( .debug_str[0x000000c9] = "intd")
This lets us set the FileCheck variable DLOC to the desired value 0x00000233, pulled from the line right before "intd". Main character energy, no cap ๐ฆ
โจ AUTHOR โจ
Maintained by the LLVM Team (https://llvm.org/) ๐ซถ
โจ COPYRIGHT โจ
2003-2024, LLVM Project ๐
And that's the whole page, bestie ๐ This one's version 15, dated 2024-04-14. Stay iconic, and go slay those match files ๐ โจ
๐ฆ where this page comes from
- ubuntu noble: llvm-16 1:16.0.6-23ubuntu4 ยท APACHE-2-LLVM-EXCEPTIONS
- ๐ girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms