mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-01-01 00:33:09 +00:00
implement and document support for CHECK-NOT
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@82408 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
96077036f0
commit
f15380ba8a
@ -594,6 +594,36 @@ directive in a file.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- _______________________________________________________________________ -->
|
||||
<div class="doc_subsubsection"><a
|
||||
name="FileCheck-CHECK-NOT">The "CHECK-NOT:" directive</a></div>
|
||||
|
||||
<div class="doc_text">
|
||||
|
||||
<p>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:</p>
|
||||
|
||||
<div class="doc_code">
|
||||
<pre>
|
||||
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
|
||||
; <b>CHECK:</b> @coerce_offset0
|
||||
; <b>CHECK-NOT:</b> load
|
||||
; <b>CHECK:</b> ret i8
|
||||
}
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- _______________________________________________________________________ -->
|
||||
<div class="doc_subsection"><a name="dgvars">Variables and
|
||||
substitutions</a></div>
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -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<std::pair<SMLoc, std::string> > 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<std::pair<SMLoc, std::string> > 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.
|
||||
|
Loading…
Reference in New Issue
Block a user