FileCheck - 柔軟なパターンマッチングファイル検証ツール

概要

FileCheck match-filename [–check-prefix=XXX] [–strict-whitespace]

説明

FileCheck は2つのファイル(1つは標準入力から、もう1つはコマンドラインで指定されたもの)を読み込み、一方を使用してもう一方を検証します。 この動作は、いくつかのツール(例えば、llc)の出力が期待される情報(例えば、espからのmovsdやその他興味深いもの)を含んでいることを検証したいテストスイートにとって特に便利です。 これはgrepを使用するのと似ていますが、1つのファイル内の複数の異なる入力を特定の順序で照合することに最適化されています。

match-filename ファイルは、照合するパターンを含むファイルを指定します。検証するファイルは、--input-file オプションが使用されない限り、標準入力から読み込まれます。

オプション

オプションは環境変数 FILECHECK_OPTS とコマンドラインから解析されます。

-help

コマンドラインオプションの概要を表示します。

--check-prefix prefix

FileCheck は、match-filename の内容を検索して、一致するパターンを探します。 デフォルトでは、これらのパターンには「CHECK:」というプレフィックスが付いています。 別のプレフィックスを使用したい場合(例えば、同じ入力ファイルが複数の異なるツールまたはオプションをチェックしているため)、--check-prefix 引数を使用すると、(末尾の「:」なしで)一致させる1つ以上のプレフィックスを指定できます。 複数のプレフィックスは、実行オプションによって変更される可能性があるが、ほとんどの行は同じままであるテストに役立ちます。

FileCheck は、チェックプレフィックスとコメントプレフィックス(下記の --comment-prefixes を参照)のどちらであっても、重複したプレフィックスを許可しません。

--check-prefixes prefix1,prefix2,...

複数のプレフィックスをカンマ区切りリストとして指定できる --check-prefix のエイリアスです。

--comment-prefixes prefix1,prefix2,...

デフォルトでは、FileCheck は、match-filename 内のチェックプレフィックスの出現を、同じ行で「COM:」または「RUN:」が前に付いている場合は無視します。 使用方法の詳細は、「COM:」ディレクティブのセクションを参照してください。

これらのデフォルトのコメントプレフィックスは、テスト環境に適切でない場合は、--comment-prefixes によってオーバーライドできます。 ただし、LLVMのLITベースのテストスイートでは、すべてが一貫したコメントスタイルに従っている場合、保守が容易になるため、お勧めしません。 その場合は、代わりにデフォルトのコメントプレフィックスの変更を提案することを検討してください。

--allow-unused-prefixes

このオプションは、--check-prefix または --check-prefixes で指定された複数のプレフィックスを使用し、これらのプレフィックスの一部がテストファイルにない場合の動作を制御します。 trueの場合、これは許可されます。falseの場合、FileCheck はエラーを報告し、見つからないプレフィックスを一覧表示します。 デフォルト値はfalseです。

--input-file filename

チェックするファイル(デフォルトはstdin)。

--match-full-lines

デフォルトでは、FileCheck は行のどこでも一致を許可します。 このオプションは、すべての一致が 行全体をカバーすることを要求します。 --strict-whitespace も指定されていない限り、先頭と末尾の空白は無視されます。 (注:CHECK-NOT からの負の一致はこのオプションの影響を受けません!)

このオプションを渡すことは、すべての正のチェックパターンの前後に {{^ *}} または {{^}} を挿入し、{{ *$}} または {{$}} を挿入することと同じです。

--strict-whitespace

デフォルトでは、FileCheck は入力の水平方向の空白(スペースとタブ)を正規化するため、これらの違いを無視します(スペースはタブと一致します)。 --strict-whitespace 引数は、この動作を無効にします。 行末シーケンスは、すべてのモードでUNIXスタイルの \n に正規化されます。

--ignore-case

デフォルトでは、FileCheckは大文字と小文字を区別するマッチングを使用します。このオプションを指定すると、FileCheckは大文字と小文字を区別しないマッチングを使用します。

--implicit-check-not check-pattern

