2009-07-09 02:44:05 +08:00
|
|
|
//===- FileCheck.cpp - Check that File's Contents match what is expected --===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// FileCheck does a line-by line check of a file that validates whether it
|
|
|
|
// contains the expected content. This is useful for regression tests etc.
|
|
|
|
//
|
2017-03-14 18:51:14 +08:00
|
|
|
// This program exits with an exit status of 2 on error, exit status of 0 if
|
2009-07-09 02:44:05 +08:00
|
|
|
// the file matched the expected contents, and exit status of 1 if it did not
|
|
|
|
// contain the expected contents.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "llvm/Support/CommandLine.h"
|
2018-04-14 02:26:06 +08:00
|
|
|
#include "llvm/Support/InitLLVM.h"
|
[SourceMgr][FileCheck] Obey -color by extending WithColor
(Relands r344930, reverted in r344935, and now hopefully fixed for
Windows.)
While this change specifically targets FileCheck, it affects any tool
using the same SourceMgr facilities.
Previously, -color was documented in FileCheck's -help output, but
-color had no effect. Now, -color obeys its documentation: it forces
colors to be used in FileCheck diagnostics even when stderr is not a
terminal.
-color is especially helpful when combined with FileCheck's -v, which
can produce a long series of diagnostics that you might wish to pipe
to a pager, such as less -R. The WithColor extensions here will also
help to clean up color usage in FileCheck's annotated dump of input,
which is proposed in D52999.
Reviewed By: JDevlieghere, zturner
Differential Revision: https://reviews.llvm.org/D53419
llvm-svn: 345202
2018-10-25 05:46:42 +08:00
|
|
|
#include "llvm/Support/Process.h"
|
2009-07-09 02:44:05 +08:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2018-08-08 05:58:49 +08:00
|
|
|
#include "llvm/Support/FileCheck.h"
|
2009-07-09 02:44:05 +08:00
|
|
|
using namespace llvm;
|
|
|
|
|
|
|
|
static cl::opt<std::string>
|
2016-12-11 17:54:36 +08:00
|
|
|
CheckFilename(cl::Positional, cl::desc("<check-file>"), cl::Required);
|
2009-07-09 02:44:05 +08:00
|
|
|
|
|
|
|
static cl::opt<std::string>
|
2016-12-11 17:54:36 +08:00
|
|
|
InputFilename("input-file", cl::desc("File to check (defaults to stdin)"),
|
|
|
|
cl::init("-"), cl::value_desc("filename"));
|
2009-07-09 02:44:05 +08:00
|
|
|
|
2016-12-11 17:54:36 +08:00
|
|
|
static cl::list<std::string> CheckPrefixes(
|
|
|
|
"check-prefix",
|
|
|
|
cl::desc("Prefix to use from check file (defaults to 'CHECK')"));
|
2016-06-14 22:28:04 +08:00
|
|
|
static cl::alias CheckPrefixesAlias(
|
|
|
|
"check-prefixes", cl::aliasopt(CheckPrefixes), cl::CommaSeparated,
|
|
|
|
cl::NotHidden,
|
|
|
|
cl::desc(
|
|
|
|
"Alias for -check-prefix permitting multiple comma separated values"));
|
2009-07-09 02:44:05 +08:00
|
|
|
|
2016-12-11 17:54:36 +08:00
|
|
|
static cl::opt<bool> NoCanonicalizeWhiteSpace(
|
|
|
|
"strict-whitespace",
|
|
|
|
cl::desc("Do not treat all horizontal whitespace as equivalent"));
|
2009-07-12 02:58:15 +08:00
|
|
|
|
2014-07-11 20:39:32 +08:00
|
|
|
static cl::list<std::string> ImplicitCheckNot(
|
|
|
|
"implicit-check-not",
|
|
|
|
cl::desc("Add an implicit negative check with this pattern to every\n"
|
|
|
|
"positive check. This can be used to ensure that no instances of\n"
|
|
|
|
"this pattern occur which are not matched by a positive pattern"),
|
|
|
|
cl::value_desc("pattern"));
|
|
|
|
|
2017-11-07 21:24:44 +08:00
|
|
|
static cl::list<std::string> GlobalDefines("D", cl::Prefix,
|
|
|
|
cl::desc("Define a variable to be used in capture patterns."),
|
|
|
|
cl::value_desc("VAR=VALUE"));
|
|
|
|
|
2014-08-08 02:40:37 +08:00
|
|
|
static cl::opt<bool> AllowEmptyInput(
|
|
|
|
"allow-empty", cl::init(false),
|
|
|
|
cl::desc("Allow the input file to be empty. This is useful when making\n"
|
|
|
|
"checks that some error message does not occur, for example."));
|
|
|
|
|
2016-02-12 00:46:09 +08:00
|
|
|
static cl::opt<bool> MatchFullLines(
|
|
|
|
"match-full-lines", cl::init(false),
|
|
|
|
cl::desc("Require all positive matches to cover an entire input line.\n"
|
|
|
|
"Allows leading and trailing whitespace if --strict-whitespace\n"
|
|
|
|
"is not also passed."));
|
|
|
|
|
2017-03-10 01:59:04 +08:00
|
|
|
static cl::opt<bool> EnableVarScope(
|
|
|
|
"enable-var-scope", cl::init(false),
|
|
|
|
cl::desc("Enables scope for regex variables. Variables with names that\n"
|
|
|
|
"do not start with '$' will be reset at the beginning of\n"
|
|
|
|
"each CHECK-LABEL block."));
|
|
|
|
|
2018-07-12 04:27:27 +08:00
|
|
|
static cl::opt<bool> AllowDeprecatedDagOverlap(
|
|
|
|
"allow-deprecated-dag-overlap", cl::init(false),
|
|
|
|
cl::desc("Enable overlapping among matches in a group of consecutive\n"
|
|
|
|
"CHECK-DAG directives. This option is deprecated and is only\n"
|
|
|
|
"provided for convenience as old tests are migrated to the new\n"
|
|
|
|
"non-overlapping CHECK-DAG implementation.\n"));
|
|
|
|
|
2018-07-13 11:08:23 +08:00
|
|
|
static cl::opt<bool> Verbose("v", cl::init(false),
|
|
|
|
cl::desc("Print directive pattern matches.\n"));
|
|
|
|
|
|
|
|
static cl::opt<bool> VerboseVerbose(
|
|
|
|
"vv", cl::init(false),
|
|
|
|
cl::desc("Print information helpful in diagnosing internal FileCheck\n"
|
|
|
|
"issues. Implies -v.\n"));
|
2018-07-21 04:21:57 +08:00
|
|
|
static const char * DumpInputEnv = "FILECHECK_DUMP_INPUT_ON_FAILURE";
|
|
|
|
|
|
|
|
static cl::opt<bool> DumpInputOnFailure(
|
|
|
|
"dump-input-on-failure", cl::init(std::getenv(DumpInputEnv)),
|
|
|
|
cl::desc("Dump original input to stderr before failing.\n"
|
|
|
|
"The value can be also controlled using\n"
|
|
|
|
"FILECHECK_DUMP_INPUT_ON_FAILURE environment variable.\n"));
|
2018-07-13 11:08:23 +08:00
|
|
|
|
2013-11-10 10:04:09 +08:00
|
|
|
typedef cl::list<std::string>::const_iterator prefix_iterator;
|
|
|
|
|
2011-04-09 14:18:02 +08:00
|
|
|
|
2010-08-21 01:38:38 +08:00
|
|
|
|
2012-12-03 00:02:41 +08:00
|
|
|
|
2010-08-21 01:38:38 +08:00
|
|
|
|
|
|
|
|
2013-08-13 07:05:59 +08:00
|
|
|
|
2016-05-28 05:23:25 +08:00
|
|
|
static void DumpCommandLine(int argc, char **argv) {
|
|
|
|
errs() << "FileCheck command line: ";
|
|
|
|
for (int I = 0; I < argc; I++)
|
|
|
|
errs() << " " << argv[I];
|
|
|
|
errs() << "\n";
|
|
|
|
}
|
|
|
|
|
2018-08-08 05:58:49 +08:00
|
|
|
int main(int argc, char **argv) {
|
[SourceMgr][FileCheck] Obey -color by extending WithColor
(Relands r344930, reverted in r344935, and now hopefully fixed for
Windows.)
While this change specifically targets FileCheck, it affects any tool
using the same SourceMgr facilities.
Previously, -color was documented in FileCheck's -help output, but
-color had no effect. Now, -color obeys its documentation: it forces
colors to be used in FileCheck diagnostics even when stderr is not a
terminal.
-color is especially helpful when combined with FileCheck's -v, which
can produce a long series of diagnostics that you might wish to pipe
to a pager, such as less -R. The WithColor extensions here will also
help to clean up color usage in FileCheck's annotated dump of input,
which is proposed in D52999.
Reviewed By: JDevlieghere, zturner
Differential Revision: https://reviews.llvm.org/D53419
llvm-svn: 345202
2018-10-25 05:46:42 +08:00
|
|
|
// Enable use of ANSI color codes because FileCheck is using them to
|
|
|
|
// highlight text.
|
|
|
|
llvm::sys::Process::UseANSIEscapeCodes(true);
|
|
|
|
|
2018-08-08 05:58:49 +08:00
|
|
|
InitLLVM X(argc, argv);
|
2018-11-07 06:07:03 +08:00
|
|
|
cl::ParseCommandLineOptions(argc, argv, /*Overview*/ "", /*Errs*/ nullptr,
|
|
|
|
"FILECHECK_OPTS");
|
2013-07-12 22:51:05 +08:00
|
|
|
|
2018-08-08 05:58:49 +08:00
|
|
|
FileCheckRequest Req;
|
|
|
|
for (auto Prefix : CheckPrefixes)
|
|
|
|
Req.CheckPrefixes.push_back(Prefix);
|
2013-07-12 22:51:05 +08:00
|
|
|
|
2018-08-08 05:58:49 +08:00
|
|
|
for (auto CheckNot : ImplicitCheckNot)
|
|
|
|
Req.ImplicitCheckNot.push_back(CheckNot);
|
2013-07-12 22:51:05 +08:00
|
|
|
|
2018-08-08 05:58:49 +08:00
|
|
|
for (auto G : GlobalDefines)
|
|
|
|
Req.GlobalDefines.push_back(G);
|
2010-08-21 01:38:38 +08:00
|
|
|
|
2018-08-08 05:58:49 +08:00
|
|
|
Req.AllowEmptyInput = AllowEmptyInput;
|
|
|
|
Req.EnableVarScope = EnableVarScope;
|
|
|
|
Req.AllowDeprecatedDagOverlap = AllowDeprecatedDagOverlap;
|
|
|
|
Req.Verbose = Verbose;
|
|
|
|
Req.VerboseVerbose = VerboseVerbose;
|
|
|
|
Req.NoCanonicalizeWhiteSpace = NoCanonicalizeWhiteSpace;
|
|
|
|
Req.MatchFullLines = MatchFullLines;
|
2016-12-11 17:50:05 +08:00
|
|
|
|
2018-08-08 05:58:49 +08:00
|
|
|
if (VerboseVerbose)
|
|
|
|
Req.Verbose = true;
|
2016-12-11 17:50:05 +08:00
|
|
|
|
2018-08-08 05:58:49 +08:00
|
|
|
FileCheck FC(Req);
|
|
|
|
if (!FC.ValidateCheckPrefixes()) {
|
2016-12-11 17:50:05 +08:00
|
|
|
errs() << "Supplied check-prefix is invalid! Prefixes must be unique and "
|
|
|
|
"start with a letter and contain only alphanumeric characters, "
|
|
|
|
"hyphens and underscores\n";
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
|
2018-08-08 05:58:49 +08:00
|
|
|
Regex PrefixRE = FC.buildCheckPrefixRegex();
|
[FileCheck] Re-implement the logic to find each check prefix in the
check file to not be unreasonably slow in the face of multiple check
prefixes.
The previous logic would repeatedly scan potentially large portions of
the check file looking for alternative prefixes. In the worst case this
would scan most of the file looking for a rare prefix between every
single occurance of a common prefix. Even if we bounded the scan, this
would do bad things if the order of the prefixes was "unlucky" and the
distant prefix was scanned for first.
None of this is necessary. It is straightforward to build a state
machine that recognizes the first, longest of the set of alternative
prefixes. That is in fact exactly whan a regular expression does.
This patch builds a regular expression once for the set of prefixes and
then uses it to search incrementally for the next prefix. This requires
some threading of state but actually makes the code dramatically
simpler. I've also added a big comment describing the algorithm as it
was not at all obvious to me when I started.
With this patch, several previously pathological test cases in
test/CodeGen/X86 are 5x and more faster. Overall, running all tests
under test/CodeGen/X86 uses 10% less CPU after this, and because all the
slowest tests were hitting this, finishes in 40% less wall time on my
system (going from just over 5.38s to just over 3.23s) on a release
build! This patch substantially improves the time of all 7 X86 tests
that were in the top 20 reported by --time-tests, 5 of them are
completely off the list and the remaining 2 are much lower. (Sadly, the
new tests on the list include 2 new X86 ones that are slow for unrelated
reasons, so the count stays at 4 of the top 20.)
It isn't clear how much this helps debug builds in aggregate in part
because of the noise, but it again makes mane of the slowest x86 tests
significantly faster (10% or more improvement).
llvm-svn: 289382
2016-12-11 20:49:05 +08:00
|
|
|
std::string REError;
|
|
|
|
if (!PrefixRE.isValid(REError)) {
|
|
|
|
errs() << "Unable to combine check-prefix strings into a prefix regular "
|
|
|
|
"expression! This is likely a bug in FileCheck's verification of "
|
|
|
|
"the check-prefix strings. Regular expression parsing failed "
|
|
|
|
"with the following error: "
|
|
|
|
<< REError << "\n";
|
|
|
|
return 2;
|
|
|
|
}
|
2016-12-11 17:50:05 +08:00
|
|
|
|
2018-07-13 11:08:23 +08:00
|
|
|
|
2016-12-11 17:50:05 +08:00
|
|
|
SourceMgr SM;
|
|
|
|
|
|
|
|
// Read the expected strings from the check file.
|
|
|
|
ErrorOr<std::unique_ptr<MemoryBuffer>> CheckFileOrErr =
|
|
|
|
MemoryBuffer::getFileOrSTDIN(CheckFilename);
|
|
|
|
if (std::error_code EC = CheckFileOrErr.getError()) {
|
|
|
|
errs() << "Could not open check file '" << CheckFilename
|
|
|
|
<< "': " << EC.message() << '\n';
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
MemoryBuffer &CheckFile = *CheckFileOrErr.get();
|
|
|
|
|
|
|
|
SmallString<4096> CheckFileBuffer;
|
2018-08-08 05:58:49 +08:00
|
|
|
StringRef CheckFileText = FC.CanonicalizeFile(CheckFile, CheckFileBuffer);
|
2016-12-11 17:50:05 +08:00
|
|
|
|
|
|
|
SM.AddNewSourceBuffer(MemoryBuffer::getMemBuffer(
|
|
|
|
CheckFileText, CheckFile.getBufferIdentifier()),
|
|
|
|
SMLoc());
|
|
|
|
|
2018-08-08 05:58:49 +08:00
|
|
|
std::vector<FileCheckString> CheckStrings;
|
|
|
|
if (FC.ReadCheckFile(SM, CheckFileText, PrefixRE, CheckStrings))
|
2016-12-11 17:50:05 +08:00
|
|
|
return 2;
|
|
|
|
|
|
|
|
// Open the file to check and add it to SourceMgr.
|
|
|
|
ErrorOr<std::unique_ptr<MemoryBuffer>> InputFileOrErr =
|
|
|
|
MemoryBuffer::getFileOrSTDIN(InputFilename);
|
|
|
|
if (std::error_code EC = InputFileOrErr.getError()) {
|
|
|
|
errs() << "Could not open input file '" << InputFilename
|
|
|
|
<< "': " << EC.message() << '\n';
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
MemoryBuffer &InputFile = *InputFileOrErr.get();
|
|
|
|
|
|
|
|
if (InputFile.getBufferSize() == 0 && !AllowEmptyInput) {
|
|
|
|
errs() << "FileCheck error: '" << InputFilename << "' is empty.\n";
|
|
|
|
DumpCommandLine(argc, argv);
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
SmallString<4096> InputFileBuffer;
|
2018-08-08 05:58:49 +08:00
|
|
|
StringRef InputFileText = FC.CanonicalizeFile(InputFile, InputFileBuffer);
|
2016-12-11 17:50:05 +08:00
|
|
|
|
2016-12-11 17:54:36 +08:00
|
|
|
SM.AddNewSourceBuffer(MemoryBuffer::getMemBuffer(
|
|
|
|
InputFileText, InputFile.getBufferIdentifier()),
|
|
|
|
SMLoc());
|
2016-12-11 17:50:05 +08:00
|
|
|
|
2018-08-08 05:58:49 +08:00
|
|
|
int ExitCode =
|
|
|
|
FC.CheckInput(SM, InputFileText, CheckStrings) ? EXIT_SUCCESS : 1;
|
2018-07-21 04:21:57 +08:00
|
|
|
if (ExitCode == 1 && DumpInputOnFailure)
|
|
|
|
errs() << "Full input was:\n<<<<<<\n" << InputFileText << "\n>>>>>>\n";
|
|
|
|
|
|
|
|
return ExitCode;
|
2009-07-09 02:44:05 +08:00
|
|
|
}
|