FILECHECK(1)
โจ FILECHECK(1) from LLVM โจ
๐ NAME ๐
FileCheck is 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 name on the command line, and then it uses one of them to verify the other ๐ซถ this is literally the move for the testsuite, which needs to confirm that some tool's output (like llc) has the info it's supposed to, like a movsd from esp or whatever is interesting ๐ it's kinda like grep, but it's built for matching a bunch of different things 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 ๐ฆ
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โFileChecksearches match-filename for patterns to match, and by default they're prefixed withCHECK:๐ if you want a different prefix (maybe the same input file is checking multiple tools or options), this lets you pick one or more prefixes to match, without the trailing:. multiple prefixes are super useful for tests that change between run options but where most lines stay the same ๐ FileCheck does not 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 multiple prefixes, comma separated ๐--comment-prefixes prefix1,prefix2,...โ by default,FileCheckignores any check prefix in match-filename if it's preceded on the same line byCOM:orRUN:๐ see the section The "COM:" directive for usage details. you can override these default comment prefixes with--comment-prefixesif they don't fit your testing environment, but it's not recommended in LLVM's LIT-based test suites, which are way easier to maintain when everything follows one consistent comment style. if that's your situation, consider proposing a change to the default comment prefixes instead ๐ญ--allow-unused-prefixesโ this controls what happens when you use more than one prefix (through--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,FileCheckreports an error listing the missing prefixes. the default value isfalse๐ซ--input-file filenameโ the file to check (defaults to stdin) ๐ฅ--match-full-linesโ by default, matches can happen anywhere on a line, but 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!) passing this option is the same as inserting{{^ *}}or{{^}}before, and{{ *$}}or{{$}}after, every positive check pattern ๐ง--strict-whitespaceโ by default,FileCheckcanonicalizes horizontal whitespace (spaces and tabs), so a space will match a tab ๐ซ this disables that behavior. end-of-line sequences get canonicalized to UNIX-style\nin all modes, though ๐ง--ignore-caseโ by default, matching is case-sensitive. this makesFileCheckuse case-insensitive matching instead ๐ค--implicit-check-not check-patternโ adds implicit negative checks for the patterns you specify, between positive checks. this lets you write stricter tests without stuffing them full ofCHECK-NOTs ๐ง for example,--implicit-check-not warning:can be really useful when testing diagnostic messages from tools that don't have an option likeclang -verify. with this option,FileCheckverifies that the input doesn't contain any warnings that aren't covered by aCHECK:pattern ๐จ--dump-input <value>โ dumps the input to stderr, adding annotations for the diagnostics that are currently enabled ๐๏ธ when this option shows up multiple times, the<value>that appears 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 specified by--dump-input-filter๐งพ when this option shows up multiple times, the largest specified<N>wins. the default is5๐ข--dump-input-filter <value>โ in the--dump-inputdump, prints only input lines of kind<value>, plus any context from--dump-input-context๐ฏ when this option shows up multiple times, the<value>that appears earliest in the list below wins. 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 throughout the whole file. all other variables get undefined after eachCHECK-LABELthat's encountered ๐งน-D<VAR=VALUE>โ sets aFileCheckpattern variableVARwith the valueVALUE, which can be used inCHECK:lines ๐ซ-D#<FMT>,<NUMVAR>=<NUMERIC EXPRESSION>โ sets aFileChecknumeric variableNUMVARof matching formatFMTto the result of evaluating<NUMERIC EXPRESSION>, which can be used inCHECK:lines ๐ขโจ see section FileCheck Numeric Variables and Expressions for details on the supported numeric expressions ๐-versionโ shows the version number of this program ๐ท๏ธ-vโ prints good directive pattern matches ๐ however, if-dump-input=failor-dump-input=alwaysis set, those matches get added as input annotations instead ๐๏ธ-vvโ prints info that's helpful for diagnosing internalFileCheckissues, like discarded overlappingCHECK-DAG:matches, implicit EOF pattern matches, andCHECK-NOT:patterns that don't have any matches ๐ต๏ธโโ๏ธ implies-v. however, if-dump-input=failor-dump-input=alwaysis set, that info just 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 provided for convenience while old tests get migrated to the new non-overlappingCHECK-DAG:implementation ๐--allow-emptyโ allows checking empty input. by default, empty input is rejected ๐ซ๐ซ--colorโ uses colors in the output ๐ (autodetected by default) ๐จ
In this case, we're making sure we get the expected code generation for both 32-bit and 64-bit targets, bestie ๐ ๐
๐ฌ The COM: directive ๐ฌ
Sometimes you want to switch off a FileCheck directive without deleting it entirely, or you want to write comments that name a directive out loud. 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 clock the commented X32: and X64: lines above as real directives ๐ญ And FileCheck diagnostics have been proposed that might yell about those X64 mentions that don't have the trailing :, because they look like directive typos. Dodging all of that is exhausting for a test author, and mangled syntax can make the point of the test code super unclear. COM: skips all of that drama โจ
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 it parses any other directive, so only the first directive on the line gets recognized.
RUN:gets the same treatment: For the sake of LIT, FileCheck treatsRUN:just likeCOM:. If that doesn't vibe with your test environment, check out--comment-prefixes.- Suffix combos are not it: 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). FileCheck treats that combo as plain text instead ๐ฅด 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. You can use CHECK: and CHECK-NEXT: to pull that off ๐ If you set a custom check prefix, just use <PREFIX>-NEXT: instead. 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, so don't put it at the top ๐ซ
๐ The CHECK-SAME: directive ๐
Sometimes you want to match lines and verify that a match happens on the same line as the previous match. Use CHECK: and CHECK-SAME: for that ๐ฆ With a custom check prefix, it's <PREFIX>-SAME:.
CHECK-SAME: is seriously powerful when you pair it with CHECK-NOT: (described 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 super useful for skipping matchers for stuff you don't care about. 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 checks foo has the value 1, you might first write this:
CHECK: Name: foo
CHECK: Value: 1{{$}}
Hot take: this would be a bad test ๐ If foo's value changes, the test would still pass, because theCHECK: Value: 1line would match the value from baz. You could addCHECK-NEXTmatchers for everyFieldN:line to fix it, but that's verbose and would need updating every time Field4 shows up. A more succinct way to write it, using theCHECK-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 absolutely nothing on it, not even whitespace, the CHECK-EMPTY: directive is your girl ๐ง
declare void @foo()
declare void @bar()
; CHECK: foo
; CHECK-EMPTY:
; CHECK-NEXT: bar
Just like CHECK-NEXT:, this directive will fail if there's more than one newline before it finds the next blank line. It also cannot be the first directive in a file.
๐ซ The CHECK-NOT: directive ๐ซ
The CHECK-NOT: directive is used to verify that a string doesn't show up 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, you can use 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 multiple lines with the same pattern over and over, you can just repeat a plain CHECK: as many times as you need. If that feels too boring, you can use a counted check instead: CHECK-COUNT-<num>:, where <num> is a positive decimal number ๐
It will match 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 ๐งฉ
If you need to match strings that don't show up 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. With 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, those 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 going from the definition of a variable to its use ๐ง It's 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, 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]
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 ๐ญ With 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. This non-overlapping behavior is consistent with other directives, and 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. That's true 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 bestie, so sometimes you've got a file full of tests split into logical blocks, and one or more CHECK: directives go "oh I got this!" and succeed by matching lines in a later block ๐ญ. An error usually shows up eventually, but the check it blames might have zero connection to the real problem. not the vibe ๐
โโ๏ธ
that's where CHECK-LABEL: comes in ๐. It works just like a normal CHECK directive, except FileCheck makes one extra assumption: a line matched by a 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 ๐. basically, a CHECK-LABEL: splits the input stream into separate blocks, and each block gets processed on its own, so a CHECK: in one block can't steal a line from another block ๐ง. and if --enable-var-scope is in effect, all local variables get wiped at the start 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:
the CHECK-LABEL: directives here make sure the three CHECK: directives only accept lines from the body of the @C_ctor_base function, even if the patterns match lines later in the file. the best part? if one of those three CHECK: directives fails, FileCheck just keeps going to the next block ๐
. so you can catch multiple test failures in a single invocation. literally so useful ๐ญโจ
there's no rule that CHECK-LABEL: strings have to match real syntactic labels in a source or output language ๐. they just need to uniquely match a single line in the file being verified.
โ ๏ธ CHECK-LABEL: directives cannot contain variable definitions or uses. no exceptions, bestie ๐
โจ Directive modifiers โจ
okay so you can slap a directive modifier onto a directive by following it with {<modifier>}, and the only supported value for <modifier> is LITERAL ๐
the LITERAL modifier does a literal match. it turns off any regex syntax, variable capture, or substitutions, which is super handy when the text you're matching would need a ton of escaping otherwise ๐ฆ. for example, these lines do literal matches instead of being treated as regexes:
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 stuff, fixed string matching is totally enough. but for the fancier stuff, you can write regexes wrapped in double braces: {{yourregex}}. FileCheck implements a POSIX regex matcher and supports Extended POSIX regular expressions (ERE) ๐ง . since fixed strings do most of the heavy lifting, FileCheck is built to mix and match them with regexes, so you can write things 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 ๐
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 need 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'd 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 verify it shows up again later in the file ๐. for codegen tests, this lets you allow any register but still check that the same register gets used consistently later. that's what string substitution blocks are for: you can define string variables and substitute them into patterns ๐ฅ. here's a simple one:
; CHECK: test5:
; CHECK: notw [[REGISTER:%[a-z]+]]
; CHECK: andw {{.*}}[[REGISTER]]
the first check matches the regex %[a-z]+ and captures it into the string variable REGISTER. the second line verifies that whatever's in REGISTER shows up later in the file after an "andw" ๐
. string substitution blocks are always wrapped in [[ ]] pairs, and 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 โจ
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 the operands of op to be the same register and don't care exactly which one 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 has numeric substitution blocks ๐ข. you can define numeric variables and check for numeric values that satisfy a numeric expression constraint based on those variables. this lets CHECK: directives verify a numeric relation between two numbers, like needing consecutive registers to be used ๐
to capture a numeric value, the syntax is [[#%<fmtspec>,<NUMVAR>:]] where:
%<fmtspec>,โ an optional format specifier that says what number format to match, plus the minimum number of digits to expect.<NUMVAR>:โ an optional definition of the variable<NUMVAR>from the captured value.
the syntax of <fmtspec> is #.<precision><conversion specifier> where:
#โ an optional flag for hex values (see<conversion specifier>below) that requires the matched value to be prefixed by0x..<precision>โ 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>โ an optional scanf-style conversion specifier that says what number format to match (e.g. hex). right now the accepted ones are%u,%d,%xand%X. if it's absent, it 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. but 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 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>โ the same format specifier you'd use when defining a variable, but here it's about how a numeric expression's value should be matched against. if it's absent, both components get inferred from the matching format of whatever numeric variable(s) the expression constraint uses. if no numeric variable is used, it defaults to%u, meaning unsigned with no leading zeros. if several numeric variables conflict on their 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 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>โ an expression. it's 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:
<name>โ 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>โ 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
๐ So it fails bestie because 7 is unequal to 5 + 1, and a0463443 is unequal to a0463440 + 7.
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 gets 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. This is lowkey the best way to make a testcase self-describing, because you 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]]]
That would match:
mov r4, 0xC
load r6, [r5, r4]
The --enable-var-scope option does the same thing to numeric variables that it does to string variables ๐ฆ
๐ Important note: in its current implementation, an expression cannot use a numeric variable defined earlier in the same CHECK directive. Not it, not allowed, don't try it ๐ญ
๐ธ FileCheck Pseudo Numeric Variables ๐ธ
Okay so sometimes you need to verify output that includes line numbers from the match file, like when you're testing compiler diagnostics. This gets a little fragile, because 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. Literally so annoying ๐
To fix this, FileCheck expressions understand 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
Also, for legacy code that treats @LINE as a special string variable, FileCheck still accepts these forms with the string substitution block syntax: [[@LINE]], [[@LINE+<offset>]] and [[@LINE-<offset>]]. There must be no spaces inside the brackets, and offset has to be an integer ๐
๐ฆ Matching Newline Characters ๐ฆ
To match newline characters in regular expressions, you can 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")
That lets us set the FileCheck variable DLOC to the value 0x00000233, pulled from the line right before "intd" ๐
โจ AUTHOR โจ
Maintained by the LLVM Team (https://llvm.org/) ๐ซถ
๐ COPYRIGHT ๐
2003-2025, LLVM Project ๐
And that's the whole FILECHECK(1) page, bestie ๐ Version 20, last updated 2025-09-03, and it's giving main character energy the whole way through ๐ฅ๐
๐ฆ where this page comes from
- fedora 43: llvm20 20.1.8-2.fc43 ยท Apache-2.0 WITH LLVM-exception OR NCSA
- fedora 43: llvm20 20.1.8-2.fc43 ยท Apache-2.0 WITH LLVM-exception OR NCSA
- fedora 44: llvm20 20.1.8-2.fc44 ยท Apache-2.0 WITH LLVM-exception OR NCSA
- fedora 44: llvm20 20.1.8-2.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