肯定的なチェックの間に、指定されたパターンの暗黙的な否定チェックを追加します。このオプションを使用すると、CHECK-NOT を使用せずに、より厳密なテストを作成できます。

たとえば、「--implicit-check-not warning:」は、clang -verify と同様のオプションを持たないツールからの診断メッセージをテストする場合に役立ちます。このオプションを使用すると、FileCheck は、入力が CHECK: パターンでカバーされていない警告を含んでいないことを検証します。

--dump-input <value>

入力を stderr にダンプし、現在有効になっている診断を表す注釈を追加します。 このオプションが複数回出現する場合、以下のリストで最も早く出現する <value> が優先されます。 デフォルトは fail です。

  • help - 入力ダンプの説明と終了

  • always - 常にダンプ入力

  • fail - 失敗時にダンプ入力

  • never - 入力しない

--dump-input-context <N>

--dump-input でリクエストされたダンプでは、--dump-input-filter で指定された行の前後に <N> 入力行を出力します。 このオプションが複数回出現する場合、指定された最大の <N> が優先されます。 デフォルトは5です。

--dump-input-filter <value>

--dump-input でリクエストされたダンプでは、<value> 種類の入力行と --dump-input-context で指定されたコンテキストのみを出力します。 このオプションが複数回出現する場合、以下のリストで最も早く出現する <value> が優先されます。 デフォルトは、--dump-input=fail の場合は error で、--dump-input=always の場合は all です。

  • all - すべての入力行

  • annotation-full - 注釈付きの入力行

  • annotation - 注釈の開始点を含む入力行

  • error - エラー注釈の開始点を含む入力行

--enable-var-scope

正規表現変数のスコープを有効にします。

$ で始まる名前の変数はグローバルと見なされ、ファイル全体で設定されたままになります。

その他のすべての変数は、CHECK-LABEL が検出されるたびに未定義になります。

-D<VAR=VALUE>

FileCheckパターン変数 VAR を値 VALUE で設定します。これは CHECK: 行で使用できます。

-D#<FMT>,<NUMVAR>=<NUMERIC EXPRESSION>

一致するフォーマット FMT のFileCheck数値変数 NUMVAR を、<NUMERIC EXPRESSION> の評価結果に設定します。これは CHECK: 行で使用できます。サポートされている数値式については、「FileCheck 数値変数と式」セクションを参照してください。

-version

このプログラムのバージョン番号を表示します。

-v

有効なディレクティブパターンの一致を出力します。ただし、-dump-input=fail または -dump-input=always の場合は、それらの一致を入力アノテーションとして追加します。

-vv

破棄された重複する CHECK-DAG: 一致、暗黙的なEOFパターン一致、一致しない CHECK-NOT: パターンなど、FileCheckの内部的な問題の診断に役立つ情報を出力します。-v を暗示します。ただし、-dump-input=fail または -dump-input=always の場合は、その情報を単に入力アノテーションとして追加します。

--allow-deprecated-dag-overlap

連続する CHECK-DAG: ディレクティブのグループ内での一致の重複を有効にします。このオプションは非推奨であり、古いテストを重複しない新しい CHECK-DAG: 実装に移行するための便宜上のみ提供されています。

--allow-empty

空の入力のチェックを許可します。デフォルトでは、空の入力は拒否されます。

--color

出力に色を使用します(デフォルトでは自動検出)。

終了ステータス

FileCheck がファイルが予期される内容と一致することを確認した場合、0 で終了します。そうでない場合、またはエラーが発生した場合は、ゼロ以外の値で終了します。

チュートリアル

FileCheck は通常、LLVM 回帰テストから使用され、テストの RUN 行で呼び出されます。RUN 行から FileCheck を使用する簡単な例を以下に示します。

; RUN: llvm-as < %s | llc -march=x86-64 | FileCheck %s

この構文は、現在のファイル(”%s”)を llvm-as にパイプし、それを llc にパイプし、llc の出力を FileCheck にパイプすることを示しています。つまり、FileCheck は標準入力(llc の出力)を指定されたファイル名引数(”%s” で指定された元の .ll ファイル)と照合します。これがどのように機能するかを確認するために、.ll ファイルの残りの部分(RUN 行の後)を見てみましょう。

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
}

