FILECHECK(1)
๐ FILECHECK(1) ๐
Okay bestie, this page lives in the LLVM manual, and it's all about FileCheck ๐
โจ 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 in through standard input, and one you name on the command line. Then it uses one to verify the other ๐ฅ This is literally a lifesaver for the testsuite, because it checks that a tool's output (like llc) has the info you expect. Think a movsd from esp or whatever is giving you main character energy in the output. It's kind of like grep, but it's built for matching multiple different patterns inside one file, in a specific order. Iconic. ๐
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 ๐ธ
Okay, options can come from the environment variable FILECHECK_OPTS and from the command line, so you've got options (pun intended) ๐
-helpโ Prints a summary of the command line options. Your go-to when you forget what's what ๐--check-prefix prefixโ By default, FileCheck goes hunting through match-filename for patterns marked with"CHECK:". If that prefix doesn't fit your vibe (maybe the same input file is checking a bunch of different tools or options), you can swap it out with this flag. Just leave off the trailing":", and you can pass in one or more prefixes. Multiple prefixes are super handy for tests that change between run options but mostly stay the same ๐ฆ
Bestie, FileCheck does not allow duplicate prefixes, even if one is a check prefix and another is a comment prefix (see --comment-prefixes below). No copycats allowed ๐
--check-prefixes prefix1,prefix2,...โ An alias of--check-prefixthat lets you pass multiple prefixes as a comma separated list. Same energy, just tidier ๐--comment-prefixes prefix1,prefix2,...โ By default, FileCheck ignores any check prefix showing up in match-filename if the same line already has"COM:"or"RUN:"in front of it. Check out the section The"COM:"directive for the deets ๐
You can override these default comment prefixes with --comment-prefixes if they're not working for your testing environment. Lowkey though, it's not recommended in LLVM's LIT-based test suites, because those are way easier to maintain when everyone follows the same comment style. If the defaults aren't cutting it, 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'strue, that's allowed. If it'sfalse, FileCheck will throw an error and list the missing prefixes. The default isfalse๐--input-file filenameโ The file to check. If you don't use this, it defaults to stdin ๐ง--match-full-linesโ By default, FileCheck is chill and lets matches happen anywhere on a line. This option is stricter: every positive match has to cover an entire line. Leading and trailing whitespace gets ignored, unless you also pass--strict-whitespace.
Heads up, though: negative matches from CHECK-NOT are not affected by this option! ๐
Passing this option is the same as putting {{^ *}} or {{^}} before, and {{ *$}} or {{$}} after, every positive check pattern:
{{^ *}} and {{ *$}}
{{^}} and {{$}}
--strict-whitespaceโ By default, FileCheck canonicalizes horizontal whitespace in the input (spaces and tabs), so it ignores those differences. That means a space will match a tab, which is kinda slay. This flag turns that off. End-of-line sequences get canonicalized to UNIX-style\nin all modes, though ๐--ignore-caseโ By default, FileCheck uses case-sensitive matching. This option switches it to case-insensitive matching, soCHECKandcheckare both fair game ๐ฆ--implicit-check-not check-patternโ This adds implicit negative checks for the patterns you specify, in between the positive checks. It lets you write stricter tests without stuffing them full ofCHECK-NOTs. It's so efficient ๐
For example, --implicit-check-not warning: can be super useful when you're testing diagnostic messages from tools that don't have an option like clang's -verify. With this option, FileCheck will verify that the input doesn't contain any warnings that aren't covered by a CHECK: pattern. Not a single rogue warning gets through ๐
--dump-input <value>โ Dumps the input to stderr and adds annotations for the diagnostics that are currently enabled. If you use this option more than once, the<value>that appears 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 requested by--dump-input, this prints<N>input lines before and<N>input lines after any lines picked out by--dump-input-filter. If you use this option multiple times, the largest<N>wins. The default is5๐ธ--dump-input-filter <value>โ In the dump requested by--dump-input, this prints only the input lines of the kind<value>, plus whatever context--dump-input-contextasks for. If you use this option more than once, the<value>that appears earliest in the list below wins.
The default is error when --dump-input=fail, and it's all when --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 ๐
Okay so, in this case we're testing that we get the expected code generation with both 32-bit and 64-bit code generation โจ
๐ The "COM:" directive ๐
Sometimes you wanna turn off a FileCheck directive without deleting it entirely, or you want to write comments that mention a directive by name. That's where the COM: directive comes in and makes it 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 need some combo of rewording and directive syntax mangling to stop FileCheck from recognizing the commented occurrences of X32: and X64: above as directives. Plus, FileCheck diagnostics have been proposed that might complain about those X64 occurrences that don't have the trailing :, since they look like directive typos ๐ Dodging all of this is tedious for a test author, and directive syntax mangling can make the purpose of the test code unclear. COM: avoids all these problems, periodt ๐
A few important usage notes:
COM:inside a pattern โCOM:within 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 to another line. The reason is that FileCheck parses COM: the same way as any other directive, so only the first directive on the line is recognized as a directive.
RUN:is a comment too โ For the sake of LIT, FileCheck treatsRUN:just likeCOM:. If that's not suitable for your test environment, see--comment-prefixes๐ธ- Suffix combos don't count โ 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, such as-NEXT:or-NOT:(discussed below). FileCheck treats such a combination as plain text instead. If it needs to act as a comment directive for your test environment, define it as one with--comment-prefixesโจ
๐ฆ The "CHECK-NEXT:" directive ๐ฆ
Sometimes you wanna match lines and verify that the matches happen on exactly consecutive lines, with no other lines in between. For that, use CHECK: and CHECK-NEXT: together. If you specified a custom check prefix, just use <PREFIX>-NEXT:. For example, 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 first directive in a file ๐
๐ The "CHECK-SAME:" directive ๐
Sometimes you want matches to happen on the same line as the previous match. Use CHECK: and CHECK-SAME: for that. If you specified a custom check prefix, just use <PREFIX>-SAME:.
CHECK-SAME: is especially powerful when paired with CHECK-NOT: (described below). For example, this 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 super handy for skipping matchers on irrelevant fields. Say you're writing a test that parses a tool generating 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 verifies foo has the value 1, you might first write this:
CHECK: Name: foo
CHECK: Value: 1{{$}}
Ngl, this would be a bad test ๐ If the value for foo changes, the test would still pass, because the CHECK: Value: 1 line would match the value from baz. You could fix it by adding CHECK-NEXT matchers for every FieldN: line, but that's verbose and would need updating whenever Field4 is added. A more succinct way, using the CHECK-SAME: matcher, looks like this:
CHECK: Name: foo
CHECK: Value:
CHECK-SAME: {{ 1$}}
This verifies that the next time Value: appears 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 has nothing on it, 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 directive will fail if there is more than one newline before it finds the next blank line, and it cannot be the first directive in a file.
๐ The "CHECK-NOT:" directive ๐
The CHECK-NOT: directive verifies that a string doesn't occur between two matches (or before the first match, or after the last match). For example, to verify that a load gets removed by a transformation, a test like this can be used:
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 multiple lines with the same pattern over and over, you can repeat a plain CHECK: as many times as needed. If that looks too boring, you can instead use a counted check, CHECK-COUNT-<num>:, where <num> is a positive decimal number. It will match the pattern exactly <num> times, no more and no less. If you specified a custom check prefix, just 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 it's necessary to match strings that don't occur in a strictly sequential order, CHECK-DAG: can verify them between two matches (or before the first match, or after the last match). For example, clang emits vtable globals in reverse order. Using CHECK-DAG:, we can 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 with CHECK-DAG: directives to exclude strings between the surrounding CHECK-DAG: directives. As a result, the surrounding CHECK-DAG: directives cannot be reordered. In other words, all occurrences matching CHECK-DAG: before CHECK-NOT: must not fall behind occurrences matching 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 running from the definition of a variable to its use. It's useful, e.g., 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, any order of those two add instructions will be allowed.
If you are 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]
While 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]
While this can be very useful, it's also dangerous โ ๏ธ In the case of register sequences, you must have a strong order (read before write, copy before use, etc.). If the definition your test is looking for doesn't match (because of a bug in the compiler), it may match further away from the use and mask real bugs.
In those cases, to enforce the order, use a non-DAG directive between DAG-blocks ๐ซถ
A CHECK-DAG: directive skips matches that overlap the matches of any preceding CHECK-DAG: directives in the same CHECK-DAG: block. Not only is this non-overlapping behavior consistent with other directives, it's also necessary to handle sets of non-unique strings or patterns. For example, the following directives look for unordered log entries for two tasks in a parallel program, such as 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 though the patterns are identical and even if the text of the log entries is identical, because the thread ID manages to be reused ๐ง โจ
โจ The "CHECK-LABEL:" directive โจ
Okay so, picture this ๐ซ you've got a test file split into logical blocks, and a CHECK: line from one block sneaks into a later block and "passes" ๐ ngl an error usually shows up eventually, but it's pointing at a check that has nothing to do with the actual problem. Not it.
That's where CHECK-LABEL: comes in ๐ฆธโโ๏ธ It works exactly like a normal CHECK directive, EXCEPT FileCheck assumes a line matched by it can't also be matched by any other check in match-filename. It's basically made for labels or other unique identifiers ๐ท๏ธ Conceptually, it chops the input stream into separate blocks, each processed on its own, 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 wiped at the start of each block ๐งน
Here's an example bestie:
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:
The CHECK-LABEL: lines here make sure the three CHECK: directives only accept lines from the body of the @C_ctor_base function ๐ฏ even if their patterns match stuff way further down the file. And if one of those three CHECK: directives fails, FileCheck just keeps going to the next block, so you can catch multiple failures in a single invocation ๐
There's no rule that CHECK-LABEL: strings have to match real 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 โจ
You can tack a directive modifier onto a directive by following it with {<modifier>} ๐
The only supported value for <modifier> is LITERAL.
The LITERAL modifier does a literal match ๐ It turns off regex matching, variable capture, and substitutions, which is perfect when the text you're matching would need excessive escaping otherwise. For example, these will be treated as literal matches instead of 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 things, fixed string matching is perfectly sufficient. When you need something more flexible, you can write a regular expression wrapped in double braces: {{yourregex}}. FileCheck uses a POSIX regular expression matcher and supports Extended POSIX regular expressions (ERE) ๐ง Since most of what we do is fixed string matching, FileCheck lets you 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 ๐
Because regexes are wrapped in double braces, they're visually distinct, and you don't need escape characters inside them like you would in C ๐ธ In the rare case you want to match double braces literally 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 {{([[:xdigit:]]{8})}} so it doesn't get confused with FileCheck's closing double-brace ๐
โจ FileCheck String Substitution Blocks โจ
It's often super useful to match a pattern and then check that it shows up again later in the file ๐ For codegen tests, this lets you accept any register but verify that the same register gets used consistently later. FileCheck supports string substitution blocks for this, letting 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 useful if you want both operands of op to be the same register, and you don't care exactly which register it is ๐ซถ
If --enable-var-scope is in effect, variables whose names start with $ are considered global, and all others 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 has numeric substitution blocks ๐ข These let you define numeric variables and check for numeric values that satisfy a numeric expression constraint based on those variables. This means CHECK: directives can verify a numeric relation between two numbers, like making sure consecutive registers are used ๐
To capture a numeric value, the syntax is [[#%<fmtspec>,<NUMVAR>:]], where:
%<fmtspec>,is an optional format specifier that says what 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, with leading zeros expected if needed.<conversion specifier>is an optional scanf-style conversion specifier that says what number format to match (e.g. hex number). 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 can be handy when the value itself isn't useful, for instance:
; CHECK-NOT: mov r0, r[[#]]
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 as for defining a variable, but in this context it indicates how a numeric expression value should be matched. If it's absent, both components 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 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 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 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. 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 the text:
load r5, [r0]
load r6, [r1]
Loading from 0xa0463440 to 0xa0463447
but would not match the text:
load r5, [r0]
load r7, [r1]
Loading from 0xa0463440 to 0xa0463443
Why does that one bonk? Because 7 is unequal to 5 + 1, and a0463443 is unequal to a0463440 + 7. ๐
Okay so, a numeric variable can also be set to the result of a numeric expression โจ. When that happens, the numeric expression constraint gets checked, and if it passes, the variable is assigned that value. The unified syntax for checking a numeric expression and capturing its value into a numeric variable is [[#%<fmtspec>,<NUMVAR>: <constraint> <expr>]], with each element working the way we covered earlier ๐
. Bestie, you can use this to make a testcase way more self-describing by using 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]]]
And it would totally match 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 ๐ซถ.
๐จ Important note: In its current implementation, an expression cannot use a numeric variable defined earlier in the same CHECK directive. Don't even try it, bestie ๐
โจ FileCheck Pseudo Numeric Variables โจ
Sometimes you need to verify output that contains line numbers of the match file, like when you're testing compiler diagnostics ๐ง. It's lowkey fragile though, because CHECK: lines contain absolute line numbers in the same file, and those have to be updated every single time line numbers shift from text being added or deleted ๐ฉ.
To help with this, FileCheck expressions understand the @LINE pseudo numeric variable ๐ธ, which evaluates to the line number of the CHECK pattern where it's found. Slay.
This way, match patterns can live right near the relevant test lines and use relative line number references, like so:
// CHECK: test.cpp:[[# @LINE + 4]]:6: error: expected ';' after top level declarator
// CHECK-NEXT: {{^int a}}
// CHECK-NEXT: {{^ \^}}
// CHECK-NEXT: {{^ ;}}
int a
To keep legacy uses of @LINE working as a special string variable, FileCheck also accepts these forms with string substitution block syntax: [[@LINE]], [[@LINE+<offset>]] and [[@LINE-<offset>]]. Just make sure there are no spaces inside the brackets, and offset has to be an integer ๐ง.
โจ Matching Newline Characters โจ
Okay so, 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 the 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 desired value 0x00000233, pulled from the line immediately preceding "intd" ๐. That's giving precision.
โจ AUTHOR โจ
Maintained by the LLVM Team (https://llvm.org/). ๐ซถ
โจ COPYRIGHT โจ
2003-2026, LLVM Project ๐
Bestie, that's the whole page ๐ This one's from source/version 22, dated 2026-07-16, so go forth and check ur FileCheck files ๐ฆ๐
๐ฆ where this page comes from
- fedora 44: llvm 22.1.8-4.fc44 ยท Apache-2.0 WITH LLVM-exception OR NCSA
- fedora 44: llvm 22.1.8-4.fc44 ยท Apache-2.0 WITH LLVM-exception OR NCSA
- ๐ girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms