Update LLVM 8 llvm-profdata and FileCheck

This commit is contained in:
Martin Kinkelin 2019-03-02 19:56:59 +01:00
parent 5ab43e95e0
commit 923ed00a60
2 changed files with 506 additions and 25 deletions

View file

@ -633,13 +633,21 @@ static void traverseAllValueSites(const InstrProfRecord &Func, uint32_t VK,
Stats.ValueSitesHistogram.resize(NV, 0); Stats.ValueSitesHistogram.resize(NV, 0);
Stats.ValueSitesHistogram[NV - 1]++; Stats.ValueSitesHistogram[NV - 1]++;
} }
uint64_t SiteSum = 0;
for (uint32_t V = 0; V < NV; V++)
SiteSum += VD[V].Count;
if (SiteSum == 0)
SiteSum = 1;
for (uint32_t V = 0; V < NV; V++) { for (uint32_t V = 0; V < NV; V++) {
OS << "\t[ " << I << ", "; OS << "\t[ " << format("%2u", I) << ", ";
if (Symtab == nullptr) if (Symtab == nullptr)
OS << VD[V].Value; OS << format("%4u", VD[V].Value);
else else
OS << Symtab->getFuncName(VD[V].Value); OS << Symtab->getFuncName(VD[V].Value);
OS << ", " << VD[V].Count << " ]\n"; OS << ", " << format("%10" PRId64, VD[V].Count) << " ] ("
<< format("%.2f%%", (VD[V].Count * 100.0 / SiteSum)) << ")\n";
} }
} }
} }
@ -662,9 +670,9 @@ static int showInstrProfile(const std::string &Filename, bool ShowCounts,
uint32_t TopN, bool ShowIndirectCallTargets, uint32_t TopN, bool ShowIndirectCallTargets,
bool ShowMemOPSizes, bool ShowDetailedSummary, bool ShowMemOPSizes, bool ShowDetailedSummary,
std::vector<uint32_t> DetailedSummaryCutoffs, std::vector<uint32_t> DetailedSummaryCutoffs,
bool ShowAllFunctions, bool ShowAllFunctions, uint64_t ValueCutoff,
const std::string &ShowFunction, bool TextFormat, bool OnlyListBelow, const std::string &ShowFunction,
raw_fd_ostream &OS) { bool TextFormat, raw_fd_ostream &OS) {
auto ReaderOrErr = InstrProfReader::create(Filename); auto ReaderOrErr = InstrProfReader::create(Filename);
std::vector<uint32_t> Cutoffs = std::move(DetailedSummaryCutoffs); std::vector<uint32_t> Cutoffs = std::move(DetailedSummaryCutoffs);
if (ShowDetailedSummary && Cutoffs.empty()) { if (ShowDetailedSummary && Cutoffs.empty()) {
@ -677,6 +685,7 @@ static int showInstrProfile(const std::string &Filename, bool ShowCounts,
auto Reader = std::move(ReaderOrErr.get()); auto Reader = std::move(ReaderOrErr.get());
bool IsIRInstr = Reader->isIRLevelProfile(); bool IsIRInstr = Reader->isIRLevelProfile();
size_t ShownFunctions = 0; size_t ShownFunctions = 0;
size_t BelowCutoffFunctions = 0;
int NumVPKind = IPVK_Last - IPVK_First + 1; int NumVPKind = IPVK_Last - IPVK_First + 1;
std::vector<ValueSitesStats> VPStats(NumVPKind); std::vector<ValueSitesStats> VPStats(NumVPKind);
@ -690,6 +699,11 @@ static int showInstrProfile(const std::string &Filename, bool ShowCounts,
decltype(MinCmp)> decltype(MinCmp)>
HottestFuncs(MinCmp); HottestFuncs(MinCmp);
if (!TextFormat && OnlyListBelow) {
OS << "The list of functions with the maximum counter less than "
<< ValueCutoff << ":\n";
}
// Add marker so that IR-level instrumentation round-trips properly. // Add marker so that IR-level instrumentation round-trips properly.
if (TextFormat && IsIRInstr) if (TextFormat && IsIRInstr)
OS << ":ir\n"; OS << ":ir\n";
@ -711,11 +725,24 @@ static int showInstrProfile(const std::string &Filename, bool ShowCounts,
assert(Func.Counts.size() > 0 && "function missing entry counter"); assert(Func.Counts.size() > 0 && "function missing entry counter");
Builder.addRecord(Func); Builder.addRecord(Func);
if (TopN) {
uint64_t FuncMax = 0; uint64_t FuncMax = 0;
for (size_t I = 0, E = Func.Counts.size(); I < E; ++I) uint64_t FuncSum = 0;
for (size_t I = 0, E = Func.Counts.size(); I < E; ++I) {
FuncMax = std::max(FuncMax, Func.Counts[I]); FuncMax = std::max(FuncMax, Func.Counts[I]);
FuncSum += Func.Counts[I];
}
if (FuncMax < ValueCutoff) {
++BelowCutoffFunctions;
if (OnlyListBelow) {
OS << " " << Func.Name << ": (Max = " << FuncMax
<< " Sum = " << FuncSum << ")\n";
}
continue;
} else if (OnlyListBelow)
continue;
if (TopN) {
if (HottestFuncs.size() == TopN) { if (HottestFuncs.size() == TopN) {
if (HottestFuncs.top().second < FuncMax) { if (HottestFuncs.top().second < FuncMax) {
HottestFuncs.pop(); HottestFuncs.pop();
@ -726,7 +753,6 @@ static int showInstrProfile(const std::string &Filename, bool ShowCounts,
} }
if (Show) { if (Show) {
if (!ShownFunctions) if (!ShownFunctions)
OS << "Counters:\n"; OS << "Counters:\n";
@ -781,6 +807,12 @@ static int showInstrProfile(const std::string &Filename, bool ShowCounts,
if (ShowAllFunctions || !ShowFunction.empty()) if (ShowAllFunctions || !ShowFunction.empty())
OS << "Functions shown: " << ShownFunctions << "\n"; OS << "Functions shown: " << ShownFunctions << "\n";
OS << "Total functions: " << PS->getNumFunctions() << "\n"; OS << "Total functions: " << PS->getNumFunctions() << "\n";
if (ValueCutoff > 0) {
OS << "Number of functions with maximum count (< " << ValueCutoff
<< "): " << BelowCutoffFunctions << "\n";
OS << "Number of functions with maximum count (>= " << ValueCutoff
<< "): " << PS->getNumFunctions() - BelowCutoffFunctions << "\n";
}
OS << "Maximum function count: " << PS->getMaxFunctionCount() << "\n"; OS << "Maximum function count: " << PS->getMaxFunctionCount() << "\n";
OS << "Maximum internal block count: " << PS->getMaxInternalCount() << "\n"; OS << "Maximum internal block count: " << PS->getMaxInternalCount() << "\n";
@ -882,7 +914,14 @@ static int show_main(int argc, const char *argv[]) {
cl::opt<uint32_t> TopNFunctions( cl::opt<uint32_t> TopNFunctions(
"topn", cl::init(0), "topn", cl::init(0),
cl::desc("Show the list of functions with the largest internal counts")); cl::desc("Show the list of functions with the largest internal counts"));
cl::opt<uint32_t> ValueCutoff(
"value-cutoff", cl::init(0),
cl::desc("Set the count value cutoff. Functions with the maximum count "
"less than this value will not be printed out. (Default is 0)"));
cl::opt<bool> OnlyListBelow(
"list-below-cutoff", cl::init(false),
cl::desc("Only output names of functions whose max count values are "
"below the cutoff value"));
cl::ParseCommandLineOptions(argc, argv, "LLVM profile data summary\n"); cl::ParseCommandLineOptions(argc, argv, "LLVM profile data summary\n");
if (OutputFilename.empty()) if (OutputFilename.empty())
@ -902,7 +941,8 @@ static int show_main(int argc, const char *argv[]) {
return showInstrProfile(Filename, ShowCounts, TopNFunctions, return showInstrProfile(Filename, ShowCounts, TopNFunctions,
ShowIndirectCallTargets, ShowMemOPSizes, ShowIndirectCallTargets, ShowMemOPSizes,
ShowDetailedSummary, DetailedSummaryCutoffs, ShowDetailedSummary, DetailedSummaryCutoffs,
ShowAllFunctions, ShowFunction, TextFormat, OS); ShowAllFunctions, ValueCutoff, OnlyListBelow,
ShowFunction, TextFormat, OS);
else else
return showSampleProfile(Filename, ShowCounts, ShowAllFunctions, return showSampleProfile(Filename, ShowCounts, ShowAllFunctions,
ShowFunction, OS); ShowFunction, OS);

View file

@ -18,12 +18,14 @@
#include "llvm/Support/CommandLine.h" #include "llvm/Support/CommandLine.h"
#include "llvm/Support/InitLLVM.h" #include "llvm/Support/InitLLVM.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/WithColor.h"
#include "llvm/Support/raw_ostream.h" #include "llvm/Support/raw_ostream.h"
#include "llvm/Support/FileCheck.h" #include "llvm/Support/FileCheck.h"
using namespace llvm; using namespace llvm;
static cl::opt<std::string> static cl::opt<std::string>
CheckFilename(cl::Positional, cl::desc("<check-file>"), cl::Required); CheckFilename(cl::Positional, cl::desc("<check-file>"), cl::Optional);
static cl::opt<std::string> static cl::opt<std::string>
InputFilename("input-file", cl::desc("File to check (defaults to stdin)"), InputFilename("input-file", cl::desc("File to check (defaults to stdin)"),
@ -49,7 +51,8 @@ static cl::list<std::string> ImplicitCheckNot(
"this pattern occur which are not matched by a positive pattern"), "this pattern occur which are not matched by a positive pattern"),
cl::value_desc("pattern")); cl::value_desc("pattern"));
static cl::list<std::string> GlobalDefines("D", cl::Prefix, static cl::list<std::string>
GlobalDefines("D", cl::AlwaysPrefix,
cl::desc("Define a variable to be used in capture patterns."), cl::desc("Define a variable to be used in capture patterns."),
cl::value_desc("VAR=VALUE")); cl::value_desc("VAR=VALUE"));
@ -90,7 +93,27 @@ static cl::opt<bool> DumpInputOnFailure(
"dump-input-on-failure", cl::init(std::getenv(DumpInputEnv)), "dump-input-on-failure", cl::init(std::getenv(DumpInputEnv)),
cl::desc("Dump original input to stderr before failing.\n" cl::desc("Dump original input to stderr before failing.\n"
"The value can be also controlled using\n" "The value can be also controlled using\n"
"FILECHECK_DUMP_INPUT_ON_FAILURE environment variable.\n")); "FILECHECK_DUMP_INPUT_ON_FAILURE environment variable.\n"
"This option is deprecated in favor of -dump-input=fail.\n"));
enum DumpInputValue {
DumpInputDefault,
DumpInputHelp,
DumpInputNever,
DumpInputFail,
DumpInputAlways
};
static cl::opt<DumpInputValue> DumpInput(
"dump-input", cl::init(DumpInputDefault),
cl::desc("Dump input to stderr, adding annotations representing\n"
" currently enabled diagnostics\n"),
cl::value_desc("mode"),
cl::values(clEnumValN(DumpInputHelp, "help",
"Explain dump format and quit"),
clEnumValN(DumpInputNever, "never", "Never dump input"),
clEnumValN(DumpInputFail, "fail", "Dump input on failure"),
clEnumValN(DumpInputAlways, "always", "Always dump input")));
typedef cl::list<std::string>::const_iterator prefix_iterator; typedef cl::list<std::string>::const_iterator prefix_iterator;
@ -107,9 +130,392 @@ static void DumpCommandLine(int argc, char **argv) {
errs() << "\n"; errs() << "\n";
} }
struct MarkerStyle {
/// The starting char (before tildes) for marking the line.
char Lead;
/// What color to use for this annotation.
raw_ostream::Colors Color;
/// A note to follow the marker, or empty string if none.
std::string Note;
MarkerStyle() {}
MarkerStyle(char Lead, raw_ostream::Colors Color,
const std::string &Note = "")
: Lead(Lead), Color(Color), Note(Note) {}
};
static MarkerStyle GetMarker(FileCheckDiag::MatchType MatchTy) {
switch (MatchTy) {
case FileCheckDiag::MatchFoundAndExpected:
return MarkerStyle('^', raw_ostream::GREEN);
case FileCheckDiag::MatchFoundButExcluded:
return MarkerStyle('!', raw_ostream::RED, "error: no match expected");
case FileCheckDiag::MatchFoundButWrongLine:
return MarkerStyle('!', raw_ostream::RED, "error: match on wrong line");
case FileCheckDiag::MatchFoundButDiscarded:
return MarkerStyle('!', raw_ostream::CYAN,
"discard: overlaps earlier match");
case FileCheckDiag::MatchNoneAndExcluded:
return MarkerStyle('X', raw_ostream::GREEN);
case FileCheckDiag::MatchNoneButExpected:
return MarkerStyle('X', raw_ostream::RED, "error: no match found");
case FileCheckDiag::MatchFuzzy:
return MarkerStyle('?', raw_ostream::MAGENTA, "possible intended match");
}
llvm_unreachable_internal("unexpected match type");
}
static void DumpInputAnnotationHelp(raw_ostream &OS) {
OS << "The following description was requested by -dump-input=help to\n"
<< "explain the input annotations printed by -dump-input=always and\n"
<< "-dump-input=fail:\n\n";
// Labels for input lines.
OS << " - ";
WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "L:";
OS << " labels line number L of the input file\n";
// Labels for annotation lines.
OS << " - ";
WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "T:L";
OS << " labels the only match result for a pattern of type T from "
<< "line L of\n"
<< " the check file\n";
OS << " - ";
WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "T:L'N";
OS << " labels the Nth match result for a pattern of type T from line "
<< "L of\n"
<< " the check file\n";
// Markers on annotation lines.
OS << " - ";
WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "^~~";
OS << " marks good match (reported if -v)\n"
<< " - ";
WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "!~~";
OS << " marks bad match, such as:\n"
<< " - CHECK-NEXT on same line as previous match (error)\n"
<< " - CHECK-NOT found (error)\n"
<< " - CHECK-DAG overlapping match (discarded, reported if "
<< "-vv)\n"
<< " - ";
WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "X~~";
OS << " marks search range when no match is found, such as:\n"
<< " - CHECK-NEXT not found (error)\n"
<< " - CHECK-NOT not found (success, reported if -vv)\n"
<< " - CHECK-DAG not found after discarded matches (error)\n"
<< " - ";
WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "?";
OS << " marks fuzzy match when no match is found\n";
// Colors.
OS << " - colors ";
WithColor(OS, raw_ostream::GREEN, true) << "success";
OS << ", ";
WithColor(OS, raw_ostream::RED, true) << "error";
OS << ", ";
WithColor(OS, raw_ostream::MAGENTA, true) << "fuzzy match";
OS << ", ";
WithColor(OS, raw_ostream::CYAN, true, false) << "discarded match";
OS << ", ";
WithColor(OS, raw_ostream::CYAN, true, true) << "unmatched input";
OS << "\n\n"
<< "If you are not seeing color above or in input dumps, try: -color\n";
}
/// An annotation for a single input line.
struct InputAnnotation {
/// The check file line (one-origin indexing) where the directive that
/// produced this annotation is located.
unsigned CheckLine;
/// The index of the match result for this check.
unsigned CheckDiagIndex;
/// The label for this annotation.
std::string Label;
/// What input line (one-origin indexing) this annotation marks. This might
/// be different from the starting line of the original diagnostic if this is
/// a non-initial fragment of a diagnostic that has been broken across
/// multiple lines.
unsigned InputLine;
/// The column range (one-origin indexing, open end) in which to to mark the
/// input line. If InputEndCol is UINT_MAX, treat it as the last column
/// before the newline.
unsigned InputStartCol, InputEndCol;
/// The marker to use.
MarkerStyle Marker;
/// Whether this annotation represents a good match for an expected pattern.
bool FoundAndExpectedMatch;
};
/// Get an abbreviation for the check type.
std::string GetCheckTypeAbbreviation(Check::FileCheckType Ty) {
switch (Ty) {
case Check::CheckPlain:
if (Ty.getCount() > 1)
return "count";
return "check";
case Check::CheckNext:
return "next";
case Check::CheckSame:
return "same";
case Check::CheckNot:
return "not";
case Check::CheckDAG:
return "dag";
case Check::CheckLabel:
return "label";
case Check::CheckEmpty:
return "empty";
case Check::CheckEOF:
return "eof";
case Check::CheckBadNot:
return "bad-not";
case Check::CheckBadCount:
return "bad-count";
case Check::CheckNone:
llvm_unreachable("invalid FileCheckType");
}
llvm_unreachable("unknown FileCheckType");
}
static void BuildInputAnnotations(const std::vector<FileCheckDiag> &Diags,
std::vector<InputAnnotation> &Annotations,
unsigned &LabelWidth) {
// How many diagnostics has the current check seen so far?
unsigned CheckDiagCount = 0;
// What's the widest label?
LabelWidth = 0;
for (auto DiagItr = Diags.begin(), DiagEnd = Diags.end(); DiagItr != DiagEnd;
++DiagItr) {
InputAnnotation A;
// Build label, which uniquely identifies this check result.
A.CheckLine = DiagItr->CheckLine;
llvm::raw_string_ostream Label(A.Label);
Label << GetCheckTypeAbbreviation(DiagItr->CheckTy) << ":"
<< DiagItr->CheckLine;
A.CheckDiagIndex = UINT_MAX;
auto DiagNext = std::next(DiagItr);
if (DiagNext != DiagEnd && DiagItr->CheckTy == DiagNext->CheckTy &&
DiagItr->CheckLine == DiagNext->CheckLine)
A.CheckDiagIndex = CheckDiagCount++;
else if (CheckDiagCount) {
A.CheckDiagIndex = CheckDiagCount;
CheckDiagCount = 0;
}
if (A.CheckDiagIndex != UINT_MAX)
Label << "'" << A.CheckDiagIndex;
else
A.CheckDiagIndex = 0;
Label.flush();
LabelWidth = std::max((std::string::size_type)LabelWidth, A.Label.size());
MarkerStyle Marker = GetMarker(DiagItr->MatchTy);
A.Marker = Marker;
A.FoundAndExpectedMatch =
DiagItr->MatchTy == FileCheckDiag::MatchFoundAndExpected;
// Compute the mark location, and break annotation into multiple
// annotations if it spans multiple lines.
A.InputLine = DiagItr->InputStartLine;
A.InputStartCol = DiagItr->InputStartCol;
if (DiagItr->InputStartLine == DiagItr->InputEndLine) {
// Sometimes ranges are empty in order to indicate a specific point, but
// that would mean nothing would be marked, so adjust the range to
// include the following character.
A.InputEndCol =
std::max(DiagItr->InputStartCol + 1, DiagItr->InputEndCol);
Annotations.push_back(A);
} else {
assert(DiagItr->InputStartLine < DiagItr->InputEndLine &&
"expected input range not to be inverted");
A.InputEndCol = UINT_MAX;
A.Marker.Note = "";
Annotations.push_back(A);
for (unsigned L = DiagItr->InputStartLine + 1, E = DiagItr->InputEndLine;
L <= E; ++L) {
// If a range ends before the first column on a line, then it has no
// characters on that line, so there's nothing to render.
if (DiagItr->InputEndCol == 1 && L == E) {
Annotations.back().Marker.Note = Marker.Note;
break;
}
InputAnnotation B;
B.CheckLine = A.CheckLine;
B.CheckDiagIndex = A.CheckDiagIndex;
B.Label = A.Label;
B.InputLine = L;
B.Marker = Marker;
B.Marker.Lead = '~';
B.InputStartCol = 1;
if (L != E) {
B.InputEndCol = UINT_MAX;
B.Marker.Note = "";
} else
B.InputEndCol = DiagItr->InputEndCol;
B.FoundAndExpectedMatch = A.FoundAndExpectedMatch;
Annotations.push_back(B);
}
}
}
}
static void DumpAnnotatedInput(raw_ostream &OS, const FileCheckRequest &Req,
StringRef InputFileText,
std::vector<InputAnnotation> &Annotations,
unsigned LabelWidth) {
OS << "Full input was:\n<<<<<<\n";
// Sort annotations.
//
// First, sort in the order of input lines to make it easier to find relevant
// annotations while iterating input lines in the implementation below.
// FileCheck diagnostics are not always reported and recorded in the order of
// input lines due to, for example, CHECK-DAG and CHECK-NOT.
//
// Second, for annotations for the same input line, sort in the order of the
// FileCheck directive's line in the check file (where there's at most one
// directive per line) and then by the index of the match result for that
// directive. The rationale of this choice is that, for any input line, this
// sort establishes a total order of annotations that, with respect to match
// results, is consistent across multiple lines, thus making match results
// easier to track from one line to the next when they span multiple lines.
std::sort(Annotations.begin(), Annotations.end(),
[](const InputAnnotation &A, const InputAnnotation &B) {
if (A.InputLine != B.InputLine)
return A.InputLine < B.InputLine;
if (A.CheckLine != B.CheckLine)
return A.CheckLine < B.CheckLine;
// FIXME: Sometimes CHECK-LABEL reports its match twice with
// other diagnostics in between, and then diag index incrementing
// fails to work properly, and then this assert fails. We should
// suppress one of those diagnostics or do a better job of
// computing this index. For now, we just produce a redundant
// CHECK-LABEL annotation.
// assert(A.CheckDiagIndex != B.CheckDiagIndex &&
// "expected diagnostic indices to be unique within a "
// " check line");
return A.CheckDiagIndex < B.CheckDiagIndex;
});
// Compute the width of the label column.
const unsigned char *InputFilePtr = InputFileText.bytes_begin(),
*InputFileEnd = InputFileText.bytes_end();
unsigned LineCount = InputFileText.count('\n');
if (InputFileEnd[-1] != '\n')
++LineCount;
unsigned LineNoWidth = log10(LineCount) + 1;
// +3 below adds spaces (1) to the left of the (right-aligned) line numbers
// on input lines and (2) to the right of the (left-aligned) labels on
// annotation lines so that input lines and annotation lines are more
// visually distinct. For example, the spaces on the annotation lines ensure
// that input line numbers and check directive line numbers never align
// horizontally. Those line numbers might not even be for the same file.
// One space would be enough to achieve that, but more makes it even easier
// to see.
LabelWidth = std::max(LabelWidth, LineNoWidth) + 3;
// Print annotated input lines.
auto AnnotationItr = Annotations.begin(), AnnotationEnd = Annotations.end();
for (unsigned Line = 1;
InputFilePtr != InputFileEnd || AnnotationItr != AnnotationEnd;
++Line) {
const unsigned char *InputFileLine = InputFilePtr;
// Print right-aligned line number.
WithColor(OS, raw_ostream::BLACK, true)
<< format_decimal(Line, LabelWidth) << ": ";
// For the case where -v and colors are enabled, find the annotations for
// good matches for expected patterns in order to highlight everything
// else in the line. There are no such annotations if -v is disabled.
std::vector<InputAnnotation> FoundAndExpectedMatches;
if (Req.Verbose && WithColor(OS).colorsEnabled()) {
for (auto I = AnnotationItr; I != AnnotationEnd && I->InputLine == Line;
++I) {
if (I->FoundAndExpectedMatch)
FoundAndExpectedMatches.push_back(*I);
}
}
// Print numbered line with highlighting where there are no matches for
// expected patterns.
bool Newline = false;
{
WithColor COS(OS);
bool InMatch = false;
if (Req.Verbose)
COS.changeColor(raw_ostream::CYAN, true, true);
for (unsigned Col = 1; InputFilePtr != InputFileEnd && !Newline; ++Col) {
bool WasInMatch = InMatch;
InMatch = false;
for (auto M : FoundAndExpectedMatches) {
if (M.InputStartCol <= Col && Col < M.InputEndCol) {
InMatch = true;
break;
}
}
if (!WasInMatch && InMatch)
COS.resetColor();
else if (WasInMatch && !InMatch)
COS.changeColor(raw_ostream::CYAN, true, true);
if (*InputFilePtr == '\n')
Newline = true;
else
COS << *InputFilePtr;
++InputFilePtr;
}
}
OS << '\n';
unsigned InputLineWidth = InputFilePtr - InputFileLine - Newline;
// Print any annotations.
while (AnnotationItr != AnnotationEnd &&
AnnotationItr->InputLine == Line) {
WithColor COS(OS, AnnotationItr->Marker.Color, true);
// The two spaces below are where the ": " appears on input lines.
COS << left_justify(AnnotationItr->Label, LabelWidth) << " ";
unsigned Col;
for (Col = 1; Col < AnnotationItr->InputStartCol; ++Col)
COS << ' ';
COS << AnnotationItr->Marker.Lead;
// If InputEndCol=UINT_MAX, stop at InputLineWidth.
for (++Col; Col < AnnotationItr->InputEndCol && Col <= InputLineWidth;
++Col)
COS << '~';
const std::string &Note = AnnotationItr->Marker.Note;
if (!Note.empty()) {
// Put the note at the end of the input line. If we were to instead
// put the note right after the marker, subsequent annotations for the
// same input line might appear to mark this note instead of the input
// line.
for (; Col <= InputLineWidth; ++Col)
COS << ' ';
COS << ' ' << Note;
}
COS << '\n';
++AnnotationItr;
}
}
OS << ">>>>>>\n";
}
int main(int argc, char **argv) { int main(int argc, char **argv) {
// Enable use of ANSI color codes because FileCheck is using them to
// highlight text.
llvm::sys::Process::UseANSIEscapeCodes(true);
InitLLVM X(argc, argv); InitLLVM X(argc, argv);
cl::ParseCommandLineOptions(argc, argv); cl::ParseCommandLineOptions(argc, argv, /*Overview*/ "", /*Errs*/ nullptr,
"FILECHECK_OPTS");
if (DumpInput == DumpInputHelp) {
DumpInputAnnotationHelp(outs());
return 0;
}
if (CheckFilename.empty()) {
errs() << "<check-file> not specified\n";
return 2;
}
FileCheckRequest Req; FileCheckRequest Req;
for (auto Prefix : CheckPrefixes) for (auto Prefix : CheckPrefixes)
@ -118,8 +524,25 @@ int main(int argc, char **argv) {
for (auto CheckNot : ImplicitCheckNot) for (auto CheckNot : ImplicitCheckNot)
Req.ImplicitCheckNot.push_back(CheckNot); Req.ImplicitCheckNot.push_back(CheckNot);
for (auto G : GlobalDefines) bool GlobalDefineError = false;
for (auto G : GlobalDefines) {
size_t EqIdx = G.find('=');
if (EqIdx == std::string::npos) {
errs() << "Missing equal sign in command-line definition '-D" << G
<< "'\n";
GlobalDefineError = true;
continue;
}
if (EqIdx == 0) {
errs() << "Missing pattern variable name in command-line definition '-D"
<< G << "'\n";
GlobalDefineError = true;
continue;
}
Req.GlobalDefines.push_back(G); Req.GlobalDefines.push_back(G);
}
if (GlobalDefineError)
return 2;
Req.AllowEmptyInput = AllowEmptyInput; Req.AllowEmptyInput = AllowEmptyInput;
Req.EnableVarScope = EnableVarScope; Req.EnableVarScope = EnableVarScope;
@ -151,7 +574,6 @@ int main(int argc, char **argv) {
return 2; return 2;
} }
SourceMgr SM; SourceMgr SM;
// Read the expected strings from the check file. // Read the expected strings from the check file.
@ -198,10 +620,29 @@ int main(int argc, char **argv) {
InputFileText, InputFile.getBufferIdentifier()), InputFileText, InputFile.getBufferIdentifier()),
SMLoc()); SMLoc());
int ExitCode = if (DumpInput == DumpInputDefault)
FC.CheckInput(SM, InputFileText, CheckStrings) ? EXIT_SUCCESS : 1; DumpInput = DumpInputOnFailure ? DumpInputFail : DumpInputNever;
if (ExitCode == 1 && DumpInputOnFailure)
errs() << "Full input was:\n<<<<<<\n" << InputFileText << "\n>>>>>>\n"; std::vector<FileCheckDiag> Diags;
int ExitCode = FC.CheckInput(SM, InputFileText, CheckStrings,
DumpInput == DumpInputNever ? nullptr : &Diags)
? EXIT_SUCCESS
: 1;
if (DumpInput == DumpInputAlways ||
(ExitCode == 1 && DumpInput == DumpInputFail)) {
errs() << "\n"
<< "Input file: "
<< (InputFilename == "-" ? "<stdin>" : InputFilename.getValue())
<< "\n"
<< "Check file: " << CheckFilename << "\n"
<< "\n"
<< "-dump-input=help describes the format of the following dump.\n"
<< "\n";
std::vector<InputAnnotation> Annotations;
unsigned LabelWidth;
BuildInputAnnotations(Diags, Annotations, LabelWidth);
DumpAnnotatedInput(errs(), Req, InputFileText, Annotations, LabelWidth);
}
return ExitCode; return ExitCode;
} }