ここでは、コメントで指定された「CHECK:」行が表示されます。これで、ファイルが llvm-as にパイプされ、次に llc にパイプされ、マシンコード出力が検証対象であることがわかります。FileCheck はマシンコード出力をチェックして、「CHECK:」行で指定された内容と一致することを確認します。

CHECK:」行の構文は非常にシンプルです。順番に発生する必要がある固定文字列です。FileCheck はデフォルトで水平方向の空白の違いを無視しますが(たとえば、スペースはタブと一致することが許されます)、それ以外の場合、「CHECK:」行の内容はテストファイル内の何かと正確に一致する必要があります。

FileCheck の優れた点の 1 つ(grep と比較して)は、テストケースを論理グループにまとめることができることです。たとえば、上記のテストは「sub1:」ラベルと「inc4:」ラベルをチェックしているため、これらのラベルの間に「subl」がない限り一致しません。ファイルの他の場所に存在する場合でも、それはカウントされません。「grep subl」は、「subl」がファイル内のどこかに存在する場合に一致します。

FileCheck -check-prefix オプション

FileCheck -check-prefix オプションを使用すると、1 つの .ll ファイルから複数のテスト構成を駆動できます。これは、llc で異なるアーキテクチャバリアントをテストする場合など、多くの状況で役立ちます。簡単な例を以下に示します。

; 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
}

この場合、32 ビットと 64 ビットの両方のコード生成で予期されるコード生成が得られるかどうかをテストしています。

「COM:」ディレクティブ

FileCheck ディレクティブを完全に削除せずに無効にしたり、ディレクティブに名前で言及するコメントを記述したりすることがあります。「COM:」ディレクティブを使用すると、これが簡単になります。たとえば、次のようなものがあります。

; 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

COM:」がないと、FileCheck が上記のコメントに含まれる「X32:」と「X64:」をディレクティブとして認識しないようにするために、言い換えとディレクティブ構文の変更を組み合わせる必要があります。さらに、末尾に「:」が付いていない上記の「X64」はディレクティブのタイプミスのように見えるため、FileCheck 診断で警告が表示される可能性があります。 これらの問題をすべて回避することは、テスト作成者にとって面倒な場合があり、ディレクティブ構文の変更によってテストコードの目的が不明瞭になる可能性があります。「COM:」はこれらの問題をすべて回避します。

いくつかの重要な使用上の注意

  • 別のディレクティブのパターン内にある「COM:」は、パターンの残りの部分をコメントアウト*しません*。例:

    ; X32: pinsrd $1, 4(%esp), %xmm0 COM: This is part of the X32 pattern!
    

    ディレクティブのパターンの一部を一時的にコメントアウトする必要がある場合は、別の行に移動してください。理由は、FileCheck が他のディレクティブと同じ方法で「COM:」を解析するためです。行の最初のディレクティブのみがディレクティブとして認識されます。

  • LIT のため、FileCheck は「RUN:」を「COM:」と同様に扱います。これがテスト環境に適していない場合は、--comment-prefixes を参照してください。

  • FileCheck は、以下で説明する「-NEXT:」や「-NOT:」などの通常のチェックディレクティブサフィックスと組み合わせられている場合、「COM」、「RUN」、またはユーザー定義のコメントプレフィックスをコメントディレクティブとして認識しません。FileCheck は、そのような組み合わせをプレーンテキストとして扱います。テスト環境でコメントディレクティブとして機能する必要がある場合は、--comment-prefixes を使用して定義します。

「CHECK-NEXT:」ディレクティブ

行を一致させ、一致が正確に連続した行で発生し、その間に他の行がないことを確認したい場合があります。この場合、「CHECK:」と「CHECK-NEXT:」ディレクティブを使用してこれを指定できます。カスタムチェックプレフィックスを指定した場合は、「<PREFIX>-NEXT:」を使用してください。たとえば、次のようなものが期待どおりに機能します。

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:」ディレクティブは、前のディレクティブとの間に改行がちょうど1つない限り、入力を拒否します。「CHECK-NEXT:」は、ファイルの最初のディレクティブにすることはできません。

