[LLVMdev] teaching FileCheck to handle variations in order
Matthew Curtis
mcurtis at codeaurora.org
Thu Sep 27 13:32:49 PDT 2012
I'm not very happy with the way the high-water mark is handled with the
current proposal, so I like to propose alternative. Rather that a stack
of positions, we keep a dictionary of named positions.
So this stack based example:
>
> ; CHECK-PUSH:
> ; CHECK: memw(##a)
> ; CHECK-POP:
> ; CHECK: memw(##b)
> ; CHECK-HWM:
>
> %0 = load i32* @a, align 4
> %1 = load i32* @b, align 4
>
> ; CHECK: memw(##a)
>
> %2 = load i32* @a, align 4
>
becomes:
; CHECK-SAVE-POS: foo
; CHECK: memw(##a)
; CHECK-RESTORE-POS: foo
; CHECK: memw(##b)
; CHECK-RESTORE-POS: ^
%0 = load i32* @a, align 4
%1 = load i32* @b, align 4
; CHECK: memw(##a)
%2 = load i32* @a, align 4
The name '^' used in the second CHECK-RESTORE-POS is a special name that
refers to the high water mark. I think this API is conceptually simpler,
a little more flexible.
See attached patch for implementation details.
Matthew C.
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20120927/3c333550/attachment.html>
-------------- next part --------------
diff --git a/utils/FileCheck/FileCheck.cpp b/utils/FileCheck/FileCheck.cpp
index e791628..7aa8115 100644
--- a/utils/FileCheck/FileCheck.cpp
+++ b/utils/FileCheck/FileCheck.cpp
@@ -30,6 +30,8 @@
#include <algorithm>
using namespace llvm;
+#include <stdio.h>
+
static cl::opt<std::string>
CheckFilename(cl::Positional, cl::desc("<check-file>"), cl::Required);
@@ -50,11 +52,23 @@ NoCanonicalizeWhiteSpace("strict-whitespace",
//===----------------------------------------------------------------------===//
class Pattern {
+public:
+ enum MatchType {
+ MatchStr,
+ MatchCurrent,
+ MatchEndOfFile
+ };
+
+private:
SMLoc PatternLoc;
- /// MatchEOF - When set, this pattern only matches the end of file. This is
- /// used for trailing CHECK-NOTs.
- bool MatchEOF;
+ /// MatchType - When set to ...
+ /// MatchStr, this pattern matches according to FixedStr or RegExStr.
+ /// MatchCurrent, this pattern matches (the empty string at) the current
+ /// position. This is used for CHECK-SAVEes without preceding CHECKs.
+ /// MatchEndOfFile, this pattern only matches the end of file. This is used
+ /// for trailing CHECK-NOTs.
+ enum MatchType Type;
/// FixedStr - If non-empty, this pattern is a fixed string match with the
/// specified fixed string.
@@ -77,7 +91,7 @@ class Pattern {
public:
- Pattern(bool matchEOF = false) : MatchEOF(matchEOF) { }
+ Pattern(enum MatchType t = MatchStr) : Type(t) { }
bool ParsePattern(StringRef PatternStr, SourceMgr &SM);
@@ -285,9 +299,18 @@ bool Pattern::AddRegExToRegEx(StringRef RegexStr, unsigned &CurParen,
size_t Pattern::Match(StringRef Buffer, size_t &MatchLen,
StringMap<StringRef> &VariableTable) const {
// If this is the EOF pattern, match it immediately.
- if (MatchEOF) {
+ switch (Type) {
+ case MatchStr:
+ break;
+ case MatchCurrent:
+ MatchLen = 0;
+ return 0;
+ case MatchEndOfFile:
MatchLen = 0;
return Buffer.size();
+ default:
+ assert("Unknown match type");
+ break;
}
// If this is a fixed string pattern, just match it now.
@@ -447,6 +470,9 @@ struct CheckString {
/// IsCheckNext - This is true if this is a CHECK-NEXT: directive (as opposed
/// to a CHECK: directive.
bool IsCheckNext;
+ std::vector<StringRef> SavePos;
+ StringRef RestorePos;
+ SMLoc RestoreLoc;
/// NotStrings - These are all of the strings that are disallowed from
/// occurring between this match string and the previous one (or start of
@@ -491,6 +517,48 @@ static MemoryBuffer *CanonicalizeInputFile(MemoryBuffer *MB) {
return MB2;
}
+inline bool IsWhitespace(char c)
+{
+ return c == ' ' || c == '\t';
+}
+
+static StringRef StripWhitespace(StringRef Str)
+{
+ StringRef::iterator i, j, e = Str.end();
+
+ for (i= Str.begin(); i != e; ++i)
+ if (!IsWhitespace(*i)) break;
+
+ for (j=i; j != e; ++j)
+ if (IsWhitespace(*i)) break;
+
+ return StringRef(i, j-i);
+}
+
+static bool ReadKey(SourceMgr &SM, const char* Directive, StringRef *Buffer, size_t EOL, StringRef *Key) {
+ *Key= StripWhitespace(Buffer->substr(0, EOL));
+
+ // Check that there is something on the line.
+ if (Key->empty()) {
+ SM.PrintMessage(SMLoc::getFromPointer(Buffer->data()), SourceMgr::DK_Error,
+ "'" + CheckPrefix + "-SAVE-POS:' missing register name");
+ return true;
+ }
+
+ *Buffer = Buffer->substr(EOL);
+ return false;
+}
+
+bool MatchCheckDirective(StringRef CheckPrefix, const char* Directive, StringRef *Buffer) {
+
+ int DirLen= strlen(Directive);
+ bool match= Buffer->size() > (CheckPrefix.size()+DirLen) &&
+ memcmp(Buffer->data()+CheckPrefix.size(), Directive, DirLen) == 0;
+
+ if (match)
+ *Buffer = Buffer->substr(CheckPrefix.size()+DirLen);
+ return match;
+}
/// ReadCheckFile - Read the check file, which specifies the sequence of
/// expected strings. The strings are added to the CheckStrings vector.
@@ -517,6 +585,8 @@ static bool ReadCheckFile(SourceMgr &SM,
StringRef Buffer = F->getBuffer();
std::vector<std::pair<SMLoc, Pattern> > NotMatches;
+ StringRef NextCheckRestorePos;
+ SMLoc NextCheckRestoreLoc;
while (1) {
// See if Prefix occurs in the memory buffer.
@@ -531,18 +601,19 @@ 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 IsCheckSavePos = false, IsCheckRestorePos = false;
// Verify that the : is present after the prefix.
- if (Buffer[CheckPrefix.size()] == ':') {
- Buffer = Buffer.substr(CheckPrefix.size()+1);
- } else if (Buffer.size() > CheckPrefix.size()+6 &&
- memcmp(Buffer.data()+CheckPrefix.size(), "-NEXT:", 6) == 0) {
- Buffer = Buffer.substr(CheckPrefix.size()+6);
+ if (MatchCheckDirective(CheckPrefix, ":", &Buffer)) {
+
+ } else if (MatchCheckDirective(CheckPrefix, "-NEXT:", &Buffer)) {
IsCheckNext = true;
- } else if (Buffer.size() > CheckPrefix.size()+5 &&
- memcmp(Buffer.data()+CheckPrefix.size(), "-NOT:", 5) == 0) {
- Buffer = Buffer.substr(CheckPrefix.size()+5);
+ } else if (MatchCheckDirective(CheckPrefix, "-NOT:", &Buffer)) {
IsCheckNot = true;
+ } else if (MatchCheckDirective(CheckPrefix, "-SAVE-POS:", &Buffer)) {
+ IsCheckSavePos = true;
+ } else if (MatchCheckDirective(CheckPrefix, "-RESTORE-POS:", &Buffer)) {
+ IsCheckRestorePos = true;
} else {
Buffer = Buffer.substr(1);
continue;
@@ -555,6 +626,32 @@ static bool ReadCheckFile(SourceMgr &SM,
// Scan ahead to the end of line.
size_t EOL = Buffer.find_first_of("\n\r");
+ if (IsCheckSavePos) {
+ if (CheckStrings.empty())
+ CheckStrings.push_back(
+ CheckString(Pattern(Pattern::MatchCurrent),
+ SMLoc::getFromPointer(Buffer.data()),
+ false));
+
+ StringRef Key;
+ if (ReadKey(SM, "-SAVE-POS:", &Buffer, EOL, &Key))
+ return true;
+
+ CheckStrings.back().SavePos.push_back(Key);
+ continue;
+ }
+
+ if (IsCheckRestorePos) {
+ NextCheckRestoreLoc = SMLoc::getFromPointer(CheckPrefixStart);
+
+ StringRef Key;
+ if (ReadKey(SM, "-RESTORE-POS:", &Buffer, EOL, &Key))
+ return true;
+
+ NextCheckRestorePos = Key;
+ continue;
+ }
+
// Remember the location of the start of the pattern, for diagnostics.
SMLoc PatternLoc = SMLoc::getFromPointer(Buffer.data());
@@ -587,14 +684,22 @@ static bool ReadCheckFile(SourceMgr &SM,
CheckStrings.push_back(CheckString(P,
PatternLoc,
IsCheckNext));
+ CheckStrings.back().RestorePos= NextCheckRestorePos;
+ CheckStrings.back().RestoreLoc= NextCheckRestoreLoc;
+ NextCheckRestorePos= StringRef();
+ NextCheckRestoreLoc= SMLoc();
std::swap(NotMatches, CheckStrings.back().NotStrings);
}
// Add an EOF pattern for any trailing CHECK-NOTs.
if (!NotMatches.empty()) {
- CheckStrings.push_back(CheckString(Pattern(true),
+ CheckStrings.push_back(CheckString(Pattern(Pattern::MatchEndOfFile),
SMLoc::getFromPointer(Buffer.data()),
false));
+ CheckStrings.back().RestorePos= NextCheckRestorePos;
+ CheckStrings.back().RestoreLoc= NextCheckRestoreLoc;
+ NextCheckRestorePos= StringRef();
+ NextCheckRestoreLoc= SMLoc();
std::swap(NotMatches, CheckStrings.back().NotStrings);
}
@@ -671,7 +776,7 @@ int main(int argc, char **argv) {
errs() << "FileCheck error: '" << InputFilename << "' is empty.\n";
return 1;
}
-
+
// Remove duplicate spaces in the input file if requested.
if (!NoCanonicalizeWhiteSpace)
F = CanonicalizeInputFile(F);
@@ -686,10 +791,29 @@ int main(int argc, char **argv) {
StringRef Buffer = F->getBuffer();
const char *LastMatch = Buffer.data();
+ StringMap<StringRef> PosTable;
+ PosTable["^"] = Buffer;
for (unsigned StrNo = 0, e = CheckStrings.size(); StrNo != e; ++StrNo) {
const CheckString &CheckStr = CheckStrings[StrNo];
+ if (!CheckStr.RestorePos.empty()) {
+ StringMap<StringRef>::iterator v= PosTable.find(CheckStr.RestorePos);
+
+ if (v == PosTable.end()) {
+ SM.PrintMessage(CheckStr.RestoreLoc, SourceMgr::DK_Error,
+ "attempting to '"+CheckPrefix+"-RESTORE: " + CheckStr.RestorePos + "' without previous '"+
+ CheckPrefix+ "-SAVE: " + CheckStr.RestorePos + "'");
+ return 1;
+ }
+
+ if (Buffer.data() > PosTable["^"].data())
+ PosTable["^"] = Buffer;
+
+ Buffer= v->second;
+ LastMatch = Buffer.data();
+ }
+
StringRef SearchFrom = Buffer;
// Find StrNo in the file.
@@ -751,11 +875,16 @@ int main(int argc, char **argv) {
return 1;
}
-
// Otherwise, everything is good. Step over the matched text and remember
// the position after the match as the end of the last match.
Buffer = Buffer.substr(MatchLen);
LastMatch = Buffer.data();
+
+ std::vector<StringRef>::const_iterator i = CheckStr.SavePos.begin();
+ std::vector<StringRef>::const_iterator e = CheckStr.SavePos.end();
+ for (; i != e; ++i) {
+ PosTable[*i] = Buffer;
+ }
}
return 0;
More information about the llvm-dev
mailing list