[FileCheck] Support comment directives

Sometimes you want to disable a FileCheck directive without removing
it entirely, or you want to write comments that mention a directive by
name.  The `COM:` directive makes it easy to do this.  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 this patch, you need to use some combination of rewording and
directive syntax mangling to prevent FileCheck from recognizing the
commented occurrences of `X32:` and `X64:` above as directives.
Moreover, FileCheck diagnostics have been proposed that might complain
about the occurrences of `X64` that don't have the trailing `:`
because they look like directive typos:

  <http://lists.llvm.org/pipermail/llvm-dev/2020-April/140610.html>

I think dodging all these problems can prove tedious for test authors,
and directive syntax mangling already makes the purpose of existing
test code unclear.  `COM:` can avoid all these problems.

This patch also updates the small set of existing tests that define
`COM` as a check prefix:

- clang/test/CodeGen/default-address-space.c
- clang/test/CodeGenOpenCL/addr-space-struct-arg.cl
- clang/test/Driver/hip-device-libs.hip
- llvm/test/Assembler/drop-debug-info-nonzero-alloca.ll

I think lit should support `COM:` as well.  Perhaps `clang -verify`
should too.

Reviewed By: jhenderson, thopre

Differential Revision: https://reviews.llvm.org/D79276
This commit is contained in:
Joel E. Denny 2020-05-04 18:05:55 -04:00
parent 1370757dd0
commit a1fd188223
18 changed files with 351 additions and 62 deletions

View File

@ -1,4 +1,4 @@
// RUN: %clang_cc1 -triple amdgcn---amdgiz -emit-llvm < %s | FileCheck -check-prefixes=CHECK,COM %s
// RUN: %clang_cc1 -triple amdgcn---amdgiz -emit-llvm < %s | FileCheck -check-prefixes=CHECK %s
// CHECK-DAG: @foo = addrspace(1) global i32 0
int foo;
@ -11,17 +11,17 @@ int ban[10];
int *A;
int *B;
// COM-LABEL: define i32 @test1()
// CHECK-LABEL: define i32 @test1()
// CHECK: load i32, i32* addrspacecast{{[^@]+}} @foo
int test1() { return foo; }
// COM-LABEL: define i32 @test2(i32 %i)
// COM: %[[addr:.*]] = getelementptr
// CHECK-LABEL: define i32 @test2(i32 %i)
// CHECK: %[[addr:.*]] = getelementptr
// CHECK: load i32, i32* %[[addr]]
// CHECK-NEXT: ret i32
int test2(int i) { return ban[i]; }
// COM-LABEL: define void @test3()
// CHECK-LABEL: define void @test3()
// CHECK: load i32*, i32** addrspacecast{{.*}} @B
// CHECK: load i32, i32*
// CHECK: load i32*, i32** addrspacecast{{.*}} @A

View File

@ -1,6 +1,6 @@
// RUN: %clang_cc1 %s -emit-llvm -o - -O0 -ffake-address-space-map -triple i686-pc-darwin | FileCheck -enable-var-scope -check-prefixes=COM,X86 %s
// RUN: %clang_cc1 %s -emit-llvm -o - -O0 -triple amdgcn | FileCheck -enable-var-scope -check-prefixes=COM,AMDGCN %s
// RUN: %clang_cc1 %s -emit-llvm -o - -cl-std=CL2.0 -O0 -triple amdgcn | FileCheck -enable-var-scope -check-prefixes=COM,AMDGCN,AMDGCN20 %s
// RUN: %clang_cc1 %s -emit-llvm -o - -O0 -ffake-address-space-map -triple i686-pc-darwin | FileCheck -enable-var-scope -check-prefixes=ALL,X86 %s
// RUN: %clang_cc1 %s -emit-llvm -o - -O0 -triple amdgcn | FileCheck -enable-var-scope -check-prefixes=ALL,AMDGCN %s
// RUN: %clang_cc1 %s -emit-llvm -o - -cl-std=CL2.0 -O0 -triple amdgcn | FileCheck -enable-var-scope -check-prefixes=ALL,AMDGCN,AMDGCN20 %s
// RUN: %clang_cc1 %s -emit-llvm -o - -cl-std=CL1.2 -O0 -triple spir-unknown-unknown-unknown | FileCheck -enable-var-scope -check-prefixes=SPIR %s
typedef int int2 __attribute__((ext_vector_type(2)));
@ -50,7 +50,7 @@ Mat4X4 __attribute__((noinline)) foo(Mat3X3 in) {
return out;
}
// COM-LABEL: define {{.*}} void @ker
// ALL-LABEL: define {{.*}} void @ker
// Expect two mem copies: one for the argument "in", and one for
// the return value.
// X86: call void @llvm.memcpy.p0i8.p1i8.i32(i8*
@ -70,7 +70,7 @@ Mat64X64 __attribute__((noinline)) foo_large(Mat32X32 in) {
return out;
}
// COM-LABEL: define {{.*}} void @ker_large
// ALL-LABEL: define {{.*}} void @ker_large
// Expect two mem copies: one for the argument "in", and one for
// the return value.
// X86: call void @llvm.memcpy.p0i8.p1i8.i32(i8*