「CHECK-SAME:」ディレクティブ

行をマッチさせたい場合、以前のマッチと同じ行でマッチが発生することを確認したい場合があります。この場合、「CHECK:」と「CHECK-SAME:」ディレクティブを使用してこれを指定できます。カスタムチェックプレフィックスを指定した場合は、「<PREFIX>-SAME:」を使用してください。

CHECK-SAME:」は、特に「CHECK-NOT:」(後述)と組み合わせて強力です。

たとえば、以下は期待どおりに動作します

!0 = !DILocation(line: 5, scope: !1, inlinedAt: !2)

; CHECK:       !DILocation(line: 5,
; CHECK-NOT:               column:
; CHECK-SAME:              scope: ![[SCOPE:[0-9]+]]

CHECK-SAME:」ディレクティブは、それ以前のディレクティブとの間に改行がある場合、入力を拒否します。

CHECK-SAME:」は、無関係なフィールドのマッチャーを書くことを避けるためにも役立ちます。たとえば、次のような出力を生成するツールを解析するテストを書いているとします

Name: foo
Field1: ...
Field2: ...
Field3: ...
Value: 1

Name: bar
Field1: ...
Field2: ...
Field3: ...
Value: 2

Name: baz
Field1: ...
Field2: ...
Field3: ...
Value: 1

fooの値が1であることを検証するテストを書くには、まず次のように書くかもしれません

CHECK: Name: foo
CHECK: Value: 1{{$}}

しかし、これは悪いテストです。fooの値が変更されても、「CHECK: Value: 1」行はbazの値と一致するため、テストは成功してしまいます。これを修正するには、すべてのFieldN:行にCHECK-NEXTマッチャーを追加できますが、これは冗長であり、Field4が追加されたときに更新する必要があります。「CHECK-SAME:」マッチャーを使用してテストをより簡潔に記述する方法は次のとおりです

CHECK:      Name: foo
CHECK:      Value:
CHECK-SAME:        {{ 1$}}

これは、出力に「Value:」が*次に*現れたときに、値が1であることを検証します。

注:「CHECK-SAME:」はファイルの最初のディレクティブにすることはできません。

「CHECK-EMPTY:」ディレクティブ

次の行に何もないこと、空白もないことを確認する必要がある場合は、「CHECK-EMPTY:」ディレクティブを使用できます。

declare void @foo()

declare void @bar()
; CHECK: foo
; CHECK-EMPTY:
; CHECK-NEXT: bar

CHECK-NEXT:」と同様に、次の空白行が見つかる前に複数の改行がある場合、このディレクティブは失敗し、ファイルの最初のディレクティブにすることはできません。

「CHECK-NOT:」ディレクティブ

CHECK-NOT:」ディレクティブは、2つのマッチの間(または最初のマッチの前、または最後のマッチの後)に文字列が出現しないことを検証するために使用されます。たとえば、変換によってロードが削除されたことを検証するには、次のようなテストを使用できます

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
}

「CHECK-COUNT:」ディレクティブ

同じパターンで複数の行を何度もマッチさせる必要がある場合は、プレーンなCHECK:を必要な回数だけ繰り返すことができます。それが退屈に見える場合は、代わりにカウントされたチェック「CHECK-COUNT-<num>:」を使用できます。ここで、<num>は正の10進数です。これはパターンと正確に<num>回一致し、それ以上でもそれ以下でもありません。カスタムチェックプレフィックスを指定した場合は、同じ効果を得るために「<PREFIX>-COUNT-<num>:」を使用してください。簡単な例を次に示します

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]+}}

「CHECK-DAG:」ディレクティブ

厳密に順次発生しない文字列を一致させる必要がある場合は、「CHECK-DAG:」を使用して、2つのマッチの間(または最初のマッチの前、または最後のマッチの後)でそれらを検証できます。たとえば、clangはvtableグローバルを逆順に出力します。CHECK-DAG:を使用すると、チェックを自然な順序で維持できます

// 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:ディレクティブは、CHECK-DAG:ディレクティブと組み合わせて、周囲のCHECK-DAG:ディレクティブ間の文字列を除外できます。その結果、周囲のCHECK-DAG:ディレクティブは並べ替えることができません。つまり、CHECK-NOT:の前にCHECK-DAG:と一致するすべての出現は、CHECK-NOT:の後にCHECK-DAG:と一致する出現の後ろに落ちてはなりません。たとえば、

; CHECK-DAG: BEFORE
; CHECK-NOT: NOT
; CHECK-DAG: AFTER

この場合、BEFOREAFTERの後に発生する入力文字列は拒否されます。

キャプチャされた変数を使用すると、CHECK-DAG:は、変数の定義からその使用へのエッジを持つDAGの有効なトポロジカル順序と一致させることができます。これは、たとえば、テストケースが命令スケジューラからの異なる出力シーケンスと一致する必要がある場合に役立ちます。たとえば、

; CHECK-DAG: add [[REG1:r[0-9]+]], r1, r2
; CHECK-DAG: add [[REG2:r[0-9]+]], r3, r4
; CHECK:     mul r5, [[REG1]], [[REG2]]

この場合、2つのadd命令の任意の順序が許可されます。

同じCHECK-DAG:ブロック内で変数を定義*し*使用している場合は、定義ルールがその使用の*後*に一致する可能性があることに注意してください。

したがって、たとえば、以下のコードはパスします

; CHECK-DAG: vmov.32 [[REG2:d[0-9]+]][0]
; CHECK-DAG: vmov.32 [[REG2]][1]
vmov.32 d0[1]
vmov.32 d0[0]

一方、この他のコードはパスしません

; CHECK-DAG: vmov.32 [[REG2:d[0-9]+]][0]
; CHECK-DAG: vmov.32 [[REG2]][1]
vmov.32 d1[1]
vmov.32 d0[0]

これは非常に便利ですが、危険でもあります。レジスタシーケンスの場合、厳密な順序(書き込み前の読み取り、使用前のコピーなど)が必要となるためです。テストで探している定義が(コンパイラのバグのために)一致しない場合、使用からさらに離れた場所で一致し、実際のバグを隠してしまう可能性があります。

このような場合は、順序を強制するために、DAGブロックの間に非DAGディレクティブを使用します。

CHECK-DAG:ディレクティブは、同じCHECK-DAG:ブロック内の先行するCHECK-DAG:ディレクティブのマッチと重複するマッチをスキップします。この重複しない動作は他のディレクティブと一致するだけでなく、一意でない文字列またはパターンのセットを処理するためにも必要です。たとえば、次のディレクティブは、OpenMPランタイムなどの並列プログラムにおける2つのタスクの順序付けられていないログエントリを探します

// 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

2番目のディレクティブのペアは、パターンが同一であっても、スレッドIDが再利用されたためにログエントリのテキストが同一であっても、最初のペアと同じログエントリと一致しないことが保証されます。

「CHECK-LABEL:」ディレクティブ

論理ブロックに分割された複数のテストを含むファイルでは、1つ以上のCHECK:ディレクティブが、後のブロックの行と一致することによって誤って成功する場合があります。通常は最終的にエラーが生成されますが、エラーの原因としてフラグが立てられたチェックは、実際の問題のソースとは関係がない場合があります。

このような場合により良いエラーメッセージを生成するために、「CHECK-LABEL:」ディレクティブを使用できます。これは通常のCHECKディレクティブと同様に扱われますが、FileCheckは、ディレクティブと一致する行がmatch-filenameに存在する他のチェックとも一致することはできないという追加の仮定を行います。これは、ラベルまたはその他の固有の識別子を含む行に使用することを目的としています。概念的には、CHECK-LABELが存在することで入力ストリームが個別のブロックに分割され、各ブロックは独立して処理されるため、1つのブロックのCHECK:ディレクティブが別のブロックの行と一致することがなくなります。--enable-var-scopeが有効な場合、すべてのローカル変数はブロックの先頭でクリアされます。

