[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