FILECHECK(1)

๐Ÿ“ฆ
version 11.1.0 ยท 2 versions
, in fedora 43, fedora 44

๐ŸŽ€ FILECHECK(1) ๐ŸŽ€

Okay bestie, this is the FILECHECK(1) page from the LLVM project ๐ŸŒธ The manual name is FileCheck, and it's about to get very good. Let's go โœจ

โœจ 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 comes from standard input and one you pass on the command line, and it uses one to verify the other. This is literally the move for the testsuite ๐Ÿ”ฅ, since it wants to confirm that the output of some tool (like llc) has the info you expect, like a movsd from esp or whatever is giving main character energy. It's kinda like grep, but it's built for matching multiple 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 โœจ

Okay, the options can come from the environment variable FILECHECK_OPTS and from the command line, so you've got two places to hide your settings ๐Ÿ’œ

  • -help โ€” Prints a summary of the command line options ๐ŸŒธ
  • --check-prefix prefix โ€” FileCheck goes hunting through match-filename for patterns, and by default they're prefixed with "CHECK:". If you want a different prefix (maybe the same input file is checking multiple different tools or options), this is your girl. Pass it without the trailing ":", and you can give it one or more prefixes to match. Multiple prefixes are super useful for tests that change between run options while most lines stay the same ๐Ÿงš

FileCheck does not permit duplicate prefixes, even if one is a check prefix and one is a comment prefix (see --comment-prefixes below). No copycats allowed ๐Ÿ™…โ€โ™€๏ธ

  • --check-prefixes prefix1,prefix2,... โ€” An alias of --check-prefix that lets you list multiple prefixes as a comma separated list. Same energy, just more prefixes in one go โœจ
  • --comment-prefixes prefix1,prefix2,... โ€” By default, FileCheck ignores any occurrence in match-filename of any check prefix if it's preceded on the same line by "COM:" or "RUN:". See the section The "COM:" directive for usage details ๐Ÿ’ญ

You can override these default comment prefixes with --comment-prefixes if they don't fit your testing environment. Honestly though, doing that is not recommended in LLVM's LIT-based test suites. Those should be easier to maintain when everyone follows a consistent comment style. If the defaults aren't working for you, consider proposing a change to the default comment prefixes instead ๐Ÿซ 

  • --input-file filename โ€” The file to check. Defaults to stdin ๐Ÿ“ฅ
  • --match-full-lines โ€” By default, FileCheck allows matches anywhere on a line. This option requires all positive matches to cover an entire line. Leading and trailing whitespace is ignored, unless --strict-whitespace is also specified. (Note: negative matches from CHECK-NOT are not affected by this option!) ๐Ÿ™ˆ

Passing this option is equivalent to inserting {{^ *}} or {{^}} before, and {{ *$}} or {{$}} after, every positive check pattern.

  • --strict-whitespace โ€” By default, FileCheck canonicalizes input horizontal whitespace (spaces and tabs), so it ignores those differences. A space will match a tab, which is lowkey iconic. This flag turns that behavior off. End-of-line sequences are canonicalized to UNIX-style \n in all modes, no matter what ๐Ÿ“
  • --ignore-case โ€” By default, FileCheck uses case-sensitive matching. This option makes it use case-insensitive matching instead ๐ŸŒˆ
  • --implicit-check-not check-pattern โ€” Adds implicit negative checks for the specified patterns between positive checks. This lets you write stricter tests without stuffing them full of CHECK-NOTs. Ate and left no crumbs ๐Ÿ’…

For example, --implicit-check-not warning: can be super useful when you're testing diagnostic messages from tools that don't have an option similar to clang -verify. With this option, FileCheck verifies that the input doesn't contain any warnings that aren't covered by a CHECK: pattern ๐Ÿ‘‘

  • --dump-input <value> โ€” Dumps the input to stderr, adding annotations that represent the currently enabled diagnostics. If you use this option multiple times, the <value> that appears earliest in the list below wins. The default is fail ๐Ÿ”
    • 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, prints <N> input lines before and <N> input lines after any lines specified by --dump-input-filter. If you use this option multiple times, the largest specified <N> takes precedence. The default is 5 ๐Ÿง
  • --dump-input-filter <value> โ€” In the dump requested by --dump-input, prints only the input lines of kind <value>, plus any context specified by --dump-input-context. If you use this option multiple times, the <value> that appears earliest in the list below has precedence. 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
  • --enable-var-scope โ€” Enables scope for regex variables ๐Ÿฆ‹

Variables with names that start with $ are considered global and stay set throughout the whole file. All other variables get undefined after each CHECK-LABEL they run into ๐Ÿงš

  • -D<VAR=VALUE> โ€” Sets a FileCheck pattern variable VAR with the value VALUE, which you can then use in CHECK: lines ๐ŸŽ€
  • -D#<FMT>,<NUMVAR>=<NUMERIC EXPRESSION> โ€” Sets a FileCheck numeric variable NUMVAR of matching format FMT to the result of evaluating <NUMERIC EXPRESSION>, which you can use in CHECK: lines. See the 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=fail or -dump-input=always is set, it adds those matches as input annotations instead ๐Ÿ‘€
  • -vv โ€” Prints information that helps diagnose internal FileCheck issues, like discarded overlapping CHECK-DAG: matches, implicit EOF pattern matches, and CHECK-NOT: patterns that don't have any matches. Implies -v. However, if -dump-input=fail or -dump-input=always is set, it just adds that information as input annotations instead ๐Ÿ•ต๏ธโ€โ™€๏ธ
  • --allow-deprecated-dag-overlap โ€” Enables overlapping among matches in a group of consecutive CHECK-DAG: directives.
Heads up bestie, this one is deprecated! It's only here for convenience while old tests get migrated to the new non-overlapping CHECK-DAG: implementation ๐Ÿšจ
  • --color โ€” Uses colors in the output. It's autodetected by default ๐ŸŒˆ
; 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 mistake the commented-out X32: and X64: bits for real directives ๐Ÿ˜ญ. There have also been proposals for FileCheck diagnostics that might yell at those X64 mentions lacking the trailing :, since they look like directive typos. Dodging all of that is tedious for the test author, and mangling directive syntax can make the purpose of the test code super unclear. COM: avoids all these problems ๐Ÿซถ

A few important usage notes, bestie ๐Ÿ’…:

  • COM: 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 as any other directive, so only the first directive on the line gets recognized ๐Ÿงš
  • For the sake of LIT, FileCheck treats RUN: just like COM:. If that's not suitable for your test environment, see --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, such as -NEXT: or -NOT: (we'll get to those below). Instead, FileCheck treats that combo as plain text ๐Ÿ’€. 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 want to match lines and verify that the matches happen on exactly consecutive lines, with no other lines in between. That's where CHECK: and CHECK-NEXT: come in, bestie ๐Ÿ’– If you specified a custom check prefix, just use <PREFIX>-NEXT:. Here's an example that 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 are picky ๐Ÿ™„ They reject the input unless there is exactly one newline between them and the previous directive. And a CHECK-NEXT: 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. For that, use CHECK: and CHECK-SAME: ๐ŸŽ€ If you specified a custom check prefix, just use <PREFIX>-SAME:.

CHECK-SAME: is seriously powerful when you pair it with CHECK-NOT: (also coming up below) ๐Ÿ”ฅ For example, this one 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. And yep, a CHECK-SAME: cannot be the first directive in a file either ๐Ÿฅบ


๐Ÿงš 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 bestie ๐Ÿ’œ

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. And it cannot be the first directive in a file.


๐Ÿ™ˆ The "CHECK-NOT:" directive

The CHECK-NOT: directive is used to verify that a string does not occur between two matches (or before the first match, or after the last match) ๐Ÿ‘€ For example, if you want to verify that a load gets removed by a transformation, 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 multiple lines with the same pattern over and over again, 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 matches 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 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 in with CHECK-DAG: directives to exclude strings between the surrounding CHECK-DAG: directives. As a result, those surrounding CHECK-DAG: directives can't be reordered. In other words, all occurrences matching a CHECK-DAG: before the CHECK-NOT: must not fall behind occurrences matching a CHECK-DAG: after the 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 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, 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, bestie ๐Ÿ˜ญ In the case of a register sequence, 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, 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

Sometimes you've got a file with multiple tests divided into logical blocks, and one or more CHECK: directives may accidentally succeed by matching lines in a later block ๐Ÿ˜ต An error will usually get generated eventually, but the check flagged as causing it may not actually have anything to do with the real source of the problem.

To get better error messages in these cases, use the CHECK-LABEL: directive ๐Ÿ’… It's treated identically to a normal CHECK directive, except FileCheck makes an extra assumption: a line matched by the directive cannot also be matched by any other check present in match-filename. This is meant for lines containing labels or other unique identifiers ๐Ÿท๏ธ Conceptually, a CHECK-LABEL divides the input stream into separate blocks, each processed independently, which stops a CHECK: in one block from matching a line in another block. 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:

The use of CHECK-LABEL: here is what keeps those three CHECK: directives in line ๐Ÿซถ they only accept lines from the body of the @C_ctor_base function, even if their patterns also match lines way later in the file ๐Ÿ‘€. And if one of the three CHECK: directives fails, FileCheck doesn't give up. It recovers by moving on to the next block, so you can catch multiple test failures in one invocation ๐Ÿ’…

No rule says CHECK-LABEL: has to contain strings that match real syntactic labels in a source or output language ๐Ÿ™ˆ It just has to uniquely match a single line in the file being verified. That's the whole vibe โœจ

๐Ÿšซ Heads up: CHECK-LABEL: directives cannot contain variable definitions or uses.

โœจ FileCheck Regex Matching Syntax

