implement support for CHECK-NEXT: in filecheck.

llvm-svn: 79123
This commit is contained in:
Chris Lattner 2009-08-15 18:32:21 +00:00
parent ffa73acfec
commit da108b4ed4
3 changed files with 157 additions and 37 deletions

View File

@ -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>

View File

@ -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
}

View File

@ -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;