summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Lattner <sabre@nondot.org>2009-08-15 18:32:21 +0000
committerChris Lattner <sabre@nondot.org>2009-08-15 18:32:21 +0000
commit5dafafdeb4d89b37c6b7efbeabaa7d818c7023fe (patch)
tree30f0d5d6a4ac953cef5b24c01edfe524618157d5
parent16b794d25accbc4c5db63bb4d172049f052f0a55 (diff)
downloadllvm-5dafafdeb4d89b37c6b7efbeabaa7d818c7023fe.tar.gz
llvm-5dafafdeb4d89b37c6b7efbeabaa7d818c7023fe.tar.bz2
llvm-5dafafdeb4d89b37c6b7efbeabaa7d818c7023fe.tar.xz
implement support for CHECK-NEXT: in filecheck.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@79123 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--docs/TestingGuide.html43
-rw-r--r--test/CodeGen/X86/sse2.ll20
-rw-r--r--utils/FileCheck/FileCheck.cpp131
3 files changed, 157 insertions, 37 deletions
diff --git a/docs/TestingGuide.html b/docs/TestingGuide.html
index 38e9d19fde..990dcee207 100644
--- a/docs/TestingGuide.html
+++ b/docs/TestingGuide.html
@@ -518,14 +518,18 @@ is a "subl" in between those labels. If it existed somewhere else in the file,
that would not count: "grep subl" matches if subl exists anywhere in the
file.</p>
+</div>
+
+<!-- _______________________________________________________________________ -->
<div class="doc_subsubsection"><a
name="FileCheck-check-prefix">The FileCheck -check-prefix option</a></div>
+<div class="doc_text">
+
<p>The FileCheck -check-prefix option allows multiple test configurations to be
driven from one .ll file. This is useful in many circumstances, for example,
testing different architectural variants with llc. Here's a simple example:</p>
-
<div class="doc_code">
<pre>
; RUN: llvm-as &lt; %s | llc -mtriple=i686-apple-darwin9 -mattr=sse41 \
@@ -548,6 +552,43 @@ define &lt;4 x i32&gt; @pinsrd_1(i32 %s, &lt;4 x i32&gt; %tmp) nounwind {
<p>In this case, we're testing that we get the expected code generation with
both 32-bit and 64-bit code generation.</p>
+</div>
+
+<!-- _______________________________________________________________________ -->
+<div class="doc_subsubsection"><a
+name="FileCheck-CHECK-NEXT">The "CHECK-NEXT:" directive</a></div>
+
+<div class="doc_text">
+
+<p>Sometimes you want to match lines and would like to verify that matches
+happen on exactly consequtive lines with no other lines in between them. In
+this case, you can use CHECK: and CHECK-NEXT: directives to specify this. If
+you specified a custom check prefix, just use "&lt;PREFIX&gt;-NEXT:". For
+example, something like this works as you'd expect:</p>
+
+<div class="doc_code">
+<pre>
+define void @t2(&lt;2 x double&gt;* %r, &lt;2 x double&gt;* %A, double %B) nounwind {
+ %tmp3 = load &lt;2 x double&gt;* %A, align 16
+ %tmp7 = insertelement &lt;2 x double&gt; undef, double %B, i32 0
+ %tmp9 = shufflevector &lt;2 x double&gt; %tmp3, &lt;2 x double&gt; %tmp7, &lt;2 x i32&gt; &lt; i32 0, i32 2 &gt;
+ store &lt;2 x double&gt; %tmp9, &lt;2 x double&gt;* %r, align 16
+ ret void
+
+; <b>CHECK:</b> t2:
+; <b>CHECK:</b> movl 8(%esp), %eax
+; <b>CHECK-NEXT:</b> movapd (%eax), %xmm0
+; <b>CHECK-NEXT:</b> movhpd 12(%esp), %xmm0
+; <b>CHECK-NEXT:</b> movl 4(%esp), %eax
+; <b>CHECK-NEXT:</b> movapd %xmm0, (%eax)
+; <b>CHECK-NEXT:</b> ret
+}
+</pre>
+</div>
+
+<p>CHECK-NEXT: directives reject the input unless there is exactly one newline
+between it an the previous directive. A CHECK-NEXT cannot be the first
+directive in a file.</p>
</div>
diff --git a/test/CodeGen/X86/sse2.ll b/test/CodeGen/X86/sse2.ll
index 463df30a6f..da1ec37541 100644
--- a/test/CodeGen/X86/sse2.ll
+++ b/test/CodeGen/X86/sse2.ll
@@ -10,11 +10,11 @@ define void @t1(<2 x double>* %r, <2 x double>* %A, double %B) nounwind {
; CHECK: t1:
; CHECK: movl 8(%esp), %eax
-; CHECK: movapd (%eax), %xmm0
-; CHECK: movlpd 12(%esp), %xmm0
-; CHECK: movl 4(%esp), %eax
-; CHECK: movapd %xmm0, (%eax)
-; CHECK: ret
+; CHECK-NEXT: movapd (%eax), %xmm0
+; CHECK-NEXT: movlpd 12(%esp), %xmm0
+; CHECK-NEXT: movl 4(%esp), %eax
+; CHECK-NEXT: movapd %xmm0, (%eax)
+; CHECK-NEXT: ret
}
define void @t2(<2 x double>* %r, <2 x double>* %A, double %B) nounwind {
@@ -26,9 +26,9 @@ define void @t2(<2 x double>* %r, <2 x double>* %A, double %B) nounwind {
; CHECK: t2:
; CHECK: movl 8(%esp), %eax
-; CHECK: movapd (%eax), %xmm0
-; CHECK: movhpd 12(%esp), %xmm0
-; CHECK: movl 4(%esp), %eax
-; CHECK: movapd %xmm0, (%eax)
-; CHECK: ret
+; CHECK-NEXT: movapd (%eax), %xmm0
+; CHECK-NEXT: movhpd 12(%esp), %xmm0
+; CHECK-NEXT: movl 4(%esp), %eax
+; CHECK-NEXT: movapd %xmm0, (%eax)
+; CHECK-NEXT: ret
}
diff --git a/utils/FileCheck/FileCheck.cpp b/utils/FileCheck/FileCheck.cpp
index 986c7838a0..f051e9e7e0 100644
--- a/utils/FileCheck/FileCheck.cpp
+++ b/utils/FileCheck/FileCheck.cpp
@@ -47,7 +47,12 @@ struct CheckString {
/// Loc - The location in the match file that the check string was specified.
SMLoc Loc;
- CheckString(const std::string &S, SMLoc L) : Str(S), Loc(L) {}
+ /// IsCheckNext - This is true if this is a CHECK-NEXT: directive (as opposed
+ /// to a CHECK: directive.
+ bool IsCheckNext;
+
+ CheckString(const std::string &S, SMLoc L, bool isCheckNext)
+ : Str(S), Loc(L), IsCheckNext(isCheckNext) {}
};
@@ -106,16 +111,27 @@ static bool ReadCheckFile(SourceMgr &SM,
if (Ptr == BufferEnd)
break;
+ const char *CheckPrefixStart = Ptr;
+
+ // When we find a check prefix, keep track of whether we find CHECK: or
+ // CHECK-NEXT:
+ bool IsCheckNext;
+
// Verify that the : is present after the prefix.
- if (Ptr[CheckPrefix.size()] != ':') {
+ if (Ptr[CheckPrefix.size()] == ':') {
+ Ptr += CheckPrefix.size()+1;
+ IsCheckNext = false;
+ } else if (BufferEnd-Ptr > 6 &&
+ memcmp(Ptr+CheckPrefix.size(), "-NEXT:", 6) == 0) {
+ Ptr += CheckPrefix.size()+7;
+ IsCheckNext = true;
+ } else {
CurPtr = Ptr+1;
continue;
}
// Okay, we found the prefix, yay. Remember the rest of the line, but
// ignore leading and trailing whitespace.
- Ptr += CheckPrefix.size()+1;
-
while (*Ptr == ' ' || *Ptr == '\t')
++Ptr;
@@ -136,9 +152,18 @@ static bool ReadCheckFile(SourceMgr &SM,
return true;
}
+ // Verify that CHECK-NEXT lines have at least one CHECK line before them.
+ if (IsCheckNext && CheckStrings.empty()) {
+ SM.PrintMessage(SMLoc::getFromPointer(CheckPrefixStart),
+ "found '"+CheckPrefix+"-NEXT:' without previous '"+
+ CheckPrefix+ ": line", "error");
+ return true;
+ }
+
// Okay, add the string we captured to the output vector and move on.
CheckStrings.push_back(CheckString(std::string(Ptr, CurPtr),
- SMLoc::getFromPointer(Ptr)));
+ SMLoc::getFromPointer(Ptr),
+ IsCheckNext));
}
if (CheckStrings.empty()) {
@@ -204,6 +229,45 @@ static MemoryBuffer *CanonicalizeInputFile(MemoryBuffer *MB) {
}
+static void PrintCheckFailed(const SourceMgr &SM, const CheckString &CheckStr,
+ const char *CurPtr, const char *BufferEnd) {
+ // Otherwise, we have an error, emit an error message.
+ SM.PrintMessage(CheckStr.Loc, "expected string not found in input",
+ "error");
+
+ // Print the "scanning from here" line. If the current position is at the
+ // end of a line, advance to the start of the next line.
+ const char *Scan = CurPtr;
+ while (Scan != BufferEnd &&
+ (*Scan == ' ' || *Scan == '\t'))
+ ++Scan;
+ if (*Scan == '\n' || *Scan == '\r')
+ CurPtr = Scan+1;
+
+
+ SM.PrintMessage(SMLoc::getFromPointer(CurPtr), "scanning from here",
+ "note");
+}
+
+static unsigned CountNumNewlinesBetween(const char *Start, const char *End) {
+ unsigned NumNewLines = 0;
+ for (; Start != End; ++Start) {
+ // Scan for newline.
+ if (Start[0] != '\n' && Start[0] != '\r')
+ continue;
+
+ ++NumNewLines;
+
+ // Handle \n\r and \r\n as a single newline.
+ if (Start+1 != End &&
+ (Start[0] == '\n' || Start[0] == '\r') &&
+ (Start[0] != Start[1]))
+ ++Start;
+ }
+
+ return NumNewLines;
+}
+
int main(int argc, char **argv) {
sys::PrintStackTraceOnErrorSignal();
PrettyStackTraceProgram X(argc, argv);
@@ -240,35 +304,50 @@ int main(int argc, char **argv) {
// file.
const char *CurPtr = F->getBufferStart(), *BufferEnd = F->getBufferEnd();
+ const char *LastMatch = 0;
for (unsigned StrNo = 0, e = CheckStrings.size(); StrNo != e; ++StrNo) {
const CheckString &CheckStr = CheckStrings[StrNo];
// Find StrNo in the file.
const char *Ptr = FindFixedStringInBuffer(CheckStr.Str, CurPtr, *F);
- // If we found a match, we're done, move on.
- if (Ptr != BufferEnd) {
- CurPtr = Ptr + CheckStr.Str.size();
- continue;
+ // If we didn't find a match, reject the input.
+ if (Ptr == BufferEnd) {
+ PrintCheckFailed(SM, CheckStr, CurPtr, BufferEnd);
+ return 1;
}
- // Otherwise, we have an error, emit an error message.
- SM.PrintMessage(CheckStr.Loc, "expected string not found in input",
- "error");
-
- // Print the "scanning from here" line. If the current position is at the
- // end of a line, advance to the start of the next line.
- const char *Scan = CurPtr;
- while (Scan != BufferEnd &&
- (*Scan == ' ' || *Scan == '\t'))
- ++Scan;
- if (*Scan == '\n' || *Scan == '\r')
- CurPtr = Scan+1;
-
-
- SM.PrintMessage(SMLoc::getFromPointer(CurPtr), "scanning from here",
- "note");
- return 1;
+ // 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).
+ if (CheckStr.IsCheckNext) {
+ // Count the number of newlines between the previous match and this one.
+ assert(LastMatch && "CHECK-NEXT can't be the first check in a file");
+
+ unsigned NumNewLines = CountNumNewlinesBetween(LastMatch, Ptr);
+ if (NumNewLines == 0) {
+ SM.PrintMessage(SMLoc::getFromPointer(Ptr),
+ CheckPrefix+"-NEXT: is on the same line as previous match",
+ "error");
+ SM.PrintMessage(SMLoc::getFromPointer(LastMatch),
+ "previous match was here", "note");
+ return 1;
+ }
+
+ if (NumNewLines != 1) {
+ SM.PrintMessage(SMLoc::getFromPointer(Ptr),
+ CheckPrefix+
+ "-NEXT: is not on the line after the previous match",
+ "error");
+ SM.PrintMessage(SMLoc::getFromPointer(LastMatch),
+ "previous match was here", "note");
+ return 1;
+ }
+ }
+
+ // Otherwise, everything is good. Remember this as the last match and move
+ // on to the next one.
+ LastMatch = Ptr;
+ CurPtr = Ptr + CheckStr.Str.size();
}
return 0;