Every FileCheck directive takes a pattern to match ๐ŸŽ€ For most things, plain fixed string matching is perfectly sufficient. For the times you need something more flexible, you can write a regular expression inside double braces, like {{yourregex}}. FileCheck implements a POSIX regular expression matcher and supports Extended POSIX regular expressions (ERE). Since fixed string matching is what we use most of the time, FileCheck is built to mix and match it 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 ๐Ÿฆ‹

Regexes live inside double braces, so they stand out visually, and you don't need escape characters inside them the way you would in C ๐Ÿ’– The rare time you want to match double braces literally from the input, you can use something ugly like {{[}][}]}} as your pattern ๐Ÿ™ˆ And if you're using the repetition count syntax, like [[:xdigit:]]{8} to match exactly 8 hex digits, wrap it in parentheses like {{([[:xdigit:]]{8})}} so it doesn't get confused with FileCheck's closing double-brace ๐Ÿซถ

โœจ FileCheck String Substitution Blocks

It's super useful to match a pattern and then check that it shows up again later in the file ๐Ÿ‘‘ For codegen tests, this lets you allow any register but verify that the same register is used consistently later. That's what string substitution blocks are for. FileCheck lets 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 ๐Ÿ”ฅ 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. Otherwise, it's a substitution โœจ

FileCheck variables can be defined multiple times, and substitutions always grab the latest value ๐Ÿ’… Variables can also be substituted later on the same line they were 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 with names starting 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 ๐Ÿ”ข You can define numeric variables and check for numeric values that satisfy a numeric expression constraint based on those variables, using a numeric substitution. This lets CHECK: directives verify a numeric relationship between two numbers, like making sure consecutive registers are used โญ

The syntax to define a numeric variable is [[#%<fmtspec>,<NUMVAR>:]], where:

  • %<fmtspec> is an optional scanf-style matching format specifier that tells FileCheck what number format to match, like a hex number ๐ŸŒธ Right now the accepted format specifiers are %u, %d, %x and %X. If it's left out, the format specifier defaults to %u.
  • <NUMVAR> is the name of the numeric variable that gets set to the matching value ๐Ÿ’œ

For example:

; CHECK: mov r[[#REG:]], 0x[[#%X,IMM:]]

would match mov r5, 0xF0F0 and set REG to the value 5 and IMM to the value 0xF0F0 ๐ŸŽ€

The syntax for a numeric substitution is [[#%<fmtspec>: <constraint> <expr>]], where:

  • %<fmtspec> is the same matching format specifier you use when defining numeric variables, but here it acts as a printf-style format showing how a numeric expression value should be matched. If it's left out, the format specifier gets inferred from the matching format of the numeric variable(s) the expression constraint uses, if any. If no numeric variable is used, it defaults to %u. If several numeric variables have conflicting matching formats, the format specifier is mandatory ๐Ÿ™ˆ
  • <constraint> describes how the value to match has to 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 can 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:

  • name is 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 would not match this text:

load r5, [r0]
load r7, [r1]
Loading from 0xa0463440 to 0xa0463443

Why? Because 7 is unequal to 5 + 1, and a0463443 is unequal to a0463440 + 7 ๐Ÿ˜ญ

The syntax also supports an empty expression, which is equivalent to writing {{[0-9]+}}. Use it when the input must contain a numeric value but the value itself doesn't matter ๐Ÿ“

; CHECK-NOT: mov r0, r[[#]]

This checks that a value is synthesized rather than moved around ๐Ÿงš

A numeric variable can also be defined as the result of a numeric expression. In that case, the numeric expression constraint is checked, and if it's verified, the variable gets assigned that value. The unified syntax for defining numeric variables and checking a numeric expression is [[#%<fmtspec>,<NUMVAR>: <constraint> <expr>]], with each element described above. You can use this to make a testcase more self-describing by using variables instead of 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.

โœจ 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 catch is that this makes the match file fragile, because CHECK: lines contain absolute line numbers in the same file, and those have to be updated whenever line numbers change because of text being added or deleted ๐Ÿ˜ฉ

To make this easier, FileCheck expressions understand the @LINE pseudo numeric variable, which evaluates to the line number of the CHECK pattern where it's found ๐ŸŒธ That means your match patterns can sit 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 legacy uses of @LINE as a special string variable, FileCheck also accepts these forms with string substitution block syntax: [[@LINE]], [[@LINE+<offset>]] and [[@LINE-<offset>]]. They have no spaces inside the brackets, and offset is 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")

This lets us set the FileCheck variable DLOC to the desired value 0x00000233, extracted from the line immediately preceding "intd" ๐ŸŽ€


โœจ AUTHOR โœจ

Maintained by the LLVM Team (https://llvm.org/) ๐Ÿ’œ

2003-2024, LLVM Project ๐ŸŒˆ

Okay bestie, that's the whole page ๐Ÿซถ Footer says FILECHECK(1), version 11, dated 2024-07-18. Go slay your tests! ๐Ÿ’…โœจ

๐Ÿ“ฆ where this page comes from