View File

@ -10,7 +10,7 @@
// RUN: --cuda-gpu-arch=gfx803 \
// RUN: --rocm-path=%S/Inputs/rocm-device-libs \
// RUN: %S/Inputs/hip_multiple_inputs/b.hip \
// RUN: 2>&1 | FileCheck %s --check-prefixes=COM,FLUSHD
// RUN: 2>&1 | FileCheck %s --check-prefixes=ALL,FLUSHD
// Test subtarget with flushing off by ddefault.
@ -18,7 +18,7 @@
// RUN: --cuda-gpu-arch=gfx900 \
// RUN: --rocm-path=%S/Inputs/rocm-device-libs \
// RUN: %S/Inputs/hip_multiple_inputs/b.hip \
// RUN: 2>&1 | FileCheck %s --check-prefixes=COM,NOFLUSHD
// RUN: 2>&1 | FileCheck %s --check-prefixes=ALL,NOFLUSHD
// Test explicit flag, opposite of target default.
@ -27,7 +27,7 @@
// RUN: -fcuda-flush-denormals-to-zero \
// RUN: --rocm-path=%S/Inputs/rocm-device-libs \
// RUN: %S/Inputs/hip_multiple_inputs/b.hip \
// RUN: 2>&1 | FileCheck %s --check-prefixes=COM,FLUSHD
// RUN: 2>&1 | FileCheck %s --check-prefixes=ALL,FLUSHD
// Test explicit flag, opposite of target default.
@ -36,7 +36,7 @@
// RUN: -fno-cuda-flush-denormals-to-zero \
// RUN: --rocm-path=%S/Inputs/rocm-device-libs \
// RUN: %S/Inputs/hip_multiple_inputs/b.hip \
// RUN: 2>&1 | FileCheck %s --check-prefixes=COM,NOFLUSHD
// RUN: 2>&1 | FileCheck %s --check-prefixes=ALL,NOFLUSHD
// Test explicit flag, same as target default.
@ -45,7 +45,7 @@
// RUN: -fno-cuda-flush-denormals-to-zero \
// RUN: --rocm-path=%S/Inputs/rocm-device-libs \
// RUN: %S/Inputs/hip_multiple_inputs/b.hip \
// RUN: 2>&1 | FileCheck %s --check-prefixes=COM,NOFLUSHD
// RUN: 2>&1 | FileCheck %s --check-prefixes=ALL,NOFLUSHD
// Test explicit flag, same as target default.
@ -54,7 +54,7 @@
// RUN: -fcuda-flush-denormals-to-zero \
// RUN: --rocm-path=%S/Inputs/rocm-device-libs \
// RUN: %S/Inputs/hip_multiple_inputs/b.hip \
// RUN: 2>&1 | FileCheck %s --check-prefixes=COM,FLUSHD
// RUN: 2>&1 | FileCheck %s --check-prefixes=ALL,FLUSHD
// Test last flag wins, not flushing
@ -63,7 +63,7 @@
// RUN: -fcuda-flush-denormals-to-zero -fno-cuda-flush-denormals-to-zero \
// RUN: --rocm-path=%S/Inputs/rocm-device-libs \
// RUN: %S/Inputs/hip_multiple_inputs/b.hip \
// RUN: 2>&1 | FileCheck %s --check-prefixes=COM,NOFLUSHD
// RUN: 2>&1 | FileCheck %s --check-prefixes=ALL,NOFLUSHD
// RUN: %clang -### -target x86_64-linux-gnu \
@ -71,7 +71,7 @@
// RUN: -fcuda-flush-denormals-to-zero -fno-cuda-flush-denormals-to-zero \
// RUN: --rocm-path=%S/Inputs/rocm-device-libs \
// RUN: %S/Inputs/hip_multiple_inputs/b.hip \
// RUN: 2>&1 | FileCheck %s --check-prefixes=COM,NOFLUSHD
// RUN: 2>&1 | FileCheck %s --check-prefixes=ALL,NOFLUSHD
// RUN: %clang -### -target x86_64-linux-gnu \
@ -79,7 +79,7 @@
// RUN: -fno-cuda-flush-denormals-to-zero -fcuda-flush-denormals-to-zero \
// RUN: --rocm-path=%S/Inputs/rocm-device-libs \
// RUN: %S/Inputs/hip_multiple_inputs/b.hip \
// RUN: 2>&1 | FileCheck %s --check-prefixes=COM,FLUSHD
// RUN: 2>&1 | FileCheck %s --check-prefixes=ALL,FLUSHD
// RUN: %clang -### -target x86_64-linux-gnu \
@ -87,7 +87,7 @@
// RUN: -fno-cuda-flush-denormals-to-zero -fcuda-flush-denormals-to-zero \
// RUN: --rocm-path=%S/Inputs/rocm-device-libs \
// RUN: %S/Inputs/hip_multiple_inputs/b.hip \
// RUN: 2>&1 | FileCheck %s --check-prefixes=COM,FLUSHD
// RUN: 2>&1 | FileCheck %s --check-prefixes=ALL,FLUSHD
// Test --hip-device-lib-path flag
@ -95,7 +95,7 @@
// RUN: --cuda-gpu-arch=gfx803 \
// RUN: --hip-device-lib-path=%S/Inputs/rocm-device-libs/amdgcn/bitcode \
// RUN: %S/Inputs/hip_multiple_inputs/b.hip \
// RUN: 2>&1 | FileCheck %s --check-prefixes=COM,FLUSHD
// RUN: 2>&1 | FileCheck %s --check-prefixes=ALL,FLUSHD
// Test environment variable HIP_DEVICE_LIB_PATH
@ -103,18 +103,18 @@
// RUN: %clang -### -target x86_64-linux-gnu \
// RUN: --cuda-gpu-arch=gfx900 \
// RUN: %S/Inputs/hip_multiple_inputs/b.hip \
// RUN: 2>&1 | FileCheck %s --check-prefixes=COM
// RUN: 2>&1 | FileCheck %s --check-prefixes=ALL
// COM: {{"[^"]*clang[^"]*"}}
// COM-SAME: "-mlink-builtin-bitcode" "{{.*}}hip.bc"
// COM-SAME: "-mlink-builtin-bitcode" "{{.*}}ocml.bc"
// COM-SAME: "-mlink-builtin-bitcode" "{{.*}}ockl.bc"
// ALL: {{"[^"]*clang[^"]*"}}
// ALL-SAME: "-mlink-builtin-bitcode" "{{.*}}hip.bc"
// ALL-SAME: "-mlink-builtin-bitcode" "{{.*}}ocml.bc"
// ALL-SAME: "-mlink-builtin-bitcode" "{{.*}}ockl.bc"
// FLUSHD-SAME: "-mlink-builtin-bitcode" "{{.*}}oclc_daz_opt_on.bc"
// NOFLUSHD-SAME: "-mlink-builtin-bitcode" "{{.*}}oclc_daz_opt_off.bc"
// COM-SAME: "-mlink-builtin-bitcode" "{{.*}}oclc_unsafe_math_off.bc"
// COM-SAME: "-mlink-builtin-bitcode" "{{.*}}oclc_finite_only_off.bc"
// COM-SAME: "-mlink-builtin-bitcode" "{{.*}}oclc_correctly_rounded_sqrt_on.bc"
// COM-SAME: "-mlink-builtin-bitcode" "{{.*}}oclc_wavefrontsize64_on.bc"
// COM-SAME: "-mlink-builtin-bitcode" "{{.*}}oclc_isa_version_{{[0-9]+}}.bc"
// ALL-SAME: "-mlink-builtin-bitcode" "{{.*}}oclc_unsafe_math_off.bc"
// ALL-SAME: "-mlink-builtin-bitcode" "{{.*}}oclc_finite_only_off.bc"
// ALL-SAME: "-mlink-builtin-bitcode" "{{.*}}oclc_correctly_rounded_sqrt_on.bc"
// ALL-SAME: "-mlink-builtin-bitcode" "{{.*}}oclc_wavefrontsize64_on.bc"
// ALL-SAME: "-mlink-builtin-bitcode" "{{.*}}oclc_isa_version_{{[0-9]+}}.bc"

View File

@ -39,15 +39,31 @@ and from the command line.
match. By default, these patterns are prefixed with "``CHECK:``".
If you'd like to use a different prefix (e.g. because the same input
file is checking multiple different tool or options), the
:option:`--check-prefix` argument allows you to specify one or more
prefixes to match. Multiple prefixes are useful for tests which might
change for different run options, but most lines remain the same.
:option:`--check-prefix` argument allows you to specify (without the trailing
"``:``") one or more prefixes to match. Multiple prefixes are useful for tests
which might change for different run options, but most lines remain the same.
FileCheck does not permit duplicate prefixes, even if one is a check prefix
and one is a comment prefix (see :option:`--comment-prefixes` below).
.. option:: --check-prefixes prefix1,prefix2,...
An alias of :option:`--check-prefix` that allows multiple prefixes to be
specified as a comma separated list.
.. option:: --comment-prefixes prefix1,prefix2,...
By default, FileCheck ignores any occurrence in ``match-filename`` of any check
prefix if it is preceded on the same line by "``COM:``" or "``RUN:``". See the
section `The "COM:" directive`_ for usage details.
These default comment prefixes can be overridden by
:option:`--comment-prefixes` if they are not appropriate for your testing
environment. However, doing so is not recommended in LLVM's LIT-based test
suites, which should be easier to maintain if they all follow a consistent
comment style. In that case, consider proposing a change to the default
comment prefixes instead.
.. option:: --input-file filename
File to check (defaults to stdin).
@ -236,6 +252,57 @@ circumstances, for example, testing different architectural variants with
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 want to disable a FileCheck directive without removing it
entirely, or you want to write comments that mention a directive by name. The
"``COM:``" directive makes it easy to do this. For example, you might have:
.. code-block:: llvm
; 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 would need to use some combination of rewording and
directive syntax mangling to prevent FileCheck from recognizing the commented
occurrences of "``X32:``" and "``X64:``" above as directives. Moreover,
FileCheck diagnostics have been proposed that might complain about the above
occurrences of "``X64``" that don't have the trailing "``:``" because they look
like directive typos. Dodging all these problems can be tedious for a test
author, and directive syntax mangling can make the purpose of test code unclear.
"``COM:``" avoids all these problems.
A few important usage notes:
* "``COM:``" within another directive's pattern does *not* comment out the
remainder of the pattern. For example:
.. code-block:: llvm
; 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:``" in the same
manner as any other directive: only the first directive on the line is
recognized as a directive.
* For the sake of LIT, FileCheck treats "``RUN:``" just like "``COM:``". If this
is not suitable for your test environment, see :option:`--comment-prefixes`.
* 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 such with
:option:`--comment-prefixes`.
The "CHECK-NEXT:" directive
~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -25,6 +25,7 @@ namespace llvm {
/// Contains info about various FileCheck options.
struct FileCheckRequest {
std::vector<StringRef> CheckPrefixes;
std::vector<StringRef> CommentPrefixes;
bool NoCanonicalizeWhiteSpace = false;
std::vector<StringRef> ImplicitCheckNot;
std::vector<StringRef> GlobalDefines;
@ -53,6 +54,7 @@ enum FileCheckKind {
CheckDAG,
CheckLabel,
CheckEmpty,
CheckComment,
/// Indicates the pattern only matches the end of file. This is used for
/// trailing CHECK-NOTs.

View File

@ -1110,6 +1110,8 @@ std::string Check::FileCheckType::getDescription(StringRef Prefix) const {
return Prefix.str() + "-LABEL";
case Check::CheckEmpty:
return Prefix.str() + "-EMPTY";
case Check::CheckComment:
return std::string(Prefix);
case Check::CheckEOF:
return "implicit EOF";
case Check::CheckBadNot:
@ -1121,13 +1123,24 @@ std::string Check::FileCheckType::getDescription(StringRef Prefix) const {
}
static std::pair<Check::FileCheckType, StringRef>
FindCheckType(StringRef Buffer, StringRef Prefix) {
FindCheckType(const FileCheckRequest &Req, StringRef Buffer, StringRef Prefix) {
if (Buffer.size() <= Prefix.size())
return {Check::CheckNone, StringRef()};
char NextChar = Buffer[Prefix.size()];
StringRef Rest = Buffer.drop_front(Prefix.size() + 1);
// Check for comment.
if (Req.CommentPrefixes.end() != std::find(Req.CommentPrefixes.begin(),
Req.CommentPrefixes.end(),
Prefix)) {
if (NextChar == ':')
return {Check::CheckComment, Rest};
// Ignore a comment prefix if it has a suffix like "-NOT".
return {Check::CheckNone, StringRef()};
}
// Verify that the : is present after the prefix.
if (NextChar == ':')
return {Check::CheckPlain, Rest};
@ -1206,8 +1219,9 @@ static size_t SkipWord(StringRef Str, size_t Loc) {
/// If no valid prefix is found, the state of Buffer, LineNumber, and CheckTy
/// is unspecified.
static std::pair<StringRef, StringRef>
FindFirstMatchingPrefix(Regex &PrefixRE, StringRef &Buffer,
unsigned &LineNumber, Check::FileCheckType &CheckTy) {
FindFirstMatchingPrefix(const FileCheckRequest &Req, Regex &PrefixRE,
StringRef &Buffer, unsigned &LineNumber,
Check::FileCheckType &CheckTy) {
SmallVector<StringRef, 2> Matches;
while (!Buffer.empty()) {
@ -1235,7 +1249,7 @@ FindFirstMatchingPrefix(Regex &PrefixRE, StringRef &Buffer,
if (Skipped.empty() || !IsPartOfWord(Skipped.back())) {
// Now extract the type.
StringRef AfterSuffix;
std::tie(CheckTy, AfterSuffix) = FindCheckType(Buffer, Prefix);
std::tie(CheckTy, AfterSuffix) = FindCheckType(Req, Buffer, Prefix);
// If we've found a valid check type for this prefix, we're done.
if (CheckTy != Check::CheckNone)
@ -1316,7 +1330,7 @@ bool FileCheck::readCheckFile(
// found.
unsigned LineNumber = 1;
bool FoundUsedPrefix = false;
bool FoundUsedCheckPrefix = false;
while (1) {
Check::FileCheckType CheckTy;
@ -1324,10 +1338,11 @@ bool FileCheck::readCheckFile(
StringRef UsedPrefix;
StringRef AfterSuffix;
std::tie(UsedPrefix, AfterSuffix) =
FindFirstMatchingPrefix(PrefixRE, Buffer, LineNumber, CheckTy);
FindFirstMatchingPrefix(Req, PrefixRE, Buffer, LineNumber, CheckTy);
if (UsedPrefix.empty())
break;
FoundUsedPrefix = true;
if (CheckTy != Check::CheckComment)
FoundUsedCheckPrefix = true;
assert(UsedPrefix.data() == Buffer.data() &&
"Failed to move Buffer's start forward, or pointed prefix outside "
@ -1370,9 +1385,17 @@ bool FileCheck::readCheckFile(
// Remember the location of the start of the pattern, for diagnostics.
SMLoc PatternLoc = SMLoc::getFromPointer(Buffer.data());
// Extract the pattern from the buffer.
StringRef PatternBuffer = Buffer.substr(0, EOL);
Buffer = Buffer.substr(EOL);
// If this is a comment, we're done.
if (CheckTy == Check::CheckComment)
continue;
// Parse the pattern.
Pattern P(CheckTy, PatternContext.get(), LineNumber);
if (P.parsePattern(Buffer.substr(0, EOL), UsedPrefix, SM, Req))
if (P.parsePattern(PatternBuffer, UsedPrefix, SM, Req))
return true;
// Verify that CHECK-LABEL lines do not define or use variables
@ -1384,8 +1407,6 @@ bool FileCheck::readCheckFile(
return true;
}
Buffer = Buffer.substr(EOL);
// Verify that CHECK-NEXT/SAME/EMPTY lines have at least one CHECK line before them.
if ((CheckTy == Check::CheckNext || CheckTy == Check::CheckSame ||
CheckTy == Check::CheckEmpty) &&
@ -1414,7 +1435,7 @@ bool FileCheck::readCheckFile(
// When there are no used prefixes we report an error except in the case that
// no prefix is specified explicitly but -implicit-check-not is specified.
if (!FoundUsedPrefix &&
if (!FoundUsedCheckPrefix &&
(ImplicitNegativeChecks.empty() || !Req.IsDefaultCheckPrefix)) {
errs() << "error: no check strings found with prefix"
<< (Req.CheckPrefixes.size() > 1 ? "es " : " ");
@ -1874,50 +1895,76 @@ size_t FileCheckString::CheckDag(const SourceMgr &SM, StringRef Buffer,
return StartPos;
}
static bool ValidatePrefixes(StringSet<> &UniquePrefixes,
static bool ValidatePrefixes(StringRef Kind, StringSet<> &UniquePrefixes,
ArrayRef<StringRef> SuppliedPrefixes) {
for (StringRef Prefix : SuppliedPrefixes) {
if (Prefix.empty()) {
errs() << "error: supplied check prefix must not be the empty string\n";
errs() << "error: supplied " << Kind << " prefix must not be the empty "
<< "string\n";
return false;
}
static const Regex Validator("^[a-zA-Z0-9_-]*$");
if (!Validator.match(Prefix)) {
errs() << "error: supplied check prefix must start with a letter and "
<< "contain only alphanumeric characters, hyphens, and "
errs() << "error: supplied " << Kind << " prefix must start with a "
<< "letter and contain only alphanumeric characters, hyphens, and "
<< "underscores: '" << Prefix << "'\n";
return false;
}
if (!UniquePrefixes.insert(Prefix).second) {
errs() << "error: supplied check prefix must be unique among check "
<< "prefixes: '" << Prefix << "'\n";
errs() << "error: supplied " << Kind << " prefix must be unique among "
<< "check and comment prefixes: '" << Prefix << "'\n";
return false;
}
}
return true;
}
static const char *DefaultCheckPrefixes[] = {"CHECK"};
static const char *DefaultCommentPrefixes[] = {"COM", "RUN"};
bool FileCheck::ValidateCheckPrefixes() {
StringSet<> UniquePrefixes;
if (!ValidatePrefixes(UniquePrefixes, Req.CheckPrefixes))
// Add default prefixes to catch user-supplied duplicates of them below.
if (Req.CheckPrefixes.empty()) {
for (const char *Prefix : DefaultCheckPrefixes)
UniquePrefixes.insert(Prefix);
}
if (Req.CommentPrefixes.empty()) {
for (const char *Prefix : DefaultCommentPrefixes)
UniquePrefixes.insert(Prefix);
}
// Do not validate the default prefixes, or diagnostics about duplicates might
// incorrectly indicate that they were supplied by the user.
if (!ValidatePrefixes("check", UniquePrefixes, Req.CheckPrefixes))
return false;
if (!ValidatePrefixes("comment", UniquePrefixes, Req.CommentPrefixes))
return false;
return true;
}
Regex FileCheck::buildCheckPrefixRegex() {
if (Req.CheckPrefixes.empty()) {
Req.CheckPrefixes.push_back("CHECK");
for (const char *Prefix : DefaultCheckPrefixes)
Req.CheckPrefixes.push_back(Prefix);
Req.IsDefaultCheckPrefix = true;
}
if (Req.CommentPrefixes.empty()) {
for (const char *Prefix : DefaultCommentPrefixes)
Req.CommentPrefixes.push_back(Prefix);
}
// We already validated the contents of CheckPrefixes so just concatenate
// them as alternatives.
// We already validated the contents of CheckPrefixes and CommentPrefixes so
// just concatenate them as alternatives.
SmallString<32> PrefixRegexStr;
for (size_t I = 0, E = Req.CheckPrefixes.size(); I != E; ++I) {
if (I != 0)
PrefixRegexStr.push_back('|');
PrefixRegexStr.append(Req.CheckPrefixes[I]);
}
for (StringRef Prefix : Req.CommentPrefixes) {
PrefixRegexStr.push_back('|');
PrefixRegexStr.append(Prefix);
}
return Regex(PrefixRegexStr);
}

View File

@ -1,7 +1,7 @@
; RUN: llvm-as < %s -o %t.bc -data-layout=A5 2>&1 | FileCheck -check-prefixes=COM,AS %s
; RUN: llvm-dis < %t.bc | FileCheck -check-prefixes=COM,DIS %s
; RUN: opt < %s -S -data-layout=A5 2>&1 | FileCheck -check-prefixes=COM,AS %s
; RUN: opt < %t.bc -S | FileCheck -check-prefixes=COM,DIS %s
; RUN: llvm-as < %s -o %t.bc -data-layout=A5 2>&1 | FileCheck -check-prefixes=ALL,AS %s
; RUN: llvm-dis < %t.bc | FileCheck -check-prefixes=ALL,DIS %s
; RUN: opt < %s -S -data-layout=A5 2>&1 | FileCheck -check-prefixes=ALL,AS %s
; RUN: opt < %t.bc -S | FileCheck -check-prefixes=ALL,DIS %s
define void @foo() {
entry:
@ -12,7 +12,7 @@ entry:
metadata i8* undef,
metadata !DILocalVariable(scope: !1),
metadata !DIExpression())
; COM-NOT: Allocation instruction pointer not in the stack address space!
; ALL-NOT: Allocation instruction pointer not in the stack address space!
; AS: llvm.dbg.value intrinsic requires a !dbg attachment
; AS: warning: ignoring invalid debug info in <stdin>
ret void

View File

@ -0,0 +1,16 @@
# Comment prefixes are not recognized at ends of words.
RUN: echo 'foo' > %t.in
RUN: echo 'bar' >> %t.in
RUN: echo 'foo' >> %t.in
RUN: echo 'bar' >> %t.in
RUN: echo 'FOO-COM: CHECK: foo' > %t.chk
RUN: echo 'RUN_COM: CHECK: bar' >> %t.chk
RUN: echo 'RUN3COM: CHECK: foo' >> %t.chk
RUN: echo ' COMRUN: CHECK: bar' >> %t.chk
RUN: %ProtectFileCheckOutput FileCheck -vv %t.chk < %t.in 2>&1 | FileCheck %s
CHECK: .chk:1:17: remark: CHECK: expected string found in input
CHECK: .chk:2:17: remark: CHECK: expected string found in input
CHECK: .chk:3:17: remark: CHECK: expected string found in input
CHECK: .chk:4:17: remark: CHECK: expected string found in input

View File

@ -0,0 +1,48 @@
# Bad comment prefixes are diagnosed.
# Check empty comment prefix.
RUN: %ProtectFileCheckOutput not FileCheck /dev/null < /dev/null 2>&1 \
RUN: -comment-prefixes= | \
RUN: FileCheck -check-prefix=PREFIX-EMPTY %s
RUN: %ProtectFileCheckOutput not FileCheck /dev/null < /dev/null 2>&1 \
RUN: -comment-prefixes=,FOO | \
RUN: FileCheck -check-prefix=PREFIX-EMPTY %s
RUN: %ProtectFileCheckOutput not FileCheck /dev/null < /dev/null 2>&1 \
RUN: -comment-prefixes=FOO, | \
RUN: FileCheck -check-prefix=PREFIX-EMPTY %s
RUN: %ProtectFileCheckOutput not FileCheck /dev/null < /dev/null 2>&1 \
RUN: -comment-prefixes=FOO,,BAR | \
RUN: FileCheck -check-prefix=PREFIX-EMPTY %s
PREFIX-EMPTY: error: supplied comment prefix must not be the empty string
# Check invalid characters in comment prefix.
RUN: %ProtectFileCheckOutput not FileCheck /dev/null < /dev/null 2>&1 \
RUN: -comment-prefixes=. | \
RUN: FileCheck -check-prefix=PREFIX-BAD-CHAR1 %s
RUN: %ProtectFileCheckOutput not FileCheck /dev/null < /dev/null 2>&1 \
RUN: -comment-prefixes='foo ' | \
RUN: FileCheck -check-prefix=PREFIX-BAD-CHAR2 %s
PREFIX-BAD-CHAR1: error: supplied comment prefix must start with a letter and contain only alphanumeric characters, hyphens, and underscores: '.'
PREFIX-BAD-CHAR2: error: supplied comment prefix must start with a letter and contain only alphanumeric characters, hyphens, and underscores: 'foo '
# Check duplicate comment prefixes.
RUN: %ProtectFileCheckOutput not FileCheck /dev/null < /dev/null 2>&1 \
RUN: -comment-prefixes=FOO,BAR,BAZ,BAR | \
RUN: FileCheck -check-prefix=COMMENT-PREFIX-DUP %s
COMMENT-PREFIX-DUP: error: supplied comment prefix must be unique among check and comment prefixes: 'BAR'
# Check user-supplied check prefix that duplicates a default comment prefix.
RUN: %ProtectFileCheckOutput not FileCheck /dev/null < /dev/null 2>&1 \
RUN: -check-prefixes=FOO,COM | \
RUN: FileCheck -check-prefix=CHECK-PREFIX-DUP-COM %s
RUN: %ProtectFileCheckOutput not FileCheck /dev/null < /dev/null 2>&1 \
RUN: -check-prefixes=RUN,FOO | \
RUN: FileCheck -check-prefix=CHECK-PREFIX-DUP-RUN_ %s
CHECK-PREFIX-DUP-COM: error: supplied check prefix must be unique among check and comment prefixes: 'COM'
CHECK-PREFIX-DUP-RUN_: error: supplied check prefix must be unique among check and comment prefixes: 'RUN'
# Check user-supplied comment prefix that duplicates default check prefixes.
RUN: %ProtectFileCheckOutput not FileCheck /dev/null < /dev/null 2>&1 \
RUN: -comment-prefixes=CHECK | \
RUN: FileCheck -check-prefix=COMMENT-PREFIX-DUP-CHECK %s
COMMENT-PREFIX-DUP-CHECK: error: supplied comment prefix must be unique among check and comment prefixes: 'CHECK'

View File

@ -0,0 +1,9 @@
# Comment directives with blank contents are fine.
RUN: echo 'foo' > %t.in
RUN: echo 'COM:' > %t.chk
RUN: echo 'CHECK: foo' >> %t.chk
RUN: echo ' COM: ' >> %t.chk
RUN: %ProtectFileCheckOutput FileCheck -vv %t.chk < %t.in 2>&1 | FileCheck %s
CHECK: .chk:2:8: remark: CHECK: expected string found in input

View File

@ -0,0 +1,22 @@
# Comment prefixes plus check directive suffixes are not comment directives
# and are treated as plain text.
RUN: echo foo > %t.in
RUN: echo bar >> %t.in
RUN: echo 'COM-NEXT: CHECK: foo' > %t.chk
RUN: echo 'RUN-NOT: CHECK: bar' >> %t.chk
RUN: %ProtectFileCheckOutput FileCheck -vv %t.chk < %t.in 2>&1 | \
RUN: FileCheck -check-prefix=CHECK1 %s
CHECK1: .chk:1:18: remark: CHECK: expected string found in input
CHECK1: .chk:2:17: remark: CHECK: expected string found in input
# But we can define them as comment prefixes.
RUN: %ProtectFileCheckOutput \
RUN: FileCheck -vv -comment-prefixes=COM,RUN,RUN-NOT %t.chk < %t.in 2>&1 | \
RUN: FileCheck -check-prefix=CHECK2 %s
CHECK2: .chk:1:18: remark: CHECK: expected string found in input
CHECK2-NOT: .chk:2

View File

@ -0,0 +1,33 @@
# Comment directives successfully comment out check directives.
# Check all default comment prefixes.
# Check that a comment directive at the beginning/end of the file is handled.
# Check that the preceding/following line's check directive is not affected.
RUN: echo 'foo' > %t-1.in
RUN: echo 'COM: CHECK: bar' > %t-1.chk
RUN: echo 'CHECK: foo' >> %t-1.chk
RUN: echo 'RUN: echo "CHECK: baz"' >> %t-1.chk
RUN: %ProtectFileCheckOutput FileCheck -vv %t-1.chk < %t-1.in 2>&1 | \
RUN: FileCheck -DCHECK_LINE=2 %s
# Check the case of one user-specified comment prefix.
# Check that a comment directive not at the beginning of a line is handled.
RUN: echo 'foo' > %t-2.in
RUN: echo 'CHECK: foo' > %t-2.chk
RUN: echo 'letters then space MY-PREFIX: CHECK: bar' >> %t-2.chk
RUN: %ProtectFileCheckOutput \
RUN: FileCheck -vv %t-2.chk -comment-prefixes=MY-PREFIX < %t-2.in 2>&1 | \
RUN: FileCheck -DCHECK_LINE=1 %s
# Check the case of multiple user-specified comment prefixes.
RUN: echo 'foo' > %t-3.in
RUN: echo 'Bar_2: CHECK: Bar' > %t-3.chk
RUN: echo 'CHECK: foo' >> %t-3.chk
RUN: echo 'Foo_1: CHECK: Foo' >> %t-3.chk
RUN: echo 'Baz_3: CHECK: Baz' >> %t-3.chk
RUN: %ProtectFileCheckOutput \
RUN: FileCheck -vv %t-3.chk -comment-prefixes=Foo_1,Bar_2 \
RUN: -comment-prefixes=Baz_3 < %t-3.in 2>&1 | \
RUN: FileCheck -DCHECK_LINE=2 %s
CHECK: .chk:[[CHECK_LINE]]:8: remark: CHECK: expected string found in input

View File

@ -0,0 +1,8 @@
# Comment directives do not suppress diagnostics for unused check prefixes.
RUN: echo 'foo' > %t.in
RUN: echo 'COM: foo' > %t.chk
RUN: echo 'RUN: echo' >> %t.chk
RUN: %ProtectFileCheckOutput not FileCheck %t.chk < %t.in 2>&1 | FileCheck %s
CHECK: error: no check strings found with prefix 'CHECK:'

View File

@ -0,0 +1,16 @@
# Not using comment directives is always fine.
RUN: echo 'foo' > %t.in
RUN: echo 'CHECK: foo' > %t.chk
# Check the case of default comment prefixes.
RUN: %ProtectFileCheckOutput \
RUN: FileCheck -vv %t.chk < %t.in 2>&1 | FileCheck %s
# Specifying non-default comment prefixes doesn't mean you have to use them.
# For example, they might be applied to an entire test suite via
# FILECHECK_OPTS or via a wrapper command or substitution.
RUN: %ProtectFileCheckOutput \
RUN: FileCheck -vv -comment-prefixes=FOO %t.chk < %t.in 2>&1 | FileCheck %s
CHECK: .chk:1:8: remark: CHECK: expected string found in input

View File

@ -0,0 +1,8 @@
# A comment directive is not recognized within a check directive's pattern and
# thus does not comment out the remainder of the pattern.
RUN: echo 'foo' > %t.in
RUN: echo 'CHECK: foo COM: bar' > %t.chk
RUN: %ProtectFileCheckOutput not FileCheck %t.chk < %t.in 2>&1 | FileCheck %s
CHECK: .chk:1:8: error: CHECK: expected string not found in input

View File

@ -1,2 +1,2 @@
RUN: FileCheck -check-prefix=RUN -input-file %s %s
RUN: FileCheck -check-prefix=RUN --comment-prefixes=COM -input-file %s %s
// Prefix is at the first character in the file. The run line then matches itself.

View File

@ -8,6 +8,6 @@ foobar
; BAD_PREFIX: supplied check prefix must start with a letter and contain only alphanumeric characters, hyphens, and underscores: 'A!'
; DUPLICATE_PREFIX: error: supplied check prefix must be unique among check prefixes: 'REPEAT'
; DUPLICATE_PREFIX: error: supplied check prefix must be unique among check and comment prefixes: 'REPEAT'
; EMPTY_PREFIX: error: supplied check prefix must not be the empty string

View File

@ -44,6 +44,14 @@ static cl::alias CheckPrefixesAlias(
cl::desc(
"Alias for -check-prefix permitting multiple comma separated values"));
static cl::list<std::string> CommentPrefixes(
"comment-prefixes", cl::CommaSeparated, cl::Hidden,
cl::desc("Comma-separated list of comment prefixes to use from check file\n"
"(defaults to 'COM,RUN'). Please avoid using this feature in\n"
"LLVM's LIT-based test suites, which should be easier to\n"
"maintain if they all follow a consistent comment style. This\n"
"feature is meant for non-LIT test suites using FileCheck."));
static cl::opt<bool> NoCanonicalizeWhiteSpace(
"strict-whitespace",
cl::desc("Do not treat all horizontal whitespace as equivalent"));
@ -279,6 +287,8 @@ std::string GetCheckTypeAbbreviation(Check::FileCheckType Ty) {
return "label";
case Check::CheckEmpty:
return "empty";
case Check::CheckComment:
return "com";
case Check::CheckEOF:
return "eof";
case Check::CheckBadNot:
@ -565,6 +575,9 @@ int main(int argc, char **argv) {
for (StringRef Prefix : CheckPrefixes)
Req.CheckPrefixes.push_back(Prefix);
for (StringRef Prefix : CommentPrefixes)
Req.CommentPrefixes.push_back(Prefix);
for (StringRef CheckNot : ImplicitCheckNot)
Req.ImplicitCheckNot.push_back(CheckNot);