Add 'CHECK-DAG' support

Refer to 'FileCheck.rst'f for details of 'CHECK-DAG'.



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@181827 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Michael Liao
2013-05-14 20:34:12 +00:00
parent 7efbbd61eb
commit 95ab326674
4 changed files with 306 additions and 23 deletions

View File

@ -60,6 +60,12 @@ class Pattern {
/// used for trailing CHECK-NOTs.
bool MatchEOF;
/// MatchNot
bool MatchNot;
/// MatchDag
bool MatchDag;
/// FixedStr - If non-empty, this pattern is a fixed string match with the
/// specified fixed string.
StringRef FixedStr;
@ -83,7 +89,8 @@ class Pattern {
public:
Pattern(bool matchEOF = false) : MatchEOF(matchEOF) { }
Pattern(bool matchEOF = false)
: MatchEOF(matchEOF), MatchNot(false), MatchDag(false) { }
/// getLoc - Return the location in source code.
SMLoc getLoc() const { return PatternLoc; }
@ -108,6 +115,12 @@ public:
void PrintFailureInfo(const SourceMgr &SM, StringRef Buffer,
const StringMap<StringRef> &VariableTable) const;
void setMatchNot(bool Not) { MatchNot = Not; }
bool getMatchNot() const { return MatchNot; }
void setMatchDag(bool Dag) { MatchDag = Dag; }
bool getMatchDag() const { return MatchDag; }
private:
static void AddFixedStringToRegEx(StringRef FixedStr, std::string &TheStr);
bool AddRegExToRegEx(StringRef RS, unsigned &CurParen, SourceMgr &SM);
@ -581,15 +594,15 @@ struct CheckString {
/// to a CHECK: directive.
bool IsCheckNext;
/// NotStrings - These are all of the strings that are disallowed from
/// DagNotStrings - These are all of the strings that are disallowed from
/// occurring between this match string and the previous one (or start of
/// file).
std::vector<Pattern> NotStrings;
std::vector<Pattern> DagNotStrings;
CheckString(const Pattern &P, SMLoc L, bool isCheckNext)
: Pat(P), Loc(L), IsCheckNext(isCheckNext) {}
/// Check - Match check string and its "not strings".
/// Check - Match check string and its "not strings" and/or "dag strings".
size_t Check(const SourceMgr &SM, StringRef Buffer, size_t &MatchLen,
StringMap<StringRef> &VariableTable) const;
@ -598,7 +611,13 @@ struct CheckString {
/// CheckNot - Verify there's no "not strings" in the given buffer.
bool CheckNot(const SourceMgr &SM, StringRef Buffer,
const std::vector<const Pattern *> &NotStrings,
StringMap<StringRef> &VariableTable) const;
/// CheckDag - Match "dag strings" and their mixed "not strings".
size_t CheckDag(const SourceMgr &SM, StringRef Buffer,
std::vector<const Pattern *> &NotStrings,
StringMap<StringRef> &VariableTable) const;
};
/// Canonicalize whitespaces in the input file. Line endings are replaced
@ -663,7 +682,7 @@ static bool ReadCheckFile(SourceMgr &SM,
// Find all instances of CheckPrefix followed by : in the file.
StringRef Buffer = F->getBuffer();
std::vector<Pattern> NotMatches;
std::vector<Pattern> DagNotMatches;
// LineNumber keeps track of the line on which CheckPrefix instances are
// found.
@ -684,7 +703,7 @@ static bool ReadCheckFile(SourceMgr &SM,
// When we find a check prefix, keep track of whether we find CHECK: or
// CHECK-NEXT:
bool IsCheckNext = false, IsCheckNot = false;
bool IsCheckNext = false, IsCheckNot = false, IsCheckDag = false;
// Verify that the : is present after the prefix.
if (Buffer[CheckPrefix.size()] == ':') {
@ -697,6 +716,10 @@ static bool ReadCheckFile(SourceMgr &SM,
memcmp(Buffer.data()+CheckPrefix.size(), "-NOT:", 5) == 0) {
Buffer = Buffer.substr(CheckPrefix.size()+5);
IsCheckNot = true;
} else if (Buffer.size() > CheckPrefix.size()+5 &&
memcmp(Buffer.data()+CheckPrefix.size(), "-DAG:", 5) == 0) {
Buffer = Buffer.substr(CheckPrefix.size()+5);
IsCheckDag = true;
} else {
Buffer = Buffer.substr(1);
continue;
@ -717,6 +740,9 @@ static bool ReadCheckFile(SourceMgr &SM,
if (P.ParsePattern(Buffer.substr(0, EOL), SM, LineNumber))
return true;
P.setMatchNot(IsCheckNot);
P.setMatchDag(IsCheckDag);
Buffer = Buffer.substr(EOL);
// Verify that CHECK-NEXT lines have at least one CHECK line before them.
@ -728,9 +754,9 @@ static bool ReadCheckFile(SourceMgr &SM,
return true;
}
// Handle CHECK-NOT.
if (IsCheckNot) {
NotMatches.push_back(P);
// Handle CHECK-DAG/-NOT.
if (IsCheckDag || IsCheckNot) {
DagNotMatches.push_back(P);
continue;
}
@ -738,15 +764,15 @@ static bool ReadCheckFile(SourceMgr &SM,
CheckStrings.push_back(CheckString(P,
PatternLoc,
IsCheckNext));
std::swap(NotMatches, CheckStrings.back().NotStrings);
std::swap(DagNotMatches, CheckStrings.back().DagNotStrings);
}
// Add an EOF pattern for any trailing CHECK-NOTs.
if (!NotMatches.empty()) {
// Add an EOF pattern for any trailing CHECK-DAG/-NOTs.
if (!DagNotMatches.empty()) {
CheckStrings.push_back(CheckString(Pattern(true),
SMLoc::getFromPointer(Buffer.data()),
false));
std::swap(NotMatches, CheckStrings.back().NotStrings);
std::swap(DagNotMatches, CheckStrings.back().DagNotStrings);
}
if (CheckStrings.empty()) {
@ -758,11 +784,11 @@ static bool ReadCheckFile(SourceMgr &SM,
return false;
}
static void PrintCheckFailed(const SourceMgr &SM, const CheckString &CheckStr,
StringRef Buffer,
static void PrintCheckFailed(const SourceMgr &SM, const SMLoc &Loc,
const Pattern &Pat, StringRef Buffer,
StringMap<StringRef> &VariableTable) {
// Otherwise, we have an error, emit an error message.
SM.PrintMessage(CheckStr.Loc, SourceMgr::DK_Error,
SM.PrintMessage(Loc, SourceMgr::DK_Error,
"expected string not found in input");
// Print the "scanning from here" line. If the current position is at the
@ -773,7 +799,13 @@ static void PrintCheckFailed(const SourceMgr &SM, const CheckString &CheckStr,
"scanning from here");
// Allow the pattern to print additional information if desired.
CheckStr.Pat.PrintFailureInfo(SM, Buffer, VariableTable);
Pat.PrintFailureInfo(SM, Buffer, VariableTable);
}
static void PrintCheckFailed(const SourceMgr &SM, const CheckString &CheckStr,
StringRef Buffer,
StringMap<StringRef> &VariableTable) {
PrintCheckFailed(SM, CheckStr.Loc, CheckStr.Pat, Buffer, VariableTable);
}
/// CountNumNewlinesBetween - Count the number of newlines in the specified
@ -799,13 +831,24 @@ static unsigned CountNumNewlinesBetween(StringRef Range) {
size_t CheckString::Check(const SourceMgr &SM, StringRef Buffer,
size_t &MatchLen,
StringMap<StringRef> &VariableTable) const {
size_t MatchPos = Pat.Match(Buffer, MatchLen, VariableTable);
size_t LastPos = 0;
std::vector<const Pattern *> NotStrings;
// Match "dag strings" (with mixed "not strings" if any).
LastPos = CheckDag(SM, Buffer, NotStrings, VariableTable);
if (LastPos == StringRef::npos)
return StringRef::npos;
// Match itself from the last position after matching CHECK-DAG.
StringRef MatchBuffer = Buffer.substr(LastPos);
size_t MatchPos = Pat.Match(MatchBuffer, MatchLen, VariableTable);
if (MatchPos == StringRef::npos) {
PrintCheckFailed(SM, *this, Buffer, VariableTable);
PrintCheckFailed(SM, *this, MatchBuffer, VariableTable);
return StringRef::npos;
}
MatchPos += LastPos;
StringRef SkippedRegion = Buffer.substr(0, MatchPos);
StringRef SkippedRegion = Buffer.substr(LastPos, MatchPos);
// If this check is a "CHECK-NEXT", verify that the previous match was on
// the previous line (i.e. that there is one newline between them).
@ -814,7 +857,7 @@ size_t CheckString::Check(const SourceMgr &SM, StringRef Buffer,
// If this match had "not strings", verify that they don't exist in the
// skipped region.
if (CheckNot(SM, SkippedRegion, VariableTable))
if (CheckNot(SM, SkippedRegion, NotStrings, VariableTable))
return StringRef::npos;
return MatchPos;
@ -857,18 +900,22 @@ bool CheckString::CheckNext(const SourceMgr &SM, StringRef Buffer) const {
}
bool CheckString::CheckNot(const SourceMgr &SM, StringRef Buffer,
const std::vector<const Pattern *> &NotStrings,
StringMap<StringRef> &VariableTable) const {
for (unsigned ChunkNo = 0, e = NotStrings.size();
ChunkNo != e; ++ChunkNo) {
const Pattern *Pat = NotStrings[ChunkNo];
assert(Pat->getMatchNot() && "Expect CHECK-NOT!");
size_t MatchLen = 0;
size_t Pos = NotStrings[ChunkNo].Match(Buffer, MatchLen, VariableTable);
size_t Pos = Pat->Match(Buffer, MatchLen, VariableTable);
if (Pos == StringRef::npos) continue;
SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()+Pos),
SourceMgr::DK_Error,
CheckPrefix+"-NOT: string occurred!");
SM.PrintMessage(NotStrings[ChunkNo].getLoc(), SourceMgr::DK_Note,
SM.PrintMessage(Pat->getLoc(), SourceMgr::DK_Note,
CheckPrefix+"-NOT: pattern specified here");
return true;
}
@ -876,6 +923,83 @@ bool CheckString::CheckNot(const SourceMgr &SM, StringRef Buffer,
return false;
}
size_t CheckString::CheckDag(const SourceMgr &SM, StringRef Buffer,
std::vector<const Pattern *> &NotStrings,
StringMap<StringRef> &VariableTable) const {
if (DagNotStrings.empty())
return 0;
size_t LastPos = 0;
size_t StartPos = LastPos;
for (unsigned ChunkNo = 0, e = DagNotStrings.size();
ChunkNo != e; ++ChunkNo) {
const Pattern &Pat = DagNotStrings[ChunkNo];
assert((Pat.getMatchDag() ^ Pat.getMatchNot()) &&
"Invalid CHECK-DAG or CHECK-NOT!");
if (Pat.getMatchNot()) {
NotStrings.push_back(&Pat);
continue;
}
assert(Pat.getMatchDag() && "Expect CHECK-DAG!");
size_t MatchLen = 0, MatchPos;
// CHECK-DAG always matches from the start.
StringRef MatchBuffer = Buffer.substr(StartPos);
MatchPos = Pat.Match(MatchBuffer, MatchLen, VariableTable);
// With a group of CHECK-DAGs, a single mismatching means the match on
// that group of CHECK-DAGs fails immediately.
if (MatchPos == StringRef::npos) {
PrintCheckFailed(SM, Pat.getLoc(), Pat, MatchBuffer, VariableTable);
return StringRef::npos;
}
// Re-calc it as the offset relative to the start of the original string.
MatchPos += StartPos;
if (!NotStrings.empty()) {
if (MatchPos < LastPos) {
// Reordered?
SM.PrintMessage(SMLoc::getFromPointer(Buffer.data() + MatchPos),
SourceMgr::DK_Error,
CheckPrefix+"-DAG: found a match of CHECK-DAG"
" reordering across a CHECK-NOT");
SM.PrintMessage(SMLoc::getFromPointer(Buffer.data() + LastPos),
SourceMgr::DK_Note,
CheckPrefix+"-DAG: the farthest match of CHECK-DAG"
" is found here");
SM.PrintMessage(NotStrings[0]->getLoc(), SourceMgr::DK_Note,
CheckPrefix+"-NOT: the crossed pattern specified"
" here");
SM.PrintMessage(Pat.getLoc(), SourceMgr::DK_Note,
CheckPrefix+"-DAG: the reordered pattern specified"
" here");
return StringRef::npos;
}
// All subsequent CHECK-DAGs should be matched from the farthest
// position of all precedent CHECK-DAGs (including this one.)
StartPos = LastPos;
// If there's CHECK-NOTs between two CHECK-DAGs or from CHECK to
// CHECK-DAG, verify that there's no 'not' strings occurred in that
// region.
StringRef SkippedRegion = Buffer.substr(LastPos, MatchPos);
size_t Pos = CheckNot(SM, SkippedRegion, NotStrings, VariableTable);
if (Pos != StringRef::npos)
return StringRef::npos;
// Clear "not strings".
NotStrings.clear();
}
// Update the last position with CHECK-DAG matches.
LastPos = std::max(MatchPos + MatchLen, LastPos);
}
return LastPos;
}
int main(int argc, char **argv) {
sys::PrintStackTraceOnErrorSignal();
PrettyStackTraceProgram X(argc, argv);