forked from OSchip/llvm-project
implement support for CHECK-NEXT: in filecheck.
llvm-svn: 79123
This commit is contained in:
parent
ffa73acfec
commit
da108b4ed4
|
@ -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 < %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 {
|
|||
<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 "<PREFIX>-NEXT:". For
|
||||
example, something like this works as you'd expect:</p>
|
||||
|
||||
<div class="doc_code">
|
||||
<pre>
|
||||
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
|
||||
|
||||
; <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>
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue