From f15380ba8ae35941dcd56d9a288ad023295dde30 Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Sun, 20 Sep 2009 22:35:26 +0000 Subject: [PATCH] implement and document support for CHECK-NOT git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@82408 91177308-0d34-0410-b5e6-96231b3b80d8 --- docs/TestingGuide.html | 30 ++++++++++++++++++ test/Transforms/GVN/rle.ll | 21 +++++++++++++ utils/FileCheck/FileCheck.cpp | 58 ++++++++++++++++++++++++++++++----- 3 files changed, 101 insertions(+), 8 deletions(-) diff --git a/docs/TestingGuide.html b/docs/TestingGuide.html index f9743634e77..9e4a40ade8d 100644 --- a/docs/TestingGuide.html +++ b/docs/TestingGuide.html @@ -594,6 +594,36 @@ directive in a file.

+ +
The "CHECK-NOT:" directive
+ +
+ +

The CHECK-NOT: directive is used to verify that a string doesn't occur +between two matches (or the first matches and the beginning of the file). For +example, to verify that a load is removed by a transformation, a test like this +can be used:

+ +
+
+define i8 @coerce_offset0(i32 %V, i32* %P) {
+  store i32 %V, i32* %P
+   
+  %P2 = bitcast i32* %P to i8*
+  %P3 = getelementptr i8* %P2, i32 2
+
+  %A = load i8* %P3
+  ret i8 %A
+; CHECK: @coerce_offset0
+; CHECK-NOT: load
+; CHECK: ret i8
+}
+
+
+ +
+
Variables and substitutions
diff --git a/test/Transforms/GVN/rle.ll b/test/Transforms/GVN/rle.ll index 1c5ab676f7d..6b458903d7b 100644 --- a/test/Transforms/GVN/rle.ll +++ b/test/Transforms/GVN/rle.ll @@ -191,3 +191,24 @@ Cont: ; CHECK: ret i8 %A } +;;===----------------------------------------------------------------------===;; +;; Store -> Load and Load -> Load forwarding where src and dst are different +;; types, and the reload is an offset from the store pointer. +;;===----------------------------------------------------------------------===;; + +;; i32 -> f32 forwarding. +define i8 @coerce_offset0(i32 %V, i32* %P) { + store i32 %V, i32* %P + + %P2 = bitcast i32* %P to i8* + %P3 = getelementptr i8* %P2, i32 2 + + %A = load i8* %P3 + ret i8 %A +; CHECK: @coerce_offset0 +; CHECK-NOT: load +; CHECK: ret i8 +} + + + diff --git a/utils/FileCheck/FileCheck.cpp b/utils/FileCheck/FileCheck.cpp index 8de2612f88d..b429f5ddf81 100644 --- a/utils/FileCheck/FileCheck.cpp +++ b/utils/FileCheck/FileCheck.cpp @@ -51,6 +51,11 @@ struct CheckString { /// to a CHECK: directive. bool IsCheckNext; + /// NotStrings - These are all of the strings that are disallowed from + /// occurring between this match string and the previous one (or start of + /// file). + std::vector > NotStrings; + CheckString(const std::string &S, SMLoc L, bool isCheckNext) : Str(S), Loc(L), IsCheckNext(isCheckNext) {} }; @@ -74,6 +79,8 @@ static bool ReadCheckFile(SourceMgr &SM, // Find all instances of CheckPrefix followed by : in the file. StringRef Buffer = F->getBuffer(); + std::vector > NotMatches; + while (1) { // See if Prefix occurs in the memory buffer. Buffer = Buffer.substr(Buffer.find(CheckPrefix)); @@ -86,16 +93,19 @@ static bool ReadCheckFile(SourceMgr &SM, // When we find a check prefix, keep track of whether we find CHECK: or // CHECK-NEXT: - bool IsCheckNext; + bool IsCheckNext = false, IsCheckNot = false; // Verify that the : is present after the prefix. if (Buffer[CheckPrefix.size()] == ':') { Buffer = Buffer.substr(CheckPrefix.size()+1); - IsCheckNext = false; } else if (Buffer.size() > CheckPrefix.size()+6 && memcmp(Buffer.data()+CheckPrefix.size(), "-NEXT:", 6) == 0) { Buffer = Buffer.substr(CheckPrefix.size()+7); IsCheckNext = true; + } else if (Buffer.size() > CheckPrefix.size()+5 && + memcmp(Buffer.data()+CheckPrefix.size(), "-NOT:", 5) == 0) { + Buffer = Buffer.substr(CheckPrefix.size()+6); + IsCheckNot = true; } else { Buffer = Buffer.substr(1); continue; @@ -103,8 +113,7 @@ static bool ReadCheckFile(SourceMgr &SM, // Okay, we found the prefix, yay. Remember the rest of the line, but // ignore leading and trailing whitespace. - while (!Buffer.empty() && (Buffer[0] == ' ' || Buffer[0] == '\t')) - Buffer = Buffer.substr(1); + Buffer = Buffer.substr(Buffer.find_first_not_of(" \t")); // Scan ahead to the end of line. size_t EOL = Buffer.find_first_of("\n\r"); @@ -122,6 +131,16 @@ static bool ReadCheckFile(SourceMgr &SM, return true; } + StringRef PatternStr = Buffer.substr(0, EOL); + + // Handle CHECK-NOT. + if (IsCheckNot) { + NotMatches.push_back(std::make_pair(SMLoc::getFromPointer(Buffer.data()), + PatternStr.str())); + Buffer = Buffer.substr(EOL); + continue; + } + // Verify that CHECK-NEXT lines have at least one CHECK line before them. if (IsCheckNext && CheckStrings.empty()) { SM.PrintMessage(SMLoc::getFromPointer(CheckPrefixStart), @@ -131,10 +150,10 @@ static bool ReadCheckFile(SourceMgr &SM, } // Okay, add the string we captured to the output vector and move on. - CheckStrings.push_back(CheckString(std::string(Buffer.data(), - Buffer.data()+EOL), + CheckStrings.push_back(CheckString(PatternStr.str(), SMLoc::getFromPointer(Buffer.data()), IsCheckNext)); + std::swap(NotMatches, CheckStrings.back().NotStrings); Buffer = Buffer.substr(EOL); } @@ -145,6 +164,12 @@ static bool ReadCheckFile(SourceMgr &SM, return true; } + if (!NotMatches.empty()) { + errs() << "error: '" << CheckPrefix + << "-NOT:' not supported after last check line.\n"; + return true; + } + return false; } @@ -271,7 +296,8 @@ int main(int argc, char **argv) { // file. StringRef Buffer = F->getBuffer(); - const char *LastMatch = 0; + const char *LastMatch = Buffer.data(); + for (unsigned StrNo = 0, e = CheckStrings.size(); StrNo != e; ++StrNo) { const CheckString &CheckStr = CheckStrings[StrNo]; @@ -290,7 +316,8 @@ int main(int argc, char **argv) { // 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"); + assert(LastMatch != F->getBufferStart() && + "CHECK-NEXT can't be the first check in a file"); unsigned NumNewLines = CountNumNewlinesBetween(LastMatch, Buffer.data()); if (NumNewLines == 0) { @@ -316,6 +343,21 @@ int main(int argc, char **argv) { return 1; } } + + // If this match had "not strings", verify that they don't exist in the + // skipped region. + StringRef SkippedRegion(LastMatch, Buffer.data()-LastMatch); + for (unsigned i = 0, e = CheckStr.NotStrings.size(); i != e; ++i) { + size_t Pos = SkippedRegion.find(CheckStr.NotStrings[i].second); + if (Pos == StringRef::npos) continue; + + SM.PrintMessage(SMLoc::getFromPointer(LastMatch+Pos), + CheckPrefix+"-NOT: string occurred!", "error"); + SM.PrintMessage(CheckStr.NotStrings[i].first, + CheckPrefix+"-NOT: pattern specified here", "note"); + return 1; + } + // Otherwise, everything is good. Remember this as the last match and move // on to the next one.