たとえば、

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:

この場合、CHECK-LABEL:ディレクティブを使用することで、3つのCHECK:ディレクティブは、パターンがファイルの後半で見つかった行と一致する場合でも、@C_ctor_base関数の本体に対応する行のみを受け入れることが保証されます。さらに、これら3つのCHECK:ディレクティブのいずれかが失敗した場合、FileCheckは次のブロックに進むことで回復し、1回の呼び出しで複数のテストの失敗を検出できます。

CHECK-LABEL:ディレクティブに、ソース言語または出力言語の実際の構文ラベルに対応する文字列が含まれている必要はありません。検証対象のファイル内の1行に一意に一致する必要があります。

CHECK-LABEL:ディレクティブには、変数の定義または使用を含めることはできません。

ディレクティブ修飾子

ディレクティブ修飾子は、ディレクティブの後に {<modifier>} を付けることで追加できます。ここで、<modifier> でサポートされている値は LITERAL のみです。

LITERAL ディレクティブ修飾子は、リテラルマッチを実行するために使用できます。この修飾子を使用すると、ディレクティブは正規表現マッチング、変数キャプチャ、または置換を実行するための構文を認識しなくなります。これは、一致させるテキストがそうでなければ過剰なエスケープを必要とする場合に役立ちます。たとえば、以下は正規表現としてではなく、リテラルマッチを実行します。

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 正規表現マッチング構文

すべての FileCheck ディレクティブは、一致させるパターンを取ります。FileCheck のほとんどの用途では、固定文字列マッチングで十分です。場合によっては、より柔軟な形式のマッチングが求められます。これをサポートするために、FileCheck では、二重中括弧で囲まれたマッチング文字列に正規表現を指定できます:{{yourregex}}。FileCheck は POSIX 正規表現マッチャーを実装しています。拡張 POSIX 正規表現 (ERE) をサポートしています。私たちは、私たちが行うことのほとんどで固定文字列マッチングを使用したいと考えているため、FileCheck は固定文字列マッチングと正規表現の混合とマッチングをサポートするように設計されています。これにより、次のようなものを書くことができます。

; CHECK: movhpd      {{[0-9]+}}(%esp), {{%xmm[0-7]}}

この場合、ESP レジスタからの任意のオフセットと、任意の xmm レジスタが許可されます。

正規表現は二重中括弧で囲まれているため、視覚的に区別され、C のように二重中括弧内でエスケープ文字を使用する必要はありません。入力から二重中括弧を明示的に一致させたいというまれなケースでは、{{[}][}]}} のような見苦しいパターンを使用できます。または、繰り返し回数構文を使用している場合、たとえば、正確に 8 桁の16進数を一致させる [[:xdigit:]]{8} の場合、FileCheck の閉じ二重中括弧との混同を避けるために、{{([[:xdigit:]]{8})}} のように括弧を追加する必要があります。

FileCheck 文字列置換ブロック

パターンを一致させてから、後でファイルに再度出現することを確認すると便利な場合があります。コード生成テストでは、これは任意のレジスタを許可するが、そのレジスタが後で一貫して使用されていることを確認するのに役立ちます。これを行うために、FileCheck は、文字列変数を定義し、パターンに代入できる文字列置換ブロックをサポートしています。簡単な例を次に示します。

; CHECK: test5:
; CHECK:    notw     [[REGISTER:%[a-z]+]]
; CHECK:    andw     {{.*}}[[REGISTER]]

最初のチェック行は正規表現 %[a-z]+ に一致し、それを文字列変数 REGISTER にキャプチャします。2行目は、REGISTER にあるものが「andw」の後にファイルの後半に現れることを確認します。FileCheck 文字列置換ブロックは常に [[ ]] のペアに含まれ、文字列変数名は正規表現 \$[a-zA-Z_][a-zA-Z0-9_]* で形成できます。名前にコロンが続く場合は、変数の定義です。そうでない場合は、置換です。

FileCheck 変数は複数回定義でき、置換は常に最新の値を取得します。変数は、定義されたのと同じ行で後で置換することもできます。例えば

; CHECK: op [[REG:r[0-9]+]], [[REG]]

op のオペランドが同じレジスタであり、どのレジスタであるかは気にしない場合に役立ちます。

--enable-var-scope が有効になっている場合、$ で始まる名前の変数はグローバルと見なされます。他のすべての変数はローカルです。すべてのローカル変数は、各 CHECK-LABEL ブロックの先頭で未定義になります。グローバル変数は CHECK-LABEL の影響を受けません。これにより、個々のテストが前のテストで設定された変数の影響を受けないようにすることが容易になります。

FileCheck 数値置換ブロック

FileCheck は、数値変数を定義し、数値置換を介してそれらの変数に基づく数値式制約を満たす数値をチェックできる数値置換ブロックもサポートしています。これにより、CHECK: ディレクティブは、連続したレジスタを使用する必要があるなど、2つの数値間の数値関係を検証できます。

数値をキャプチャするための構文は [[#%<fmtspec>,<NUMVAR>:]] です。ここで

  • %<fmtspec>, は、一致させる数値形式と、予期される最小桁数を示すオプションのフォーマット指定子です。

  • <NUMVAR>: は、キャプチャされた値からの変数 <NUMVAR> のオプションの定義です。

<fmtspec> の構文は次のとおりです:#.<precision><conversion specifier> 。ここで

  • # は、16進数値に使用できるオプションのフラグです(以下の <conversion specifier> を参照)。これは、一致する値の前に 0x が付いている必要があります。

  • .<precision> は、オプションの printf スタイルの精度指定子です。ここで、<precision> は、一致する値が持たなければならない最小桁数を示し、必要に応じて先行ゼロが予期されます。

  • <conversion specifier> は、一致させる数値形式(例:16進数)を示すオプションの scanf スタイルの変換指定子です。現在受け入れられているフォーマット指定子は、%u%d%x、および %X です。指定しない場合、フォーマット指定子のデフォルトは %u です。

例えば

; CHECK: mov r[[#REG:]], 0x[[#%.8X,ADDR:]]

mov r5, 0x0000FEFE に一致し、REG を値 5 に、ADDR を値 0xFEFE に設定します。精度のために、mov r5, 0xFEFE とは一致しません。

数値変数定義はオプションであるため、数値が特定の形式で存在することのみを確認できます。これは、値自体が役に立たない場合に役立ちます。たとえば、

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

値が移動されるのではなく、合成されることを確認するためです。

数値置換の構文は [[#%<fmtspec>, <constraint> <expr>]] です。ここで

  • <fmtspec> は、変数を定義する場合と同じフォーマット指定子ですが、このコンテキストでは、数値式の値をどのように照合するかを示します。指定しない場合、フォーマット指定子の両方のコンポーネントは、式制約で使用される数値変数のマッチング形式から推測されます(存在する場合)。数値変数が使用されない場合は、デフォルトで %u になり、値が先行ゼロなしの符号なしであることを示します。複数の数値変数のフォーマット指定子が競合する場合、変換指定子は必須になりますが、精度指定子はオプションのままです。

  • <constraint> は、一致する値が数値式の値とどのように関連している必要があるかを記述する制約です。現在受け入れられている唯一の制約は、完全一致のための == であり、<constraint> が指定されていない場合のデフォルトです。<expr> が空の場合、マッチング制約を指定する必要はありません。

  • <expr> は式です。式は、 wiederum 再帰的に次のように定義されます。

    • 数値オペランド、または

    • 式とそれに続く演算子と数値オペランド。

    数値オペランドは、以前に定義された数値変数、整数リテラル、または関数です。これらの要素の前、後、および間にスペースを使用できます。数値オペランドは 64 ビット精度です。オーバーフローとアンダーフローは拒否されます。演算子の優先順位はサポートされていませんが、括弧を使用して評価順序を変更できます。

サポートされている演算子は次のとおりです。

  • + - 2つのオペランドの合計を返します。

  • - - 2つのオペランドの差を返します。

関数呼び出しの構文は <name>(<arguments>) です。ここで

  • name は定義済みの文字列リテラルです。受け入れられる値は次のとおりです。

    • add - 2つのオペランドの合計を返します。

    • div - 2つのオペランドの商を返します。

    • max - 2つのオペランドの大きい方を返します。

    • min - 2つのオペランドの小さい方を返します。

    • mul - 2つのオペランドの積を返します。

    • sub - 2つのオペランドの差を返します。

  • <arguments> は、コンマで区切られた式のリストです。

例えば

; CHECK: load r[[#REG:]], [r0]
; CHECK: load r[[#REG+1]], [r1]
; CHECK: Loading from 0x[[#%x,ADDR:]]
; CHECK-SAME: to 0x[[#ADDR + 7]]

上記の例は、次のテキストと一致します。

load r5, [r0]
load r6, [r1]
Loading from 0xa0463440 to 0xa0463447

ただし、次のテキストとは一致しません。

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

75 + 1 と等しくないため、および a0463443a0463440 + 7 と等しくないためです。

数値変数は、数値式の結果として定義することもできます。この場合、数値式の制約がチェックされ、検証された場合、変数に値が代入されます。数値式をチェックし、その値を数値変数に取り込むための統一構文は、[[#%<fmtspec>,<NUMVAR>: <constraint> <expr>]] です。各要素は前述のとおりです。この構文を使用すると、値の代わりに変数を使用することで、テストケースをより分かりやすく記述できます。

; CHECK: mov r[[#REG_OFFSET:]], 0x[[#%X,FIELD_OFFSET:12]]
; CHECK-NEXT: load r[[#]], [r[[#REG_BASE:]], r[[#REG_OFFSET]]]

これは以下に一致します。

mov r4, 0xC
load r6, [r5, r4]

--enable-var-scope オプションは、文字列変数と同様に、数値変数にも同じ効果があります。

重要事項: 現在のところ、式では、同じ CHECK ディレクティブで以前に定義された数値変数を使用することはできません。

FileCheck 擬似数値変数

コンパイラの診断テストなど、一致ファイルの行番号を含む出力を検証する必要がある場合があります。これは、"“CHECK:” 行に同じファイル内の絶対行番号が含まれているため、テキストの追加や削除によって行番号が変更されるたびに更新する必要があるため、一致ファイル構造の脆弱性につながります。

これをサポートするために、FileCheck 式は、それが検出された CHECK パターンの行番号に評価される @LINE 擬似数値変数を理解します。

このように、一致パターンを関連するテスト行の近くに配置し、相対行番号参照を含めることができます。例えば、

// CHECK: test.cpp:[[# @LINE + 4]]:6: error: expected ';' after top level declarator
// CHECK-NEXT: {{^int a}}
// CHECK-NEXT: {{^     \^}}
// CHECK-NEXT: {{^     ;}}
int a

@LINE を特別な文字列変数として使用するという従来の使用方法をサポートするために、**FileCheck** は、[[@LINE]][[@LINE+<offset>]][[@LINE-<offset>]] のような、括弧内にスペースがなく、offset が整数である場合の @LINE の使用も受け入れます。文字列置換ブロック構文を使用します。

改行文字のマッチング

正規表現で改行文字を一致させるには、文字クラス [[:space:]] を使用できます。例えば、次のパターンは

// CHECK: DW_AT_location [DW_FORM_sec_offset] ([[DLOC:0x[0-9a-f]+]]){{[[:space:]].*}}"intd"

(llvm-dwarfdump からの) 以下の形式の出力と一致します

DW_AT_location [DW_FORM_sec_offset]   (0x00000233)
DW_AT_name [DW_FORM_strp]  ( .debug_str[0x000000c9] = "intd")

これにより、**FileCheck** 変数 DLOC を、"“intd” の直前の行から抽出された目的の値 0x00000233 に設定できます。