FILECHECK(1)
๐ FILECHECK(1) ๐
okay bestie, this is the LLVM manual page for FileCheck, and it's giving main character energy ๐ โจ let's go
โจ NAME โจ
FileCheck - Flexible pattern matching file verifier ๐ฆ
๐ธ SYNOPSIS ๐ธ
FileCheck match-filename [--check-prefix=XXX] [--strict-whitespace]
๐ DESCRIPTION ๐
okay so FileCheck reads two files ๐ one comes from standard input and the other one you name on the command line, and then it uses one to verify the other. this is super useful for the testsuite, which wants to check that the output of some tool (like llc) has the info it's supposed to have, like a movsd from esp or whatever is interesting ๐ฅ it's kinda like grep, but it's way more slay at matching a bunch of different inputs inside one file, in a specific order ๐
the match-filename file is the one holding the patterns to match ๐ง the file being verified gets read from standard input unless you use the --input-file option ๐ซถ
๐ฆ OPTIONS ๐ฆ
the options get parsed from the environment variable FILECHECK_OPTS and from the command line, so you can set them in either spot ๐
-helpโ prints a summary of all the command line options ๐--check-prefix prefixโ FileCheck goes hunting through match-filename for patterns, and by default they start withCHECK:๐ if you want a different prefix (maybe the same input file checks multiple tools or options), this lets you pick one or more prefixes to match, written without the trailing:. multiple prefixes are super handy for tests that change between run options but where most lines stay the same ๐ and FileCheck does not allow duplicate prefixes, even if one is a check prefix and another is a comment prefix (see--comment-prefixesbelow) ๐ โโ๏ธ--check-prefixes prefix1,prefix2,...โ an alias of--check-prefixthat lets you pass multiple prefixes as a comma separated list ๐--comment-prefixes prefix1,prefix2,...โ by default, FileCheck ignores any check prefix in match-filename if it hasCOM:orRUN:right before it on the same line ๐ see the section The "COM:" directive for the deets. you can override these default comment prefixes with--comment-prefixesif they don't fit your testing setup, but honestly? not recommended in LLVM's LIT-based test suites, which are easier to maintain when everyone follows one consistent comment style ๐ซ so if you think they're wrong, consider 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 ๐จ it's currently, temporarily, true by default, and will be switched to false later on โณ--input-file filenameโ the file to check. defaults to stdin ๐ฅ--match-full-linesโ by default FileCheck is chill about matching 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. (Note: negative matches fromCHECK-NOTare not affected by this option, so don't get it twisted! ๐) 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), which means it ignores those differences, so 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โ by default FileCheck is case-sensitive ๐ this makes it case-insensitive instead ๐--implicit-check-not check-patternโ adds implicit negative checks for the patterns you specify, between the positive checks ๐ง it lets you write stricter tests without stuffing them full of CHECK-NOTs. for example,--implicit-check-not warning:can be iconic when you're testing diagnostic messages from tools that don't have an option like clang -verify. with this, 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 and adds annotations for whatever diagnostics are 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 quitsalwaysโ always dumps the inputfailโ dumps the input on failureneverโ never dumps the input
--dump-input-context <N>โ in the dump requested by--dump-input, prints<N>input lines before and<N>input lines after any lines picked by--dump-input-filter๐ if you use it multiple times, the largest<N>wins. the default is5โจ--dump-input-filter <value>โ in that same dump, prints only the input lines of kind<value>, plus whatever context--dump-input-contextasks for ๐ฏ multiple uses? the<value>earliest in the list below has precedence. the default iserrorwhen--dump-input=fail, and it'sallwhen--dump-input=always๐ธallโ all input linesannotation-fullโ input lines with annotationsannotationโ input lines with starting points of annotationserrorโ input lines with starting points of error annotations
--enable-var-scopeโ enables scope for regex variables ๐งฉ variables whose names start with$are considered global and stay set the whole way through the file ๐ all the other variables get undefined after eachCHECK-LABELthey run into ๐งน-D<VAR=VALUE>โ sets a FileCheck pattern variableVARto the valueVALUE, so you can use it inCHECK:lines ๐-D#<FMT>,<NUMVAR>=<NUMERIC EXPRESSION>โ sets a FileCheck numeric variableNUMVARin the matching formatFMTto whatever you get from evaluating<NUMERIC EXPRESSION>, which you can then use inCHECK:lines ๐งฎ see section FileCheck Numeric Variables and Expressions for the supported numeric expressions ๐ค-versionโ shows the version number of this program ๐ท๏ธ-vโ prints the good directive pattern matches โ but if you're using-dump-input=failor-dump-input=always, it adds those matches as input annotations instead ๐-vvโ prints info that helps diagnose internal FileCheck issues ๐ง think discarded overlappingCHECK-DAG:matches, implicit EOF pattern matches, andCHECK-NOT:patterns that never found a match ๐ it implies-v. however, if you're using-dump-input=failor-dump-input=always, it just adds that info 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, so don't build new stuff on it ๐ญ
--allow-emptyโ allows checking empty input. by default, empty input gets rejected ๐ซ--colorโ uses colors in the output ๐ (it's autodetected by default, so you probably don't even need it ๐ )
๐ EXIT STATUS ๐
if FileCheck verifies that the file matches the expected contents, it exits with 0 โ
otherwise, if it doesn't match, or if an error happens, it exits with a non-zero value โ
๐ฌ TUTORIAL ๐ฌ
okay so FileCheck is basically always used inside LLVM regression tests, where it gets invoked on the RUN line of the test ๐ here's a super simple example of using FileCheck from a RUN line:
; RUN: llvm-as < %s | llc -march=x86-64 | FileCheck %s
so this line pipes the current file (%s) into llvm-as, pipes that into llc, and then pipes the output of llc into FileCheck ๐ง which means FileCheck is verifying its standard input (the llc output) against the filename argument you gave it (the original .ll file named by %s) ๐ to see how it all works, let's look at the rest of the .ll file, after the RUN line:
define void @sub1(i32* %p, i32 %v) {
entry:
; CHECK: sub1:
; CHECK: subl
%0 = tail call i32 @llvm.atomic.load.sub.i32.p0i32(i32* %p, i32 %v)
ret void
}
define void @inc4(i64* %p) {
entry:
; CHECK: inc4:
; CHECK: incq
%0 = tail call i64 @llvm.atomic.load.add.i64.p0i64(i64* %p, i64 1)
ret void
}
see those CHECK: lines? they're sitting in comments ๐ so the file goes into llvm-as, then llc, and the machine code output is what we're verifying ๐ FileCheck checks that machine code output to make sure it matches what the CHECK: lines say โจ
the syntax of CHECK: lines is super simple: they're fixed strings that have to show up in order ๐ซถ FileCheck defaults to ignoring horizontal whitespace differences (a space is allowed to match a tab ๐ซง), but otherwise the contents of the CHECK: line have to match something in the test file exactly ๐
one thing that's lowkey amazing about FileCheck (compared to grep) is that it lets you merge test cases together into logical groups ๐งฉ for example, because the test above checks for the sub1: and inc4: labels, it won't match unless there's a subl in between those labels ๐ฏ if it showed up somewhere else in the file, that wouldn't count! grep subl would match if subl existed anywhere in the file, but FileCheck is more precise than that ๐ฆ
๐ธ The FileCheck -check-prefix option ๐ธ
the FileCheck -check-prefix option lets you drive multiple test configurations from one .ll file ๐ this is useful in lots of situations, like testing different architectural variants with llc ๐ here's a simple example:
; RUN: llvm-as < %s | llc -mtriple=i686-apple-darwin9 -mattr=sse41 \
; RUN: | FileCheck %s -check-prefix=X32
; RUN: llvm-as < %s | llc -mtriple=x86_64-apple-darwin9 -mattr=sse41 \
; RUN: | FileCheck %s -check-prefix=X64
define <4 x i32> @pinsrd_1(i32 %s, <4 x i32> %tmp) nounwind {
%tmp1 = insertelement <4 x i32>; %tmp, i32 %s, i32 1
ret <4 x i32> %tmp1
; X32: pinsrd_1:
; X32: pinsrd $1, 4(%esp), %xmm0
; X64: pinsrd_1:
; X64: pinsrd $1, %edi, %xmm0
}
Okay so in this one we're making sure we get the right codegen for both 32-bit and 64-bit code generation ๐โจ
๐ The "COM:" directive ๐
Sometimes you want to switch 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 super 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 so FileCheck doesn't mistake the commented X32: and X64: lines for real directives ๐ญ And there are FileCheck diagnostics that have been proposed which might yell about those X64 lines that don't have the trailing :, because they look like directive typos. Dodging all of that is exhausting for the test author, and mangling the syntax makes the point of the test code super unclear. COM: dodges every single one of these problems ๐ซถ
A few important usage notes, bestie:
COM:sitting inside another directive's pattern does not comment out the rest of that 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 to another line ๐ฆ The reason is that FileCheck parses COM: the same way it parses 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 doesn't work for your test environment, check out--comment-prefixes๐ - FileCheck does not recognize
COM,RUN, or any user-defined comment prefix as a comment directive when it's combined with one of the usual check directive suffixes, like-NEXT:or-NOT:(we'll get to those below). Instead, FileCheck treats the whole combo as plain text ๐ If it needs to act 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 ๐ For that, you pair up a CHECK: with a CHECK-NEXT:. If you picked 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
}
โ ๏ธCHECK-NEXT:directives reject the input unless there is exactly one newline between them and the previous directive. ACHECK-NEXT:also cannot be the very first directive in a file.
๐ฆ The "CHECK-SAME:" directive ๐ฆ
Sometimes you want to match lines and verify that a match happens on the same line as the previous match โจ For that, you use CHECK: and CHECK-SAME:. If you picked a custom check prefix, use <PREFIX>-SAME: instead.
CHECK-SAME: is especially powerful when you team it up with CHECK-NOT: (which we'll hit below ๐ง).
For example, the following works like you'd expect:
!0 = !DILocation(line: 5, scope: !1, inlinedAt: !2)
; CHECK: !DILocation(line: 5,
; CHECK-NOT: column:
; CHECK-SAME: scope: ![[SCOPE:[0-9]+]]
โ ๏ธ CHECK-SAME: directives reject the input if there are any newlines between them and the previous directive.
CHECK-SAME: is also a lifesaver for skipping matchers on fields you don't care about ๐ Say you're writing a test for 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 write a test that checks foo has the value 1, your first instinct might be this:
CHECK: Name: foo
CHECK: Value: 1{{$}}
But that's a bad test, bestie ๐ If foo's value changes, the test would still pass, because the CHECK: Value: 1 line would just match the value from baz. You could fix it by adding CHECK-NEXT matchers for every FieldN: line, but that's verbose and you'd have to update it every time a Field4 shows up. The more succinct move is using CHECK-SAME::
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), reach for the CHECK-EMPTY: directive ๐ซง
declare void @foo()
declare void @bar()
; CHECK: foo
; CHECK-EMPTY:
; CHECK-NEXT: bar
Just like CHECK-NEXT:, this directive fails if there's more than one newline before it finds the next blank line, and it also cannot 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, to check that a transformation removed a load, you can write a test like this:
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 again, you can repeat a plain CHECK: as many times as you need ๐ฅฑ If that feels too boring, use a counted check, CHECK-COUNT-<num>:, where <num> is a positive decimal number. It'll match the pattern exactly <num> times, no more and no less ๐ If you picked 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 ๐ง
If you need to match strings that don't show up in a strictly sequential order, CHECK-DAG: is your bestie ๐ซ It checks them between two matches (or before the first match, or after the last one). For example, clang emits vtable globals in reverse order, so using CHECK-DAG: lets us keep the 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. Because of that, the surrounding CHECK-DAG: directives can't be reordered. In other words, every occurrence matching a CHECK-DAG: before a CHECK-NOT: must not fall behind an occurrence matching a CHECK-DAG: after that CHECK-NOT:. For example:
; CHECK-DAG: BEFORE
; CHECK-NOT: NOT
; CHECK-DAG: AFTER
This case will reject input strings where BEFORE shows up after AFTER ๐ซ
With captured variables, CHECK-DAG: can match valid topological orderings of a DAG, with edges going from a variable's definition to its use. This is super useful when your test cases 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, either 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]
As useful as this is, it's also a little dangerous ๐ฌ With register sequences you need a strong order (read before write, copy before use, and so on). If the definition your test is looking for doesn't match (because of a bug in the compiler), it might match further away from the use and hide real bugs. In those cases, to enforce the order, use a non-DAG directive between your 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 behaviour is consistent with other directives, and it's also necessary for handling sets of non-unique strings or patterns ๐ฅน For example, the following 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 even when the log entries' text is identical, because the thread ID manages to get reused ๐
๐ The "CHECK-LABEL:" directive ๐
okay so bestie, picture a file with a bunch of tests split into logical blocks ๐ง. One or more CHECK: directives can sneakily pass by matching lines in a later block ๐ญ. An error usually shows up eventually, but the check it blames might have nothing to do with the real problem ๐.
To get better error messages in these cases, use the CHECK-LABEL: directive โจ. It works exactly like a normal CHECK directive, with one extra assumption: FileCheck figures a line matched by CHECK-LABEL: can't also be matched by any other check in match-filename. It's meant for lines with labels or other unique identifiers ๐ฆ. So a CHECK-LABEL: splits the input stream into separate blocks, and each block gets processed on its own. That means a CHECK: in one block can't match a line in another block ๐. If --enable-var-scope is in effect, all local variables get cleared at the beginning of the block ๐.
Here's the vibe:
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:
So in this case, the CHECK-LABEL: directives make sure those three CHECK: directives only accept lines from the body of @C_ctor_base, even if their patterns match lines further down the file ๐. Even better, if one of those three CHECK: directives fails, FileCheck recovers and moves on to the next block ๐ซถ. That means you can catch multiple test failures in one single invocation ๐ฅ.
There's no requirement that CHECK-LABEL: directives contain strings matching 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 ๐ซ.
๐ธ Directive modifiers ๐ธ
A directive modifier can be appended to a directive by putting {<modifier>} right after it, and the only supported value for <modifier> is LITERAL ๐.
The LITERAL modifier gives you a literal match ๐. It turns off all regex matching, variable capture, and substitutions, which is super handy when the text you're matching would need a mountain of escaping otherwise ๐ฉ. For example, these will be literal matches instead of being treated 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 of what you'll do, plain fixed string matching is totally sufficient ๐โโ๏ธ. For fancier stuff, you can use a more flexible form of matching. FileCheck lets you write regular expressions inside double braces, like {{yourregex}} โจ. Under the hood it's a POSIX regular expression matcher that supports Extended POSIX regular expressions (ERE) ๐ง . Since fixed string matching covers most of what we do, FileCheck is built so you can mix and match fixed strings with regexes in the same pattern ๐ฆ. Like this:
; CHECK: movhpd {{[0-9]+}}(%esp), {{%xmm[0-7]}}
Here, any offset from the ESP register is allowed, and any xmm register is allowed too ๐ท.
Regexes are wrapped in double braces, so they stand out visually, and you don't need to escape anything inside them the way you would in C ๐. The rare time you need to match double braces literally from the input, you can use something kinda ugly like {{[}][}]}} as your pattern ๐ต. And if you're using the repetition count syntax, like [[:xdigit:]]{8} to match exactly 8 hex digits, you need to add parentheses like {{([[:xdigit:]]{8})}}. Otherwise it gets confused with FileCheck's closing double-brace ๐.
๐ง FileCheck String Substitution Blocks ๐ง
Sometimes you want to match a pattern and then check that it shows up again later in the file ๐. For codegen tests, that's great for allowing any register while making sure that same register gets used consistently later ๐. FileCheck handles this with string substitution blocks, which 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 checks that whatever's in REGISTER shows up later in the file after an "andw" ๐
. String substitution blocks are always wrapped in [[ ]] pairs โจ. 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. If there's no colon, it's a substitution ๐.
Variables can be defined multiple times, and substitutions always grab the latest value ๐. You can even substitute a variable later on the same line it was defined on. For example:
; CHECK: op [[REG:r[0-9]+]], [[REG]]
This is perfect when you want the operands of op to be the same register but don't care which register it is ๐ฅฐ.
If --enable-var-scope is in effect, variables whose names start with $ count as global ๐. Everything else is local ๐ . All local variables get undefined at the beginning of each CHECK-LABEL block, but global variables aren't affected by CHECK-LABEL at all ๐ซ. This makes it way easier to make sure individual tests aren't messed up by variables set in earlier tests ๐ง.
๐ข FileCheck Numeric Substitution Blocks ๐ข
FileCheck also has numeric substitution blocks ๐งฎ. They let you define numeric variables and check for numeric values that satisfy a constraint based on those variables. This is how a CHECK: directive can verify a numeric relationship between two numbers, like making sure consecutive registers get used ๐ฅ.
To capture a numeric value, the syntax is [[#%<fmtspec>,<NUMVAR>:]], where:
%<fmtspec>,is an optional format specifier that tells FileCheck what number format to match and the minimum number of digits to expect ๐.<NUMVAR>:is an optional definition of the variable<NUMVAR>from the captured value ๐.
The syntax of <fmtspec> is .<precision><conversion specifier>, where:
.<precision>is an optional printf-style precision specifier.<precision>is the minimum number of digits the matched value must have, and leading zeros are expected if needed 0๏ธโฃ.<conversion specifier>is an optional scanf-style conversion specifier that tells FileCheck what number format to match, like hex. The accepted format specifiers right now are%u,%d,%xand%X. If it's missing, the format specifier defaults to%u๐ฏ.
For example:
; CHECK: mov r[[#REG:]], 0x[[#%.8X,ADDR:]]
This would match mov r5, 0x0000FEFE and set REG to the value 5 and ADDR to the value 0xFEFE ๐ฆ. But heads up, 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 actual value doesn't matter:
; 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 you'd use when defining a variable, but here it tells FileCheck how a numeric expression's value should be matched. If it's missing, both parts of the format specifier get inferred from the matching format of the numeric variables used by the constraint (if there are any). If no numeric variable is used, it defaults to%u, meaning the value is unsigned with no leading zeros ๐ข. If several numeric variables have conflicting 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 accepted constraint right now is==for an exact match, and it's the default if<constraint>isn't provided. No matching constraint should be specified when<expr>is empty ๐ซ.<expr>is an expression, and it's defined recursively 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. You can put spaces before, after, and between any of these elements ๐ซถ. Numeric operands have 64-bit precision, and overflow and underflow get rejected ๐จ. There's no operator precedence, but you can use parentheses 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]]
The above example would match this text:
load r5, [r0]
load r6, [r1]
Loading from 0xa0463440 to 0xa0463447
But it would not match this text:
load r5, [r0]
load r7, [r1]
Loading from 0xa0463440 to 0xa0463443
That's because 7 isn't equal to 5 + 1, and a0463443 isn't equal to a0463440 + 7 ๐.
Okay so bestie, numeric variables can ALSO be set from a numeric expression โจ FileCheck checks the expression against the constraint, and if it passes, the variable gets assigned that value. The unified syntax for checking an expression and capturing its value into a numeric variable is [[#%<fmtspec>,<NUMVAR>: <constraint> <expr>]], and each piece works the way we covered earlier ๐ This is lowkey amazing for making a testcase self-describing, because you can use variable names instead of raw values:
; CHECK: mov r[[#REG_OFFSET:]], 0x[[#%X,FIELD_OFFSET:12]]
; CHECK-NEXT: load r[[#]], [r[[#REG_BASE:]], r[[#REG_OFFSET]]]
And it would match stuff like this ๐ฆ
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, so it's giving consistency ๐ธ
Important note ๐จ: in its current implementation, an expression cannot use a numeric variable defined earlier in the same CHECK directive. Don't get caught out, it's a whole trap ๐
๐ง 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 CHECK: lines hold absolute line numbers in that same file, so every time someone adds or deletes text, those numbers have to be updated. Major fragility energy ๐ญ
Enter the @LINE pseudo numeric variable ๐ It evaluates to the line number of the CHECK pattern where it's found. That means your match patterns can live 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
To support legacy uses of @LINE as a special string variable, FileCheck also accepts [[@LINE]], [[@LINE+<offset>]] and [[@LINE-<offset>]] with string substitution block syntax ๐ซถ No spaces inside the brackets, and the offset has to be an integer.
๐ Matching Newline Characters
Wanna 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")
Which lets us set the FileCheck variable DLOC to the value 0x00000233, pulled from the line immediately preceding "intd" โจ Main character behavior.
โจ AUTHOR โจ
Maintained by the LLVM Team (https://llvm.org/) ๐ธ
โจ COPYRIGHT โจ
2003-2024, LLVM Project ๐
And that's the whole page, bestie! ๐ฆ This was the FileCheck manpage, source version 12, dated 2024-07-18. Stay iconic ๐ ๐
๐ฆ where this page comes from
- fedora 43: llvm12 12.0.1-12.fc41 ยท NCSA
- fedora 43: llvm12 12.0.1-12.fc41 ยท NCSA
- fedora 44: llvm12 12.0.1-12.fc41 ยท NCSA
- fedora 44: llvm12 12.0.1-12.fc41 ยท NCSA
- ๐ girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms