From 5dafafdeb4d89b37c6b7efbeabaa7d818c7023fe Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Sat, 15 Aug 2009 18:32:21 +0000 Subject: [PATCH] implement support for CHECK-NEXT: in filecheck. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@79123 91177308-0d34-0410-b5e6-96231b3b80d8 --- docs/TestingGuide.html | 43 ++++++++++- test/CodeGen/X86/sse2.ll | 20 +++--- utils/FileCheck/FileCheck.cpp | 131 +++++++++++++++++++++++++++------- 3 files changed, 157 insertions(+), 37 deletions(-) diff --git a/docs/TestingGuide.html b/docs/TestingGuide.html index 38e9d19fde6..990dcee2079 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.

+ + +
The FileCheck -check-prefix option
+
+

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:

-
 ; RUN: llvm-as < %s | llc -mtriple=i686-apple-darwin9 -mattr=sse41 \
@@ -548,6 +552,43 @@ define <4 x i32> @pinsrd_1(i32 %s, <4 x i32> %tmp) nounwind {
 

In this case, we're testing that we get the expected code generation with both 32-bit and 64-bit code generation.

+
+ + + + +
+ +

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 "<PREFIX>-NEXT:". For +example, something like this works as you'd expect:

+ +
+
+define void @t2(<2 x double>* %r, <2 x double>* %A, double %B) nounwind  {
+	%tmp3 = load <2 x double>* %A, align 16
+	%tmp7 = insertelement <2 x double> undef, double %B, i32 0
+	%tmp9 = shufflevector <2 x double> %tmp3, <2 x double> %tmp7, <2 x i32> < i32 0, i32 2 >
+	store <2 x double> %tmp9, <2 x double>* %r, align 16
+	ret void
+        
+; CHECK: t2:
+; CHECK: 	movl	8(%esp), %eax
+; 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
+}
+
+
+ +

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.

diff --git a/test/CodeGen/X86/sse2.ll b/test/CodeGen/X86/sse2.ll index 463df30a6f0..da1ec375412 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 986c7838a07..f051e9e7e04 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;