[llvm] r337605 - [FileCheck] Fix search ranges for DAG-NOT-DAG

Joel E. Denny via llvm-commits llvm-commits at lists.llvm.org
Fri Jul 20 13:09:56 PDT 2018


Author: jdenny
Date: Fri Jul 20 13:09:56 2018
New Revision: 337605

URL: http://llvm.org/viewvc/llvm-project?rev=337605&view=rev
Log:
[FileCheck] Fix search ranges for DAG-NOT-DAG

A DAG-NOT-DAG is a CHECK-DAG group, X, followed by a CHECK-NOT group,
N, followed by a CHECK-DAG group, Y.  Let y be the initial directive
of Y.  This patch makes the following changes to the behavior:

    1. Directives in N can no longer match within part of Y's match
       range just because y happens not to be the earliest match from
       Y.  Specifically, this patch withdraws N's search range end
       from y's match range start to Y's match range start.

    2. y can no longer match within X's match range, where a y match
       produced a reordering complaint, which is thus no longer
       possible.  Specifically, this patch withdraws y's search range
       start from X's permitted range start to X's match range end,
       which was already the search range start for other members of
       Y.

Both of these changes can only increase the number of test passes: #1
constrains the ability of CHECK-NOTs to match, and #2 expands the
ability of CHECK-DAGs to match without complaints.

These changes are based on discussions at:

   <http://lists.llvm.org/pipermail/llvm-dev/2018-May/123550.html>
   <https://reviews.llvm.org/D47106>

which conclude that:

    1. These changes simplify the FileCheck conceptual model.  First,
       it makes search ranges for DAG-NOT-DAG more consistent with
       other cases.  Second, it was confusing that y was treated
       differently from the rest of Y.

    2. These changes add theoretical use cases for DAG-NOT-DAG that
       had no obvious means to be expressed otherwise.  We can justify
       the first half of this assertion with the observation that
       these changes can only increase the number of test passes.

    3. Reordering detection for DAG-NOT-DAG had no obvious real
       benefit.

We don't have evidence from real uses cases to help us debate
conclusions #2 and #3, but #1 at least seems intuitive.

Reviewed By: probinson

Differential Revision: https://reviews.llvm.org/D48986

Added:
    llvm/trunk/test/FileCheck/check-dag-not-dag.txt
Modified:
    llvm/trunk/test/FileCheck/check-dag-overlap.txt
    llvm/trunk/utils/FileCheck/FileCheck.cpp

Added: llvm/trunk/test/FileCheck/check-dag-not-dag.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/FileCheck/check-dag-not-dag.txt?rev=337605&view=auto
==============================================================================
--- llvm/trunk/test/FileCheck/check-dag-not-dag.txt (added)
+++ llvm/trunk/test/FileCheck/check-dag-not-dag.txt Fri Jul 20 13:09:56 2018
@@ -0,0 +1,76 @@
+;---------------------------------------------------------------------
+; RUN: FileCheck -input-file %s %s -check-prefix=NotSearchEnd
+
+The search range for the NOTs used to end at the start of the match range for
+the first DAG in the following DAG group.  Now it ends at the start of the
+match range for the entire following DAG group.
+
+__NotSearchEnd
+x0
+x1
+
+y1
+foobar
+y0
+
+z2
+foobar
+z1
+foobar
+z0
+__NotSearchEnd
+
+; NotSearchEnd:     {{^}}__NotSearchEnd
+; NotSearchEnd-DAG: {{^}}x0
+; NotSearchEnd-DAG: {{^}}x1
+; NotSearchEnd-NOT: {{^}}foobar
+; NotSearchEnd-DAG: {{^}}y0
+; NotSearchEnd-DAG: {{^}}y1
+; NotSearchEnd-NOT: {{^}}foobar
+; NotSearchEnd-DAG: {{^}}z0
+; NotSearchEnd-DAG: {{^}}z1
+; NotSearchEnd-DAG: {{^}}z2
+; NotSearchEnd:     {{^}}__NotSearchEnd
+
+;---------------------------------------------------------------------
+; RUN: FileCheck -input-file %s %s -check-prefix=Dag2SearchStart
+
+The start of the search range for the second or later DAG group used to be
+different for its first DAG than its other DAGs.  For the first DAG, it was
+the start of the permitted range for the preceding DAG group, and there was a
+reordering complaint if the match range was in the first DAG group's match
+range.  For the other DAGs, it was the end of the match range for the
+preceding DAG group, so reordering detection wasn't possible.  Now, the
+first DAG behaves like the others, and so reordering detection is no longer
+implemented.  As a result, matches that used to produce the reordering
+complaint are now skipped, permitting later matches to succeed.
+
+__Dag2SearchStart
+y0
+y1
+x0
+y0
+y1
+x1
+
+z1
+z0
+y1
+z1
+z0
+y0
+
+z0
+z1
+__Dag2SearchStart
+
+; Dag2SearchStart:     {{^}}__Dag2SearchStart
+; Dag2SearchStart-DAG: {{^}}x0
+; Dag2SearchStart-DAG: {{^}}x1
+; Dag2SearchStart-NOT: {{^}}foobar
+; Dag2SearchStart-DAG: {{^}}y0
+; Dag2SearchStart-DAG: {{^}}y1
+; Dag2SearchStart-NOT: {{^}}foobar
+; Dag2SearchStart-DAG: {{^}}z0
+; Dag2SearchStart-DAG: {{^}}z1
+; Dag2SearchStart:     {{^}}__Dag2SearchStart
\ No newline at end of file

Modified: llvm/trunk/test/FileCheck/check-dag-overlap.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/FileCheck/check-dag-overlap.txt?rev=337605&r1=337604&r2=337605&view=diff
==============================================================================
--- llvm/trunk/test/FileCheck/check-dag-overlap.txt (original)
+++ llvm/trunk/test/FileCheck/check-dag-overlap.txt Fri Jul 20 13:09:56 2018
@@ -168,7 +168,8 @@ Assume we have DAGs, NOTs, DAGs, NOTs, a
 the DAG groups such that the leading DAGs are x, y, and z.  y won't match
 overlaps with matches from:
 
-1. X.  Otherwise, we could get a spurious reordering complaint.
+1. X.  Otherwise, we used to get a spurious reordering complaint (back
+   when reordering complaints on DAG-NOT-DAG were still implemented).
 2. Y, because y is in Y.  To prevent these overlaps, the implementation must be
    careful not to drop y's match from the previous matches list when it drops
    matches from X to save search time.

Modified: llvm/trunk/utils/FileCheck/FileCheck.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/FileCheck/FileCheck.cpp?rev=337605&r1=337604&r2=337605&view=diff
==============================================================================
--- llvm/trunk/utils/FileCheck/FileCheck.cpp (original)
+++ llvm/trunk/utils/FileCheck/FileCheck.cpp Fri Jul 20 13:09:56 2018
@@ -1283,17 +1283,23 @@ size_t CheckString::CheckDag(const Sourc
   if (DagNotStrings.empty())
     return 0;
 
-  size_t LastPos = 0;
-  size_t StartPos = LastPos;
+  // The start of the search range.
+  size_t StartPos = 0;
 
-  // A sorted list of ranges for non-overlapping dag matches.
-  struct Match {
+  struct MatchRange {
     size_t Pos;
     size_t End;
   };
-  std::list<Match> Matches;
-
-  for (const Pattern &Pat : DagNotStrings) {
+  // A sorted list of ranges for non-overlapping CHECK-DAG matches.  Match
+  // ranges are erased from this list once they are no longer in the search
+  // range.
+  std::list<MatchRange> MatchRanges;
+
+  // We need PatItr and PatEnd later for detecting the end of a CHECK-DAG
+  // group, so we don't use a range-based for loop here.
+  for (auto PatItr = DagNotStrings.begin(), PatEnd = DagNotStrings.end();
+       PatItr != PatEnd; ++PatItr) {
+    const Pattern &Pat = *PatItr;
     assert((Pat.getCheckTy() == Check::CheckDAG ||
             Pat.getCheckTy() == Check::CheckNot) &&
            "Invalid CHECK-DAG or CHECK-NOT!");
@@ -1310,7 +1316,7 @@ size_t CheckString::CheckDag(const Sourc
 
     // Search for a match that doesn't overlap a previous match in this
     // CHECK-DAG group.
-    for (auto MI = Matches.begin(), ME = Matches.end(); true; ++MI) {
+    for (auto MI = MatchRanges.begin(), ME = MatchRanges.end(); true; ++MI) {
       StringRef MatchBuffer = Buffer.substr(MatchPos);
       size_t MatchPosBuf = Pat.Match(MatchBuffer, MatchLen, VariableTable);
       // With a group of CHECK-DAGs, a single mismatching means the match on
@@ -1325,10 +1331,21 @@ size_t CheckString::CheckDag(const Sourc
       if (VerboseVerbose)
         PrintMatch(true, SM, Prefix, Pat.getLoc(), Pat, Buffer, VariableTable,
                    MatchPos, MatchLen);
-      if (AllowDeprecatedDagOverlap)
+      MatchRange M{MatchPos, MatchPos + MatchLen};
+      if (AllowDeprecatedDagOverlap) {
+        // We don't need to track all matches in this mode, so we just maintain
+        // one match range that encompasses the current CHECK-DAG group's
+        // matches.
+        if (MatchRanges.empty())
+          MatchRanges.insert(MatchRanges.end(), M);
+        else {
+          auto Block = MatchRanges.begin();
+          Block->Pos = std::min(Block->Pos, M.Pos);
+          Block->End = std::max(Block->End, M.End);
+        }
         break;
+      }
       // Iterate previous matches until overlapping match or insertion point.
-      Match M{MatchPos, MatchPos + MatchLen};
       bool Overlap = false;
       for (; MI != ME; ++MI) {
         if (M.Pos < MI->End) {
@@ -1340,7 +1357,7 @@ size_t CheckString::CheckDag(const Sourc
       }
       if (!Overlap) {
         // Insert non-overlapping match into list.
-        Matches.insert(MI, M);
+        MatchRanges.insert(MI, M);
         break;
       }
       if (VerboseVerbose) {
@@ -1357,46 +1374,29 @@ size_t CheckString::CheckDag(const Sourc
       PrintMatch(true, SM, Prefix, Pat.getLoc(), Pat, Buffer, VariableTable,
                  MatchPos, MatchLen);
 
-    if (!NotStrings.empty()) {
-      if (MatchPos < LastPos) {
-        // Reordered?
-        SM.PrintMessage(SMLoc::getFromPointer(Buffer.data() + MatchPos),
-                        SourceMgr::DK_Error,
-                        Prefix + "-DAG: found a match of CHECK-DAG"
-                                 " reordering across a CHECK-NOT");
-        SM.PrintMessage(SMLoc::getFromPointer(Buffer.data() + LastPos),
-                        SourceMgr::DK_Note,
-                        Prefix + "-DAG: the farthest match of CHECK-DAG"
-                                 " is found here");
-        SM.PrintMessage(NotStrings[0]->getLoc(), SourceMgr::DK_Note,
-                        Prefix + "-NOT: the crossed pattern specified"
-                                 " here");
-        SM.PrintMessage(Pat.getLoc(), SourceMgr::DK_Note,
-                        Prefix + "-DAG: the reordered pattern specified"
-                                 " here");
-        return StringRef::npos;
+    // Handle the end of a CHECK-DAG group.
+    if (std::next(PatItr) == PatEnd ||
+        std::next(PatItr)->getCheckTy() == Check::CheckNot) {
+      if (!NotStrings.empty()) {
+        // If there are CHECK-NOTs between two CHECK-DAGs or from CHECK to
+        // CHECK-DAG, verify that there are no 'not' strings occurred in that
+        // region.
+        StringRef SkippedRegion =
+            Buffer.slice(StartPos, MatchRanges.begin()->Pos);
+        if (CheckNot(SM, SkippedRegion, NotStrings, VariableTable))
+          return StringRef::npos;
+        // Clear "not strings".
+        NotStrings.clear();
       }
-      // All subsequent CHECK-DAGs should be matched from the farthest
-      // position of all precedent CHECK-DAGs (not including this one).
-      StartPos = LastPos;
+      // All subsequent CHECK-DAGs and CHECK-NOTs should be matched from the
+      // end of this CHECK-DAG group's match range.
+      StartPos = MatchRanges.rbegin()->End;
       // Don't waste time checking for (impossible) overlaps before that.
-      Matches.clear();
-      Matches.push_back(Match{MatchPos, MatchPos + MatchLen});
-      // 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.slice(LastPos, MatchPos);
-      if (CheckNot(SM, SkippedRegion, NotStrings, VariableTable))
-        return StringRef::npos;
-      // Clear "not strings".
-      NotStrings.clear();
+      MatchRanges.clear();
     }
-
-    // Update the last position with CHECK-DAG matches.
-    LastPos = std::max(MatchPos + MatchLen, LastPos);
   }
 
-  return LastPos;
+  return StartPos;
 }
 
 // A check prefix must contain only alphanumeric, hyphens and underscores.




More information about the llvm-commits mailing list