[llvm] r194343 - Allow multiple check prefixes in FileCheck.

Matt Arsenault Matthew.Arsenault at amd.com
Sat Nov 9 18:04:09 PST 2013


Author: arsenm
Date: Sat Nov  9 20:04:09 2013
New Revision: 194343

URL: http://llvm.org/viewvc/llvm-project?rev=194343&view=rev
Log:
Allow multiple check prefixes in FileCheck.

This is useful if you want to run multiple variations
of a single test, and the majority of check lines
should be the same.

Added:
    llvm/trunk/test/FileCheck/check-a-b-has-b.txt
    llvm/trunk/test/FileCheck/check-b-a-has-b.txt
    llvm/trunk/test/FileCheck/check-dag-multi-prefix-2.txt
    llvm/trunk/test/FileCheck/check-dag-multi-prefix.txt
    llvm/trunk/test/FileCheck/check-dag-substring-prefix.txt
    llvm/trunk/test/FileCheck/check-multi-prefix-label.txt
    llvm/trunk/test/FileCheck/check-multiple-prefixes-mixed.txt
    llvm/trunk/test/FileCheck/check-substring-multi-prefix-2.txt
    llvm/trunk/test/FileCheck/check-substring-multi-prefix.txt
    llvm/trunk/test/FileCheck/first-character-match.txt
    llvm/trunk/test/FileCheck/multiple-missing-prefixes.txt
    llvm/trunk/test/FileCheck/separate-multi-prefix.txt
Modified:
    llvm/trunk/docs/CommandGuide/FileCheck.rst
    llvm/trunk/test/FileCheck/validate-check-prefix.txt
    llvm/trunk/utils/FileCheck/FileCheck.cpp

Modified: llvm/trunk/docs/CommandGuide/FileCheck.rst
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/CommandGuide/FileCheck.rst?rev=194343&r1=194342&r2=194343&view=diff
==============================================================================
--- llvm/trunk/docs/CommandGuide/FileCheck.rst (original)
+++ llvm/trunk/docs/CommandGuide/FileCheck.rst Sat Nov  9 20:04:09 2013
@@ -30,11 +30,13 @@ OPTIONS
 
 .. option:: --check-prefix prefix
 
- FileCheck searches the contents of ``match-filename`` for patterns to match.
- By default, these patterns are prefixed with "``CHECK:``".  If you'd like to
- use a different prefix (e.g. because the same input file is checking multiple
- different tool or options), the :option:`--check-prefix` argument allows you
- to specify a specific prefix to match.
+ FileCheck searches the contents of ``match-filename`` for patterns to
+ match.  By default, these patterns are prefixed with "``CHECK:``".
+ If you'd like to use a different prefix (e.g. because the same input
+ file is checking multiple different tool or options), the
+ :option:`--check-prefix` argument allows you to specify one or more
+ prefixes to match. Multiple prefixes are useful for tests which might
+ change for different run options, but most lines remain the same.
 
 .. option:: --input-file filename
 

Added: llvm/trunk/test/FileCheck/check-a-b-has-b.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/FileCheck/check-a-b-has-b.txt?rev=194343&view=auto
==============================================================================
--- llvm/trunk/test/FileCheck/check-a-b-has-b.txt (added)
+++ llvm/trunk/test/FileCheck/check-a-b-has-b.txt Sat Nov  9 20:04:09 2013
@@ -0,0 +1,5 @@
+; RUN: FileCheck -check-prefix=A -check-prefix=B -input-file %s %s
+
+this is the string to be matched
+
+; B-DAG: this is the string to be {{matched}}

Added: llvm/trunk/test/FileCheck/check-b-a-has-b.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/FileCheck/check-b-a-has-b.txt?rev=194343&view=auto
==============================================================================
--- llvm/trunk/test/FileCheck/check-b-a-has-b.txt (added)
+++ llvm/trunk/test/FileCheck/check-b-a-has-b.txt Sat Nov  9 20:04:09 2013
@@ -0,0 +1,5 @@
+; RUN: FileCheck -check-prefix=B -check-prefix=A -input-file %s %s
+
+this is the string to be matched
+
+; B-DAG: this is the string to be {{matched}}

Added: llvm/trunk/test/FileCheck/check-dag-multi-prefix-2.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/FileCheck/check-dag-multi-prefix-2.txt?rev=194343&view=auto
==============================================================================
--- llvm/trunk/test/FileCheck/check-dag-multi-prefix-2.txt (added)
+++ llvm/trunk/test/FileCheck/check-dag-multi-prefix-2.txt Sat Nov  9 20:04:09 2013
@@ -0,0 +1,7 @@
+; RUN: FileCheck -check-prefix=A -input-file %s %s
+
+this should be matched
+
+; B-DAG: foo
+
+; A-DAG: {{this}} should be matched

Added: llvm/trunk/test/FileCheck/check-dag-multi-prefix.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/FileCheck/check-dag-multi-prefix.txt?rev=194343&view=auto
==============================================================================
--- llvm/trunk/test/FileCheck/check-dag-multi-prefix.txt (added)
+++ llvm/trunk/test/FileCheck/check-dag-multi-prefix.txt Sat Nov  9 20:04:09 2013
@@ -0,0 +1,27 @@
+; RUN: FileCheck -check-prefix=A -check-prefix=B -input-file %s %s
+
+add r10, r1, r2
+add r11, r3, r4
+mul r5, r10, r11
+
+mul r11, r3, r4
+mul r10, r1, r2
+add r5, r10, r11
+
+add r11, r3, r4
+add r10, r1, r2
+mul r5, r10, r11
+
+; B-DAG: add [[REG1:r[0-9]+]], r1, r2
+; B-DAG: add [[REG2:r[0-9]+]], r3, r4
+; B: mul r5, [[REG1]], [[REG2]]
+
+; A-DAG: mul [[REG1:r[0-9]+]], r1, r2
+; A-DAG: mul [[REG2:r[0-9]+]], r3, r4
+; A: add r5, [[REG1]], [[REG2]]
+
+; B-DAG: add [[REG1:r[0-9]+]], r1, r2
+; B-DAG: add [[REG2:r[0-9]+]], r3, r4
+; B-NOT: xor
+; B-DAG: mul r5, [[REG1]], [[REG2]]
+

Added: llvm/trunk/test/FileCheck/check-dag-substring-prefix.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/FileCheck/check-dag-substring-prefix.txt?rev=194343&view=auto
==============================================================================
--- llvm/trunk/test/FileCheck/check-dag-substring-prefix.txt (added)
+++ llvm/trunk/test/FileCheck/check-dag-substring-prefix.txt Sat Nov  9 20:04:09 2013
@@ -0,0 +1,7 @@
+; RUN: not FileCheck -check-prefix=A -check-prefix=AA -input-file %s %s
+
+this is the string to be matched
+this should also be matched
+
+; BAA-DAG: this is the string to be {{matched}}
+; BAA-DAG: this should also be {{matched}}

Added: llvm/trunk/test/FileCheck/check-multi-prefix-label.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/FileCheck/check-multi-prefix-label.txt?rev=194343&view=auto
==============================================================================
--- llvm/trunk/test/FileCheck/check-multi-prefix-label.txt (added)
+++ llvm/trunk/test/FileCheck/check-multi-prefix-label.txt Sat Nov  9 20:04:09 2013
@@ -0,0 +1,6 @@
+// RUN: FileCheck -check-prefix=ONE -check-prefix=TWO -input-file %s %s
+
+foo
+bar
+; ONE-LABEL: {{f}}oo
+; TWO-NEXT: {{b}}ar

Added: llvm/trunk/test/FileCheck/check-multiple-prefixes-mixed.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/FileCheck/check-multiple-prefixes-mixed.txt?rev=194343&view=auto
==============================================================================
--- llvm/trunk/test/FileCheck/check-multiple-prefixes-mixed.txt (added)
+++ llvm/trunk/test/FileCheck/check-multiple-prefixes-mixed.txt Sat Nov  9 20:04:09 2013
@@ -0,0 +1,10 @@
+// RUN: FileCheck -check-prefix=B -check-prefix=BOTH -input-file %s %s
+// RUN: FileCheck -check-prefix=A -check-prefix=BOTH -input-file %s %s
+
+; A: {{a}}aaaaa
+; B: {{b}}bbbb
+; BOTH: {{q}}qqqqq
+aaaaaa
+bbbbb
+qqqqqq
+ccccc

Added: llvm/trunk/test/FileCheck/check-substring-multi-prefix-2.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/FileCheck/check-substring-multi-prefix-2.txt?rev=194343&view=auto
==============================================================================
--- llvm/trunk/test/FileCheck/check-substring-multi-prefix-2.txt (added)
+++ llvm/trunk/test/FileCheck/check-substring-multi-prefix-2.txt Sat Nov  9 20:04:09 2013
@@ -0,0 +1,11 @@
+; RUN: FileCheck -check-prefix=FOO -check-prefix=FOOBAR -check-prefix=BARFOO -input-file %s %s
+; RUN: FileCheck -check-prefix=FOOBAR -check-prefix=FOO -check-prefix=BARFOO -input-file %s %s
+; RUN: FileCheck -check-prefix=FOOBAR -check-prefix=BARFOO -check-prefix=FOO -input-file %s %s
+
+this is the match
+this is another
+
+FOO
+FOOBAR
+FOOBAR: this is the {{match}}
+BARFOO: this is {{another}}

Added: llvm/trunk/test/FileCheck/check-substring-multi-prefix.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/FileCheck/check-substring-multi-prefix.txt?rev=194343&view=auto
==============================================================================
--- llvm/trunk/test/FileCheck/check-substring-multi-prefix.txt (added)
+++ llvm/trunk/test/FileCheck/check-substring-multi-prefix.txt Sat Nov  9 20:04:09 2013
@@ -0,0 +1,9 @@
+// RUN: FileCheck -check-prefix=AAAOVERLAP -check-prefix=OVERLAP -input-file %s %s
+
+foo
+bar
+buzz
+
+OVERLAP: foo
+AAAOVERLAP: bar
+OVERLAP: buzz

Added: llvm/trunk/test/FileCheck/first-character-match.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/FileCheck/first-character-match.txt?rev=194343&view=auto
==============================================================================
--- llvm/trunk/test/FileCheck/first-character-match.txt (added)
+++ llvm/trunk/test/FileCheck/first-character-match.txt Sat Nov  9 20:04:09 2013
@@ -0,0 +1,2 @@
+RUN: FileCheck -check-prefix=RUN -input-file %s %s
+// Prefix is at the first character in the file. The run line then matches itself.

Added: llvm/trunk/test/FileCheck/multiple-missing-prefixes.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/FileCheck/multiple-missing-prefixes.txt?rev=194343&view=auto
==============================================================================
--- llvm/trunk/test/FileCheck/multiple-missing-prefixes.txt (added)
+++ llvm/trunk/test/FileCheck/multiple-missing-prefixes.txt Sat Nov  9 20:04:09 2013
@@ -0,0 +1,9 @@
+// RUN: FileCheck -check-prefix=ANOTHER-PREFIX -input-file %s %s
+// RUN: not FileCheck -check-prefix=PREFIX1 -check-prefix=PREFIX2 -input-file %s %s 2>&1 | FileCheck -strict-whitespace -check-prefix=CHECK-NONEXISTENT-PREFIX -check-prefix=ALSO-NONEXISTENT %s
+
+foobar
+; ANOTHER-PREFIX: foobar
+
+; We use regex to match the colon so that FileCheck won't think it is a check
+; prefix.
+; CHECK-NONEXISTENT-PREFIX: error: no check strings found with prefixes 'PREFIX1{{:}}', 'PREFIX2{{:}}'

Added: llvm/trunk/test/FileCheck/separate-multi-prefix.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/FileCheck/separate-multi-prefix.txt?rev=194343&view=auto
==============================================================================
--- llvm/trunk/test/FileCheck/separate-multi-prefix.txt (added)
+++ llvm/trunk/test/FileCheck/separate-multi-prefix.txt Sat Nov  9 20:04:09 2013
@@ -0,0 +1,7 @@
+// RUN: not FileCheck -check-prefix=SOMEPREFIX -input-file %s %s
+// RUN: FileCheck -check-prefix=ANOTHER -input-file %s %s
+
+asdf
+; SOMEPREFIX: {{t}}his_is_not_asdf
+; ANOTHER: {{a}}sdf
+

Modified: llvm/trunk/test/FileCheck/validate-check-prefix.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/FileCheck/validate-check-prefix.txt?rev=194343&r1=194342&r2=194343&view=diff
==============================================================================
--- llvm/trunk/test/FileCheck/validate-check-prefix.txt (original)
+++ llvm/trunk/test/FileCheck/validate-check-prefix.txt Sat Nov  9 20:04:09 2013
@@ -1,7 +1,9 @@
 // RUN: not FileCheck -check-prefix=A! -input-file %s %s 2>&1 | FileCheck -check-prefix=BAD_PREFIX %s
 // RUN: FileCheck -check-prefix=A1a-B_c -input-file %s %s
-
+// RUN: not FileCheck -check-prefix=REPEAT -check-prefix=REPEAT -input-file %s %s 2>&1 | FileCheck -check-prefix=BAD_PREFIX %s
+// RUN: not FileCheck -check-prefix=VALID -check-prefix=A! -input-file %s %s 2>&1 | FileCheck -check-prefix=BAD_PREFIX %s
 foobar
 ; A1a-B_c: foobar
 
-; BAD_PREFIX: Supplied check-prefix is invalid! Prefixes must start with a letter and contain only alphanumeric characters, hyphens and underscores
+; BAD_PREFIX: Supplied check-prefix is invalid! Prefixes must be
+  unique and start with a letter and contain only alphanumeric characters, hyphens and underscores

Modified: llvm/trunk/utils/FileCheck/FileCheck.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/FileCheck/FileCheck.cpp?rev=194343&r1=194342&r2=194343&view=diff
==============================================================================
--- llvm/trunk/utils/FileCheck/FileCheck.cpp (original)
+++ llvm/trunk/utils/FileCheck/FileCheck.cpp Sat Nov  9 20:04:09 2013
@@ -20,6 +20,7 @@
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringSet.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/PrettyStackTrace.h"
@@ -42,14 +43,16 @@ static cl::opt<std::string>
 InputFilename("input-file", cl::desc("File to check (defaults to stdin)"),
               cl::init("-"), cl::value_desc("filename"));
 
-static cl::opt<std::string>
-CheckPrefix("check-prefix", cl::init("CHECK"),
-            cl::desc("Prefix to use from check file (defaults to 'CHECK')"));
+static cl::list<std::string>
+CheckPrefixes("check-prefix",
+              cl::desc("Prefix to use from check file (defaults to 'CHECK')"));
 
 static cl::opt<bool>
 NoCanonicalizeWhiteSpace("strict-whitespace",
               cl::desc("Do not treat all horizontal whitespace as equivalent"));
 
+typedef cl::list<std::string>::const_iterator prefix_iterator;
+
 //===----------------------------------------------------------------------===//
 // Pattern Handling Code.
 //===----------------------------------------------------------------------===//
@@ -103,11 +106,15 @@ public:
   /// getLoc - Return the location in source code.
   SMLoc getLoc() const { return PatternLoc; }
 
-  /// ParsePattern - Parse the given string into the Pattern.  SM provides the
-  /// SourceMgr used for error reports, and LineNumber is the line number in
-  /// the input file from which the pattern string was read.
-  /// Returns true in case of an error, false otherwise.
-  bool ParsePattern(StringRef PatternStr, SourceMgr &SM, unsigned LineNumber);
+  /// ParsePattern - Parse the given string into the Pattern. Prefix provides
+  /// which prefix is being matched, SM provides the SourceMgr used for error
+  /// reports, and LineNumber is the line number in the input file from which
+  /// the pattern string was read.  Returns true in case of an error, false
+  /// otherwise.
+  bool ParsePattern(StringRef PatternStr,
+                    StringRef Prefix,
+                    SourceMgr &SM,
+                    unsigned LineNumber);
 
   /// Match - Match the pattern string against the input buffer Buffer.  This
   /// returns the position that is matched or npos if there is no match.  If
@@ -152,7 +159,9 @@ private:
 };
 
 
-bool Pattern::ParsePattern(StringRef PatternStr, SourceMgr &SM,
+bool Pattern::ParsePattern(StringRef PatternStr,
+                           StringRef Prefix,
+                           SourceMgr &SM,
                            unsigned LineNumber) {
   this->LineNumber = LineNumber;
   PatternLoc = SMLoc::getFromPointer(PatternStr.data());
@@ -166,7 +175,7 @@ bool Pattern::ParsePattern(StringRef Pat
   if (PatternStr.empty()) {
     SM.PrintMessage(PatternLoc, SourceMgr::DK_Error,
                     "found empty check string with prefix '" +
-                    CheckPrefix+":'");
+                    Prefix + ":'");
     return true;
   }
 
@@ -594,6 +603,9 @@ struct CheckString {
   /// Pat - The pattern to match.
   Pattern Pat;
 
+  /// Prefix - Which prefix name this check matched.
+  StringRef Prefix;
+
   /// Loc - The location in the match file that the check string was specified.
   SMLoc Loc;
 
@@ -606,8 +618,12 @@ struct CheckString {
   /// file).
   std::vector<Pattern> DagNotStrings;
 
-  CheckString(const Pattern &P, SMLoc L, Check::CheckType Ty)
-    : Pat(P), Loc(L), CheckTy(Ty) {}
+
+  CheckString(const Pattern &P,
+              StringRef S,
+              SMLoc L,
+              Check::CheckType Ty)
+    : Pat(P), Prefix(S), Loc(L), CheckTy(Ty) {}
 
   /// Check - Match check string and its "not strings" and/or "dag strings".
   size_t Check(const SourceMgr &SM, StringRef Buffer, bool IsLabelScanMode,
@@ -670,45 +686,157 @@ static bool IsPartOfWord(char c) {
   return (isalnum(c) || c == '-' || c == '_');
 }
 
-static Check::CheckType FindCheckType(StringRef &Buffer, StringRef Prefix) {
+// Get the size of the prefix extension.
+static size_t CheckTypeSize(Check::CheckType Ty) {
+  switch (Ty) {
+  case Check::CheckNone:
+    return 0;
+
+  case Check::CheckPlain:
+    return sizeof(":") - 1;
+
+  case Check::CheckNext:
+    return sizeof("-NEXT:") - 1;
+
+  case Check::CheckNot:
+    return sizeof("-NOT:") - 1;
+
+  case Check::CheckDAG:
+    return sizeof("-DAG:") - 1;
+
+  case Check::CheckLabel:
+    return sizeof("-LABEL:") - 1;
+
+  case Check::CheckEOF:
+    llvm_unreachable("Should not be using EOF size");
+  }
+
+  llvm_unreachable("Bad check type");
+}
+
+static Check::CheckType FindCheckType(StringRef Buffer, StringRef Prefix) {
   char NextChar = Buffer[Prefix.size()];
 
   // Verify that the : is present after the prefix.
-  if (NextChar == ':') {
-    Buffer = Buffer.substr(Prefix.size() + 1);
+  if (NextChar == ':')
     return Check::CheckPlain;
-  }
 
-  if (NextChar != '-') {
-    Buffer = Buffer.drop_front(1);
+  if (NextChar != '-')
     return Check::CheckNone;
-  }
 
   StringRef Rest = Buffer.drop_front(Prefix.size() + 1);
-  if (Rest.startswith("NEXT:")) {
-    Buffer = Rest.drop_front(sizeof("NEXT:") - 1);
+  if (Rest.startswith("NEXT:"))
     return Check::CheckNext;
-  }
 
-  if (Rest.startswith("NOT:")) {
-    Buffer = Rest.drop_front(sizeof("NOT:") - 1);
+  if (Rest.startswith("NOT:"))
     return Check::CheckNot;
-  }
 
-  if (Rest.startswith("DAG:")) {
-    Buffer = Rest.drop_front(sizeof("DAG:") - 1);
+  if (Rest.startswith("DAG:"))
     return Check::CheckDAG;
-  }
 
-  if (Rest.startswith("LABEL:")) {
-    Buffer = Rest.drop_front(sizeof("LABEL:") - 1);
+  if (Rest.startswith("LABEL:"))
     return Check::CheckLabel;
-  }
 
-  Buffer = Buffer.drop_front(1);
   return Check::CheckNone;
 }
 
+// From the given position, find the next character after the word.
+static size_t SkipWord(StringRef Str, size_t Loc) {
+  while (Loc < Str.size() && IsPartOfWord(Str[Loc]))
+    ++Loc;
+  return Loc;
+}
+
+// Try to find the first match in buffer for any prefix. If a valid match is
+// found, return that prefix and set its type and location.  If there are almost
+// matches (e.g. the actual prefix string is found, but is not an actual check
+// string), but no valid match, return an empty string and set the position to
+// resume searching from. If no partial matches are found, return an empty
+// string and the location will be StringRef::npos. If one prefix is a substring
+// of another, the maximal match should be found. e.g. if "A" and "AA" are
+// prefixes then AA-CHECK: should match the second one.
+static StringRef FindFirstCandidateMatch(StringRef &Buffer,
+                                         Check::CheckType &CheckTy,
+                                         size_t &CheckLoc) {
+  StringRef FirstPrefix;
+  size_t FirstLoc = StringRef::npos;
+  size_t SearchLoc = StringRef::npos;
+  Check::CheckType FirstTy = Check::CheckNone;
+
+  CheckTy = Check::CheckNone;
+  CheckLoc = StringRef::npos;
+
+  for (prefix_iterator I = CheckPrefixes.begin(), E = CheckPrefixes.end();
+       I != E; ++I) {
+    StringRef Prefix(*I);
+    size_t PrefixLoc = Buffer.find(Prefix);
+
+    if (PrefixLoc == StringRef::npos)
+      continue;
+
+    // Track where we are searching for invalid prefixes that look almost right.
+    // We need to only advance to the first partial match on the next attempt
+    // since a partial match could be a substring of a later, valid prefix.
+    // Need to skip to the end of the word, otherwise we could end up
+    // matching a prefix in a substring later.
+    if (PrefixLoc < SearchLoc)
+      SearchLoc = SkipWord(Buffer, PrefixLoc);
+
+    // We only want to find the first match to avoid skipping some.
+    if (PrefixLoc > FirstLoc)
+      continue;
+
+    StringRef Rest = Buffer.drop_front(PrefixLoc);
+    // Make sure we have actually found the prefix, and not a word containing
+    // it. This should also prevent matching the wrong prefix when one is a
+    // substring of another.
+    if (PrefixLoc != 0 && IsPartOfWord(Buffer[PrefixLoc - 1]))
+      continue;
+
+    Check::CheckType Ty = FindCheckType(Rest, Prefix);
+    if (Ty == Check::CheckNone)
+      continue;
+
+    FirstLoc = PrefixLoc;
+    FirstTy = Ty;
+    FirstPrefix = Prefix;
+  }
+
+  if (FirstPrefix.empty()) {
+    CheckLoc = SearchLoc;
+  } else {
+    CheckTy = FirstTy;
+    CheckLoc = FirstLoc;
+  }
+
+  return FirstPrefix;
+}
+
+static StringRef FindFirstMatchingPrefix(StringRef &Buffer,
+                                         unsigned &LineNumber,
+                                         Check::CheckType &CheckTy,
+                                         size_t &CheckLoc) {
+  while (!Buffer.empty()) {
+    StringRef Prefix = FindFirstCandidateMatch(Buffer, CheckTy, CheckLoc);
+    // If we found a real match, we are done.
+    if (!Prefix.empty()) {
+      LineNumber += Buffer.substr(0, CheckLoc).count('\n');
+      return Prefix;
+    }
+
+    // We didn't find any almost matches either, we are also done.
+    if (CheckLoc == StringRef::npos)
+      return StringRef();
+
+    LineNumber += Buffer.substr(0, CheckLoc + 1).count('\n');
+
+    // Advance to the last possible match we found and try again.
+    Buffer = Buffer.drop_front(CheckLoc + 1);
+  }
+
+  return StringRef();
+}
+
 /// ReadCheckFile - Read the check file, which specifies the sequence of
 /// expected strings.  The strings are added to the CheckStrings vector.
 /// Returns true in case of an error, false otherwise.
@@ -738,32 +866,24 @@ static bool ReadCheckFile(SourceMgr &SM,
   unsigned LineNumber = 1;
 
   while (1) {
-    // See if Prefix occurs in the memory buffer.
-    size_t PrefixLoc = Buffer.find(CheckPrefix);
-    // If we didn't find a match, we're done.
-    if (PrefixLoc == StringRef::npos)
+    Check::CheckType CheckTy;
+    size_t PrefixLoc;
+
+    // See if a prefix occurs in the memory buffer.
+    StringRef UsedPrefix = FindFirstMatchingPrefix(Buffer,
+                                                   LineNumber,
+                                                   CheckTy,
+                                                   PrefixLoc);
+    if (UsedPrefix.empty())
       break;
 
-    LineNumber += Buffer.substr(0, PrefixLoc).count('\n');
+    Buffer = Buffer.drop_front(PrefixLoc);
 
-    // Keep the charcter before our prefix so we can validate that we have
-    // found our prefix, and account for cases when PrefixLoc is 0.
-    Buffer = Buffer.substr(std::min(PrefixLoc-1, PrefixLoc));
-
-    const char *CheckPrefixStart = Buffer.data() + (PrefixLoc == 0 ? 0 : 1);
-
-    // Make sure we have actually found our prefix, and not a word containing
-    // our prefix.
-    if (PrefixLoc != 0 && IsPartOfWord(Buffer[0])) {
-      Buffer = Buffer.substr(CheckPrefix.size());
-      continue;
-    }
+    // Location to use for error messages.
+    const char *UsedPrefixStart = Buffer.data() + (PrefixLoc == 0 ? 0 : 1);
 
-    // When we find a check prefix, keep track of what kind of type of CHECK we
-    // have.
-    Check::CheckType CheckTy = FindCheckType(Buffer, CheckPrefix);
-    if (CheckTy == Check::CheckNone)
-      continue;
+    // PrefixLoc is to the start of the prefix. Skip to the end.
+    Buffer = Buffer.drop_front(UsedPrefix.size() + CheckTypeSize(CheckTy));
 
     // Okay, we found the prefix, yay. Remember the rest of the line, but ignore
     // leading and trailing whitespace.
@@ -777,15 +897,15 @@ static bool ReadCheckFile(SourceMgr &SM,
 
     // Parse the pattern.
     Pattern P(CheckTy);
-    if (P.ParsePattern(Buffer.substr(0, EOL), SM, LineNumber))
+    if (P.ParsePattern(Buffer.substr(0, EOL), UsedPrefix, SM, LineNumber))
       return true;
 
     // Verify that CHECK-LABEL lines do not define or use variables
     if ((CheckTy == Check::CheckLabel) && P.hasVariable()) {
-      SM.PrintMessage(SMLoc::getFromPointer(CheckPrefixStart),
+      SM.PrintMessage(SMLoc::getFromPointer(UsedPrefixStart),
                       SourceMgr::DK_Error,
-                      "found '"+CheckPrefix+"-LABEL:' with variable definition"
-                      " or use");
+                      "found '" + UsedPrefix + "-LABEL:'"
+                      " with variable definition or use");
       return true;
     }
 
@@ -793,10 +913,10 @@ static bool ReadCheckFile(SourceMgr &SM,
 
     // Verify that CHECK-NEXT lines have at least one CHECK line before them.
     if ((CheckTy == Check::CheckNext) && CheckStrings.empty()) {
-      SM.PrintMessage(SMLoc::getFromPointer(CheckPrefixStart),
+      SM.PrintMessage(SMLoc::getFromPointer(UsedPrefixStart),
                       SourceMgr::DK_Error,
-                      "found '"+CheckPrefix+"-NEXT:' without previous '"+
-                      CheckPrefix+ ": line");
+                      "found '" + UsedPrefix + "-NEXT:' without previous '"
+                      + UsedPrefix + ": line");
       return true;
     }
 
@@ -808,22 +928,33 @@ static bool ReadCheckFile(SourceMgr &SM,
 
     // Okay, add the string we captured to the output vector and move on.
     CheckStrings.push_back(CheckString(P,
+                                       UsedPrefix,
                                        PatternLoc,
                                        CheckTy));
     std::swap(DagNotMatches, CheckStrings.back().DagNotStrings);
   }
 
-  // Add an EOF pattern for any trailing CHECK-DAG/-NOTs.
+  // Add an EOF pattern for any trailing CHECK-DAG/-NOTs, and use the first
+  // prefix as a filler for the error message.
   if (!DagNotMatches.empty()) {
     CheckStrings.push_back(CheckString(Pattern(Check::CheckEOF),
+                                       CheckPrefixes[0],
                                        SMLoc::getFromPointer(Buffer.data()),
                                        Check::CheckEOF));
     std::swap(DagNotMatches, CheckStrings.back().DagNotStrings);
   }
 
   if (CheckStrings.empty()) {
-    errs() << "error: no check strings found with prefix '" << CheckPrefix
-           << ":'\n";
+    errs() << "error: no check strings found with prefix"
+           << (CheckPrefixes.size() > 1 ? "es " : " ");
+    for (size_t I = 0, N = CheckPrefixes.size(); I != N; ++I) {
+      StringRef Prefix(CheckPrefixes[I]);
+      errs() << '\'' << Prefix << ":'";
+      if (I != N - 1)
+        errs() << ", ";
+    }
+
+    errs() << '\n';
     return true;
   }
 
@@ -933,7 +1064,7 @@ bool CheckString::CheckNext(const Source
   unsigned NumNewLines = CountNumNewlinesBetween(Buffer);
 
   if (NumNewLines == 0) {
-    SM.PrintMessage(Loc, SourceMgr::DK_Error, CheckPrefix+
+    SM.PrintMessage(Loc, SourceMgr::DK_Error, Prefix +
                     "-NEXT: is on the same line as previous match");
     SM.PrintMessage(SMLoc::getFromPointer(Buffer.end()),
                     SourceMgr::DK_Note, "'next' match was here");
@@ -943,7 +1074,7 @@ bool CheckString::CheckNext(const Source
   }
 
   if (NumNewLines != 1) {
-    SM.PrintMessage(Loc, SourceMgr::DK_Error, CheckPrefix+
+    SM.PrintMessage(Loc, SourceMgr::DK_Error, Prefix +
                     "-NEXT: is not on the line after the previous match");
     SM.PrintMessage(SMLoc::getFromPointer(Buffer.end()),
                     SourceMgr::DK_Note, "'next' match was here");
@@ -970,9 +1101,9 @@ bool CheckString::CheckNot(const SourceM
 
     SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()+Pos),
                     SourceMgr::DK_Error,
-                    CheckPrefix+"-NOT: string occurred!");
+                    Prefix + "-NOT: string occurred!");
     SM.PrintMessage(Pat->getLoc(), SourceMgr::DK_Note,
-                    CheckPrefix+"-NOT: pattern specified here");
+                    Prefix + "-NOT: pattern specified here");
     return true;
   }
 
@@ -1022,17 +1153,17 @@ size_t CheckString::CheckDag(const Sourc
         // Reordered?
         SM.PrintMessage(SMLoc::getFromPointer(Buffer.data() + MatchPos),
                         SourceMgr::DK_Error,
-                        CheckPrefix+"-DAG: found a match of CHECK-DAG"
+                        Prefix + "-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"
+                        Prefix + "-DAG: the farthest match of CHECK-DAG"
                         " is found here");
         SM.PrintMessage(NotStrings[0]->getLoc(), SourceMgr::DK_Note,
-                        CheckPrefix+"-NOT: the crossed pattern specified"
+                        Prefix + "-NOT: the crossed pattern specified"
                         " here");
         SM.PrintMessage(Pat.getLoc(), SourceMgr::DK_Note,
-                        CheckPrefix+"-DAG: the reordered pattern specified"
+                        Prefix + "-DAG: the reordered pattern specified"
                         " here");
         return StringRef::npos;
       }
@@ -1056,10 +1187,34 @@ size_t CheckString::CheckDag(const Sourc
   return LastPos;
 }
 
-bool ValidateCheckPrefix() {
-  // The check prefix must contain only alphanumeric, hyphens and underscores.
-  Regex prefixValidator("^[a-zA-Z0-9_-]*$");
-  return prefixValidator.match(CheckPrefix);
+// A check prefix must contain only alphanumeric, hyphens and underscores.
+static bool ValidateCheckPrefix(StringRef CheckPrefix) {
+  Regex Validator("^[a-zA-Z0-9_-]*$");
+  return Validator.match(CheckPrefix);
+}
+
+static bool ValidateCheckPrefixes() {
+  StringSet<> PrefixSet;
+
+  for (prefix_iterator I = CheckPrefixes.begin(), E = CheckPrefixes.end();
+       I != E; ++I) {
+    StringRef Prefix(*I);
+
+    if (!PrefixSet.insert(Prefix))
+      return false;
+
+    if (!ValidateCheckPrefix(Prefix))
+      return false;
+  }
+
+  return true;
+}
+
+// I don't think there's a way to specify an initial value for cl::list,
+// so if nothing was specified, add the default
+static void AddCheckPrefixIfNeeded() {
+  if (CheckPrefixes.empty())
+    CheckPrefixes.push_back("CHECK");
 }
 
 int main(int argc, char **argv) {
@@ -1067,13 +1222,15 @@ int main(int argc, char **argv) {
   PrettyStackTraceProgram X(argc, argv);
   cl::ParseCommandLineOptions(argc, argv);
 
-  if (!ValidateCheckPrefix()) {
-    errs() << "Supplied check-prefix is invalid! Prefixes must start with a "
-              "letter and contain only alphanumeric characters, hyphens and "
-              "underscores\n";
+  if (!ValidateCheckPrefixes()) {
+    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;
   }
 
+  AddCheckPrefixIfNeeded();
+
   SourceMgr SM;
 
   // Read the expected strings from the check file.





More information about the llvm-commits mailing list