aboutsummaryrefslogtreecommitdiffstats
path: root/utils
diff options
context:
space:
mode:
authorStephen Hines <srhines@google.com>2014-02-11 20:01:10 -0800
committerStephen Hines <srhines@google.com>2014-02-11 20:01:10 -0800
commitce9904c6ea8fd669978a8eefb854b330eb9828ff (patch)
tree2418ee2e96ea220977c8fb74959192036ab5b133 /utils
parentc27b10b198c1d9e9b51f2303994313ec2778edd7 (diff)
parentdbb832b83351cec97b025b61c26536ef50c3181c (diff)
downloadexternal_llvm-ce9904c6ea8fd669978a8eefb854b330eb9828ff.zip
external_llvm-ce9904c6ea8fd669978a8eefb854b330eb9828ff.tar.gz
external_llvm-ce9904c6ea8fd669978a8eefb854b330eb9828ff.tar.bz2
Merge remote-tracking branch 'upstream/release_34' into merge-20140211
Conflicts: lib/Linker/LinkModules.cpp lib/Support/Unix/Signals.inc Change-Id: Ia54f291fa5dc828052d2412736e8495c1282aa64
Diffstat (limited to 'utils')
-rw-r--r--utils/FileCheck/CMakeLists.txt2
-rw-r--r--utils/FileCheck/FileCheck.cpp433
-rw-r--r--utils/FileUpdate/CMakeLists.txt2
-rwxr-xr-xutils/GetRepositoryPath4
-rw-r--r--utils/Misc/mergefunctions.clang.svn.patch14
-rw-r--r--utils/TableGen/AsmMatcherEmitter.cpp115
-rw-r--r--utils/TableGen/AsmWriterEmitter.cpp138
-rw-r--r--utils/TableGen/CodeGenDAGPatterns.cpp156
-rw-r--r--utils/TableGen/CodeGenDAGPatterns.h6
-rw-r--r--utils/TableGen/CodeGenInstruction.cpp17
-rw-r--r--utils/TableGen/CodeGenInstruction.h3
-rw-r--r--utils/TableGen/CodeGenMapTable.cpp1
-rw-r--r--utils/TableGen/CodeGenRegisters.cpp7
-rw-r--r--utils/TableGen/CodeGenSchedule.cpp6
-rw-r--r--utils/TableGen/CodeGenTarget.cpp7
-rw-r--r--utils/TableGen/DAGISelEmitter.cpp16
-rw-r--r--utils/TableGen/DAGISelMatcher.cpp6
-rw-r--r--utils/TableGen/DAGISelMatcher.h32
-rw-r--r--utils/TableGen/DAGISelMatcherEmitter.cpp15
-rw-r--r--utils/TableGen/DAGISelMatcherOpt.cpp6
-rw-r--r--utils/TableGen/FastISelEmitter.cpp82
-rw-r--r--utils/TableGen/FixedLenDecoderEmitter.cpp1
-rw-r--r--utils/TableGen/InstrInfoEmitter.cpp68
-rw-r--r--utils/TableGen/IntrinsicEmitter.cpp158
-rw-r--r--utils/TableGen/OptParserEmitter.cpp23
-rw-r--r--utils/TableGen/RegisterInfoEmitter.cpp20
-rw-r--r--utils/TableGen/SequenceToOffsetTable.h1
-rw-r--r--utils/TableGen/SetTheory.cpp49
-rw-r--r--utils/TableGen/StringToOffsetTable.h83
-rw-r--r--utils/TableGen/SubtargetEmitter.cpp5
-rw-r--r--utils/TableGen/TGValueTypes.cpp11
-rw-r--r--utils/TableGen/X86DisassemblerTables.cpp161
-rw-r--r--utils/TableGen/X86DisassemblerTables.h60
-rw-r--r--utils/TableGen/X86RecognizableInstr.cpp147
-rw-r--r--utils/TableGen/X86RecognizableInstr.h2
-rwxr-xr-xutils/buildit/build_llvm3
-rw-r--r--utils/emacs/llvm-mode.el15
-rw-r--r--utils/kate/llvm.xml3
-rw-r--r--utils/lit/TODO168
-rw-r--r--utils/lit/examples/README.txt7
-rw-r--r--utils/lit/examples/many-tests/README.txt10
-rw-r--r--utils/lit/examples/many-tests/lit.cfg (renamed from utils/lit/lit/ExampleTests/ManyTests/lit.local.cfg)2
-rw-r--r--utils/lit/lit/ExampleTests/Clang/fsyntax-only.c4
-rw-r--r--utils/lit/lit/ExampleTests/Clang/lit.cfg47
-rw-r--r--utils/lit/lit/ExampleTests/LLVM.InTree/test/Bar/data.txt1
-rw-r--r--utils/lit/lit/ExampleTests/LLVM.InTree/test/Bar/pct-S.ll1
-rw-r--r--utils/lit/lit/ExampleTests/LLVM.InTree/test/lit.cfg66
-rw-r--r--utils/lit/lit/ExampleTests/LLVM.InTree/test/lit.site.cfg7
-rw-r--r--utils/lit/lit/ExampleTests/LLVM.OutOfTree/lit.local.cfg1
-rw-r--r--utils/lit/lit/ExampleTests/LLVM.OutOfTree/obj/test/Foo/lit.local.cfg0
-rw-r--r--utils/lit/lit/ExampleTests/LLVM.OutOfTree/obj/test/lit.site.cfg8
-rw-r--r--utils/lit/lit/ExampleTests/LLVM.OutOfTree/src/test/Foo/data.txt1
-rw-r--r--utils/lit/lit/ExampleTests/LLVM.OutOfTree/src/test/Foo/pct-S.ll1
-rw-r--r--utils/lit/lit/ExampleTests/LLVM.OutOfTree/src/test/lit.cfg66
-rw-r--r--utils/lit/lit/ExampleTests/ShExternal/lit.local.cfg6
-rw-r--r--utils/lit/lit/ExampleTests/ShInternal/lit.local.cfg6
-rw-r--r--utils/lit/lit/ExampleTests/fail.c2
-rw-r--r--utils/lit/lit/ExampleTests/lit.cfg26
-rw-r--r--utils/lit/lit/ExampleTests/pass.c1
-rw-r--r--utils/lit/lit/ExampleTests/required-and-missing.c4
-rw-r--r--utils/lit/lit/ExampleTests/required-and-present.c2
-rw-r--r--utils/lit/lit/ExampleTests/vg-fail.c4
-rw-r--r--utils/lit/lit/ExampleTests/xfail-feature.c4
-rw-r--r--utils/lit/lit/ExampleTests/xfail.c2
-rw-r--r--utils/lit/lit/ExampleTests/xpass.c2
-rw-r--r--utils/lit/lit/LitConfig.py40
-rw-r--r--utils/lit/lit/LitTestCase.py22
-rw-r--r--utils/lit/lit/ProgressBar.py23
-rw-r--r--utils/lit/lit/ShUtil.py8
-rw-r--r--utils/lit/lit/Test.py167
-rw-r--r--utils/lit/lit/TestFormats.py229
-rw-r--r--utils/lit/lit/TestRunner.py230
-rw-r--r--utils/lit/lit/TestingConfig.py186
-rw-r--r--utils/lit/lit/__init__.py2
-rw-r--r--utils/lit/lit/discovery.py28
-rw-r--r--utils/lit/lit/formats/__init__.py4
-rw-r--r--utils/lit/lit/formats/base.py118
-rw-r--r--utils/lit/lit/formats/googletest.py114
-rw-r--r--utils/lit/lit/formats/shtest.py12
-rwxr-xr-xutils/lit/lit/main.py292
-rw-r--r--utils/lit/lit/run.py277
-rw-r--r--utils/lit/lit/util.py (renamed from utils/lit/lit/Util.py)45
-rw-r--r--utils/lit/setup.py9
-rw-r--r--utils/lit/tests/Inputs/discovery/lit.cfg4
-rw-r--r--utils/lit/tests/Inputs/discovery/subdir/lit.local.cfg3
-rw-r--r--utils/lit/tests/Inputs/discovery/subsuite/lit.cfg1
-rw-r--r--utils/lit/tests/Inputs/exec-discovery-in-tree/lit.cfg4
-rw-r--r--utils/lit/tests/Inputs/exec-discovery-in-tree/obj/lit.site.cfg2
-rw-r--r--utils/lit/tests/Inputs/exec-discovery/lit.site.cfg2
-rwxr-xr-xutils/lit/tests/Inputs/googletest-format/DummySubDir/OneTest34
-rw-r--r--utils/lit/tests/Inputs/googletest-format/lit.cfg3
-rw-r--r--utils/lit/tests/Inputs/progress-bar/lit.cfg1
-rw-r--r--utils/lit/tests/Inputs/shtest-format/argv0.txt6
-rw-r--r--utils/lit/tests/Inputs/shtest-format/external_shell/fail.txt2
-rw-r--r--utils/lit/tests/Inputs/shtest-format/external_shell/fail_with_bad_encoding.txt5
-rw-r--r--utils/lit/tests/Inputs/shtest-format/external_shell/lit.local.cfg1
-rwxr-xr-xutils/lit/tests/Inputs/shtest-format/external_shell/write-bad-encoding.sh3
-rw-r--r--utils/lit/tests/Inputs/shtest-format/fail.txt1
-rw-r--r--utils/lit/tests/Inputs/shtest-format/lit.cfg1
-rw-r--r--utils/lit/tests/Inputs/shtest-shell/lit.cfg1
-rw-r--r--utils/lit/tests/Inputs/test-data/lit.cfg44
-rw-r--r--utils/lit/tests/Inputs/test-data/metrics.ini7
-rw-r--r--utils/lit/tests/Inputs/unittest-adaptor/lit.cfg1
-rw-r--r--utils/lit/tests/discovery.py15
-rw-r--r--utils/lit/tests/googletest-format.py20
-rw-r--r--utils/lit/tests/lit.cfg15
-rw-r--r--utils/lit/tests/shell-parsing.py2
-rw-r--r--utils/lit/tests/shtest-encoding.py3
-rw-r--r--utils/lit/tests/shtest-format.py44
-rw-r--r--utils/lit/tests/test-data.py12
-rw-r--r--utils/lit/tests/test-output.py21
-rw-r--r--utils/lit/tests/unittest-adaptor.py2
-rw-r--r--utils/llvm-build/llvmbuild/__init__.py2
-rw-r--r--utils/llvm-build/llvmbuild/componentinfo.py93
-rw-r--r--utils/llvm-build/llvmbuild/main.py122
-rw-r--r--utils/llvm-build/llvmbuild/util.py2
-rw-r--r--utils/llvm-lit/CMakeLists.txt8
-rw-r--r--utils/not/CMakeLists.txt2
-rwxr-xr-xutils/profile.pl74
-rwxr-xr-xutils/release/tag.sh2
-rwxr-xr-xutils/release/test-release.sh80
-rwxr-xr-xutils/test_debuginfo.pl19
-rw-r--r--utils/unittest/CMakeLists.txt9
-rw-r--r--utils/unittest/googletest/Makefile3
-rw-r--r--utils/unittest/googletest/README.LLVM16
-rw-r--r--utils/unittest/googletest/include/gtest/gtest-test-part.h2
-rw-r--r--utils/unittest/googletest/include/gtest/gtest.h5
-rw-r--r--utils/unittest/googletest/include/gtest/internal/gtest-death-test-internal.h4
-rw-r--r--utils/unittest/googletest/include/gtest/internal/gtest-internal.h3
-rw-r--r--utils/unittest/googletest/include/gtest/internal/gtest-param-util.h2
-rw-r--r--utils/unittest/googletest/include/gtest/internal/gtest-port.h4
-rw-r--r--utils/unittest/googletest/src/gtest-all.cc (renamed from utils/unittest/googletest/gtest-all.cc)14
-rw-r--r--utils/unittest/googletest/src/gtest-death-test.cc (renamed from utils/unittest/googletest/gtest-death-test.cc)8
-rw-r--r--utils/unittest/googletest/src/gtest-filepath.cc (renamed from utils/unittest/googletest/gtest-filepath.cc)0
-rw-r--r--utils/unittest/googletest/src/gtest-internal-inl.h (renamed from utils/unittest/googletest/include/gtest/internal/gtest-internal-inl.h)2
-rw-r--r--utils/unittest/googletest/src/gtest-port.cc (renamed from utils/unittest/googletest/gtest-port.cc)16
-rw-r--r--utils/unittest/googletest/src/gtest-printers.cc (renamed from utils/unittest/googletest/gtest-printers.cc)0
-rw-r--r--utils/unittest/googletest/src/gtest-test-part.cc (renamed from utils/unittest/googletest/gtest-test-part.cc)2
-rw-r--r--utils/unittest/googletest/src/gtest-typed-test.cc (renamed from utils/unittest/googletest/gtest-typed-test.cc)0
-rw-r--r--utils/unittest/googletest/src/gtest.cc (renamed from utils/unittest/googletest/gtest.cc)12
-rw-r--r--utils/vim/llvm.vim29
-rw-r--r--utils/yaml-bench/YAMLBench.cpp22
142 files changed, 2995 insertions, 1955 deletions
diff --git a/utils/FileCheck/CMakeLists.txt b/utils/FileCheck/CMakeLists.txt
index fa56f92..d691ceb 100644
--- a/utils/FileCheck/CMakeLists.txt
+++ b/utils/FileCheck/CMakeLists.txt
@@ -4,7 +4,7 @@ add_llvm_utility(FileCheck
target_link_libraries(FileCheck LLVMSupport)
if( MINGW )
- target_link_libraries(FileCheck imagehlp psapi)
+ target_link_libraries(FileCheck imagehlp psapi shell32)
endif( MINGW )
if( LLVM_ENABLE_THREADS AND HAVE_LIBPTHREAD )
target_link_libraries(FileCheck pthread)
diff --git a/utils/FileCheck/FileCheck.cpp b/utils/FileCheck/FileCheck.cpp
index 8d5af58..f2510d7 100644
--- a/utils/FileCheck/FileCheck.cpp
+++ b/utils/FileCheck/FileCheck.cpp
@@ -20,6 +20,7 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringSet.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/PrettyStackTrace.h"
@@ -29,6 +30,7 @@
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/system_error.h"
#include <algorithm>
+#include <cctype>
#include <map>
#include <string>
#include <vector>
@@ -41,30 +43,39 @@ static cl::opt<std::string>
InputFilename("input-file", cl::desc("File to check (defaults to stdin)"),
cl::init("-"), cl::value_desc("filename"));
-static cl::opt<std::string>
-CheckPrefix("check-prefix", cl::init("CHECK"),
- cl::desc("Prefix to use from check file (defaults to 'CHECK')"));
+static cl::list<std::string>
+CheckPrefixes("check-prefix",
+ cl::desc("Prefix to use from check file (defaults to 'CHECK')"));
static cl::opt<bool>
NoCanonicalizeWhiteSpace("strict-whitespace",
cl::desc("Do not treat all horizontal whitespace as equivalent"));
+typedef cl::list<std::string>::const_iterator prefix_iterator;
+
//===----------------------------------------------------------------------===//
// Pattern Handling Code.
//===----------------------------------------------------------------------===//
+namespace Check {
+ enum CheckType {
+ CheckNone = 0,
+ CheckPlain,
+ CheckNext,
+ CheckNot,
+ CheckDAG,
+ CheckLabel,
+
+ /// MatchEOF - When set, this pattern only matches the end of file. This is
+ /// used for trailing CHECK-NOTs.
+ CheckEOF
+ };
+}
+
class Pattern {
SMLoc PatternLoc;
- /// MatchEOF - When set, this pattern only matches the end of file. This is
- /// used for trailing CHECK-NOTs.
- bool MatchEOF;
-
- /// MatchNot
- bool MatchNot;
-
- /// MatchDag
- bool MatchDag;
+ Check::CheckType CheckTy;
/// FixedStr - If non-empty, this pattern is a fixed string match with the
/// specified fixed string.
@@ -89,17 +100,21 @@ class Pattern {
public:
- Pattern(bool matchEOF = false)
- : MatchEOF(matchEOF), MatchNot(false), MatchDag(false) { }
+ Pattern(Check::CheckType Ty)
+ : CheckTy(Ty) { }
/// getLoc - Return the location in source code.
SMLoc getLoc() const { return PatternLoc; }
- /// ParsePattern - Parse the given string into the Pattern. SM provides the
- /// SourceMgr used for error reports, and LineNumber is the line number in
- /// the input file from which the pattern string was read.
- /// Returns true in case of an error, false otherwise.
- bool ParsePattern(StringRef PatternStr, SourceMgr &SM, unsigned LineNumber);
+ /// ParsePattern - Parse the given string into the Pattern. Prefix provides
+ /// which prefix is being matched, SM provides the SourceMgr used for error
+ /// reports, and LineNumber is the line number in the input file from which
+ /// the pattern string was read. Returns true in case of an error, false
+ /// otherwise.
+ bool ParsePattern(StringRef PatternStr,
+ StringRef Prefix,
+ SourceMgr &SM,
+ unsigned LineNumber);
/// Match - Match the pattern string against the input buffer Buffer. This
/// returns the position that is matched or npos if there is no match. If
@@ -118,11 +133,7 @@ public:
bool hasVariable() const { return !(VariableUses.empty() &&
VariableDefs.empty()); }
- void setMatchNot(bool Not) { MatchNot = Not; }
- bool getMatchNot() const { return MatchNot; }
-
- void setMatchDag(bool Dag) { MatchDag = Dag; }
- bool getMatchDag() const { return MatchDag; }
+ Check::CheckType getCheckTy() const { return CheckTy; }
private:
static void AddFixedStringToRegEx(StringRef FixedStr, std::string &TheStr);
@@ -148,7 +159,9 @@ private:
};
-bool Pattern::ParsePattern(StringRef PatternStr, SourceMgr &SM,
+bool Pattern::ParsePattern(StringRef PatternStr,
+ StringRef Prefix,
+ SourceMgr &SM,
unsigned LineNumber) {
this->LineNumber = LineNumber;
PatternLoc = SMLoc::getFromPointer(PatternStr.data());
@@ -162,7 +175,7 @@ bool Pattern::ParsePattern(StringRef PatternStr, SourceMgr &SM,
if (PatternStr.empty()) {
SM.PrintMessage(PatternLoc, SourceMgr::DK_Error,
"found empty check string with prefix '" +
- CheckPrefix+":'");
+ Prefix + ":'");
return true;
}
@@ -381,7 +394,7 @@ bool Pattern::EvaluateExpression(StringRef Expr, std::string &Value) const {
size_t Pattern::Match(StringRef Buffer, size_t &MatchLen,
StringMap<StringRef> &VariableTable) const {
// If this is the EOF pattern, match it immediately.
- if (MatchEOF) {
+ if (CheckTy == Check::CheckEOF) {
MatchLen = 0;
return Buffer.size();
}
@@ -590,27 +603,30 @@ struct CheckString {
/// Pat - The pattern to match.
Pattern Pat;
+ /// Prefix - Which prefix name this check matched.
+ StringRef Prefix;
+
/// Loc - The location in the match file that the check string was specified.
SMLoc Loc;
- /// IsCheckNext - This is true if this is a CHECK-NEXT: directive (as opposed
- /// to a CHECK: directive.
- bool IsCheckNext;
-
- /// IsCheckLabel - This is true if this is a CHECK-LABEL: directive (as
- /// opposed to a CHECK: directive.
- bool IsCheckLabel;
+ /// CheckTy - Specify what kind of check this is. e.g. CHECK-NEXT: directive,
+ /// as opposed to a CHECK: directive.
+ Check::CheckType CheckTy;
/// DagNotStrings - 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<Pattern> DagNotStrings;
- CheckString(const Pattern &P, SMLoc L, bool isCheckNext, bool isCheckLabel)
- : Pat(P), Loc(L), IsCheckNext(isCheckNext), IsCheckLabel(isCheckLabel) {}
+
+ CheckString(const Pattern &P,
+ StringRef S,
+ SMLoc L,
+ Check::CheckType Ty)
+ : Pat(P), Prefix(S), Loc(L), CheckTy(Ty) {}
/// Check - Match check string and its "not strings" and/or "dag strings".
- size_t Check(const SourceMgr &SM, StringRef Buffer, bool IsLabel,
+ size_t Check(const SourceMgr &SM, StringRef Buffer, bool IsLabelScanMode,
size_t &MatchLen, StringMap<StringRef> &VariableTable) const;
/// CheckNext - Verify there is a single line in the given buffer.
@@ -666,6 +682,161 @@ static MemoryBuffer *CanonicalizeInputFile(MemoryBuffer *MB,
return MB2;
}
+static bool IsPartOfWord(char c) {
+ return (isalnum(c) || c == '-' || c == '_');
+}
+
+// Get the size of the prefix extension.
+static size_t CheckTypeSize(Check::CheckType Ty) {
+ switch (Ty) {
+ case Check::CheckNone:
+ return 0;
+
+ case Check::CheckPlain:
+ return sizeof(":") - 1;
+
+ case Check::CheckNext:
+ return sizeof("-NEXT:") - 1;
+
+ case Check::CheckNot:
+ return sizeof("-NOT:") - 1;
+
+ case Check::CheckDAG:
+ return sizeof("-DAG:") - 1;
+
+ case Check::CheckLabel:
+ return sizeof("-LABEL:") - 1;
+
+ case Check::CheckEOF:
+ llvm_unreachable("Should not be using EOF size");
+ }
+
+ llvm_unreachable("Bad check type");
+}
+
+static Check::CheckType FindCheckType(StringRef Buffer, StringRef Prefix) {
+ char NextChar = Buffer[Prefix.size()];
+
+ // Verify that the : is present after the prefix.
+ if (NextChar == ':')
+ return Check::CheckPlain;
+
+ if (NextChar != '-')
+ return Check::CheckNone;
+
+ StringRef Rest = Buffer.drop_front(Prefix.size() + 1);
+ if (Rest.startswith("NEXT:"))
+ return Check::CheckNext;
+
+ if (Rest.startswith("NOT:"))
+ return Check::CheckNot;
+
+ if (Rest.startswith("DAG:"))
+ return Check::CheckDAG;
+
+ if (Rest.startswith("LABEL:"))
+ return Check::CheckLabel;
+
+ return Check::CheckNone;
+}
+
+// From the given position, find the next character after the word.
+static size_t SkipWord(StringRef Str, size_t Loc) {
+ while (Loc < Str.size() && IsPartOfWord(Str[Loc]))
+ ++Loc;
+ return Loc;
+}
+
+// Try to find the first match in buffer for any prefix. If a valid match is
+// found, return that prefix and set its type and location. If there are almost
+// matches (e.g. the actual prefix string is found, but is not an actual check
+// string), but no valid match, return an empty string and set the position to
+// resume searching from. If no partial matches are found, return an empty
+// string and the location will be StringRef::npos. If one prefix is a substring
+// of another, the maximal match should be found. e.g. if "A" and "AA" are
+// prefixes then AA-CHECK: should match the second one.
+static StringRef FindFirstCandidateMatch(StringRef &Buffer,
+ Check::CheckType &CheckTy,
+ size_t &CheckLoc) {
+ StringRef FirstPrefix;
+ size_t FirstLoc = StringRef::npos;
+ size_t SearchLoc = StringRef::npos;
+ Check::CheckType FirstTy = Check::CheckNone;
+
+ CheckTy = Check::CheckNone;
+ CheckLoc = StringRef::npos;
+
+ for (prefix_iterator I = CheckPrefixes.begin(), E = CheckPrefixes.end();
+ I != E; ++I) {
+ StringRef Prefix(*I);
+ size_t PrefixLoc = Buffer.find(Prefix);
+
+ if (PrefixLoc == StringRef::npos)
+ continue;
+
+ // Track where we are searching for invalid prefixes that look almost right.
+ // We need to only advance to the first partial match on the next attempt
+ // since a partial match could be a substring of a later, valid prefix.
+ // Need to skip to the end of the word, otherwise we could end up
+ // matching a prefix in a substring later.
+ if (PrefixLoc < SearchLoc)
+ SearchLoc = SkipWord(Buffer, PrefixLoc);
+
+ // We only want to find the first match to avoid skipping some.
+ if (PrefixLoc > FirstLoc)
+ continue;
+ // If one matching check-prefix is a prefix of another, choose the
+ // longer one.
+ if (PrefixLoc == FirstLoc && Prefix.size() < FirstPrefix.size())
+ continue;
+
+ StringRef Rest = Buffer.drop_front(PrefixLoc);
+ // Make sure we have actually found the prefix, and not a word containing
+ // it. This should also prevent matching the wrong prefix when one is a
+ // substring of another.
+ if (PrefixLoc != 0 && IsPartOfWord(Buffer[PrefixLoc - 1]))
+ continue;
+
+ FirstLoc = PrefixLoc;
+ FirstTy = FindCheckType(Rest, Prefix);
+ FirstPrefix = Prefix;
+ }
+
+ // If the first prefix is invalid, we should continue the search after it.
+ if (FirstTy == Check::CheckNone) {
+ CheckLoc = SearchLoc;
+ return "";
+ }
+
+ CheckTy = FirstTy;
+ CheckLoc = FirstLoc;
+ return FirstPrefix;
+}
+
+static StringRef FindFirstMatchingPrefix(StringRef &Buffer,
+ unsigned &LineNumber,
+ Check::CheckType &CheckTy,
+ size_t &CheckLoc) {
+ while (!Buffer.empty()) {
+ StringRef Prefix = FindFirstCandidateMatch(Buffer, CheckTy, CheckLoc);
+ // If we found a real match, we are done.
+ if (!Prefix.empty()) {
+ LineNumber += Buffer.substr(0, CheckLoc).count('\n');
+ return Prefix;
+ }
+
+ // We didn't find any almost matches either, we are also done.
+ if (CheckLoc == StringRef::npos)
+ return StringRef();
+
+ LineNumber += Buffer.substr(0, CheckLoc + 1).count('\n');
+
+ // Advance to the last possible match we found and try again.
+ Buffer = Buffer.drop_front(CheckLoc + 1);
+ }
+
+ return StringRef();
+}
/// ReadCheckFile - Read the check file, which specifies the sequence of
/// expected strings. The strings are added to the CheckStrings vector.
@@ -696,49 +867,27 @@ static bool ReadCheckFile(SourceMgr &SM,
unsigned LineNumber = 1;
while (1) {
- // See if Prefix occurs in the memory buffer.
- size_t PrefixLoc = Buffer.find(CheckPrefix);
- // If we didn't find a match, we're done.
- if (PrefixLoc == StringRef::npos)
+ Check::CheckType CheckTy;
+ size_t PrefixLoc;
+
+ // See if a prefix occurs in the memory buffer.
+ StringRef UsedPrefix = FindFirstMatchingPrefix(Buffer,
+ LineNumber,
+ CheckTy,
+ PrefixLoc);
+ if (UsedPrefix.empty())
break;
- LineNumber += Buffer.substr(0, PrefixLoc).count('\n');
-
- Buffer = Buffer.substr(PrefixLoc);
-
- const char *CheckPrefixStart = Buffer.data();
-
- // When we find a check prefix, keep track of whether we find CHECK: or
- // CHECK-NEXT:
- bool IsCheckNext = false, IsCheckNot = false, IsCheckDag = false,
- IsCheckLabel = false;
-
- // Verify that the : is present after the prefix.
- if (Buffer[CheckPrefix.size()] == ':') {
- Buffer = Buffer.substr(CheckPrefix.size()+1);
- } else if (Buffer.size() > CheckPrefix.size()+6 &&
- memcmp(Buffer.data()+CheckPrefix.size(), "-NEXT:", 6) == 0) {
- Buffer = Buffer.substr(CheckPrefix.size()+6);
- IsCheckNext = true;
- } else if (Buffer.size() > CheckPrefix.size()+5 &&
- memcmp(Buffer.data()+CheckPrefix.size(), "-NOT:", 5) == 0) {
- Buffer = Buffer.substr(CheckPrefix.size()+5);
- IsCheckNot = true;
- } else if (Buffer.size() > CheckPrefix.size()+5 &&
- memcmp(Buffer.data()+CheckPrefix.size(), "-DAG:", 5) == 0) {
- Buffer = Buffer.substr(CheckPrefix.size()+5);
- IsCheckDag = true;
- } else if (Buffer.size() > CheckPrefix.size()+7 &&
- memcmp(Buffer.data()+CheckPrefix.size(), "-LABEL:", 7) == 0) {
- Buffer = Buffer.substr(CheckPrefix.size()+7);
- IsCheckLabel = true;
- } else {
- Buffer = Buffer.substr(1);
- continue;
- }
+ Buffer = Buffer.drop_front(PrefixLoc);
+
+ // Location to use for error messages.
+ const char *UsedPrefixStart = Buffer.data() + (PrefixLoc == 0 ? 0 : 1);
- // Okay, we found the prefix, yay. Remember the rest of the line, but
- // ignore leading and trailing whitespace.
+ // PrefixLoc is to the start of the prefix. Skip to the end.
+ Buffer = Buffer.drop_front(UsedPrefix.size() + CheckTypeSize(CheckTy));
+
+ // Okay, we found the prefix, yay. Remember the rest of the line, but ignore
+ // leading and trailing whitespace.
Buffer = Buffer.substr(Buffer.find_first_not_of(" \t"));
// Scan ahead to the end of line.
@@ -748,59 +897,65 @@ static bool ReadCheckFile(SourceMgr &SM,
SMLoc PatternLoc = SMLoc::getFromPointer(Buffer.data());
// Parse the pattern.
- Pattern P;
- if (P.ParsePattern(Buffer.substr(0, EOL), SM, LineNumber))
+ Pattern P(CheckTy);
+ if (P.ParsePattern(Buffer.substr(0, EOL), UsedPrefix, SM, LineNumber))
return true;
// Verify that CHECK-LABEL lines do not define or use variables
- if (IsCheckLabel && P.hasVariable()) {
- SM.PrintMessage(SMLoc::getFromPointer(CheckPrefixStart),
+ if ((CheckTy == Check::CheckLabel) && P.hasVariable()) {
+ SM.PrintMessage(SMLoc::getFromPointer(UsedPrefixStart),
SourceMgr::DK_Error,
- "found '"+CheckPrefix+"-LABEL:' with variable definition"
- " or use'");
+ "found '" + UsedPrefix + "-LABEL:'"
+ " with variable definition or use");
return true;
}
- P.setMatchNot(IsCheckNot);
- P.setMatchDag(IsCheckDag);
-
Buffer = Buffer.substr(EOL);
// Verify that CHECK-NEXT lines have at least one CHECK line before them.
- if (IsCheckNext && CheckStrings.empty()) {
- SM.PrintMessage(SMLoc::getFromPointer(CheckPrefixStart),
+ if ((CheckTy == Check::CheckNext) && CheckStrings.empty()) {
+ SM.PrintMessage(SMLoc::getFromPointer(UsedPrefixStart),
SourceMgr::DK_Error,
- "found '"+CheckPrefix+"-NEXT:' without previous '"+
- CheckPrefix+ ": line");
+ "found '" + UsedPrefix + "-NEXT:' without previous '"
+ + UsedPrefix + ": line");
return true;
}
// Handle CHECK-DAG/-NOT.
- if (IsCheckDag || IsCheckNot) {
+ if (CheckTy == Check::CheckDAG || CheckTy == Check::CheckNot) {
DagNotMatches.push_back(P);
continue;
}
// Okay, add the string we captured to the output vector and move on.
CheckStrings.push_back(CheckString(P,
+ UsedPrefix,
PatternLoc,
- IsCheckNext,
- IsCheckLabel));
+ CheckTy));
std::swap(DagNotMatches, CheckStrings.back().DagNotStrings);
}
- // Add an EOF pattern for any trailing CHECK-DAG/-NOTs.
+ // Add an EOF pattern for any trailing CHECK-DAG/-NOTs, and use the first
+ // prefix as a filler for the error message.
if (!DagNotMatches.empty()) {
- CheckStrings.push_back(CheckString(Pattern(true),
+ CheckStrings.push_back(CheckString(Pattern(Check::CheckEOF),
+ CheckPrefixes[0],
SMLoc::getFromPointer(Buffer.data()),
- false,
- false));
+ Check::CheckEOF));
std::swap(DagNotMatches, CheckStrings.back().DagNotStrings);
}
if (CheckStrings.empty()) {
- errs() << "error: no check strings found with prefix '" << CheckPrefix
- << ":'\n";
+ errs() << "error: no check strings found with prefix"
+ << (CheckPrefixes.size() > 1 ? "es " : " ");
+ for (size_t I = 0, N = CheckPrefixes.size(); I != N; ++I) {
+ StringRef Prefix(CheckPrefixes[I]);
+ errs() << '\'' << Prefix << ":'";
+ if (I != N - 1)
+ errs() << ", ";
+ }
+
+ errs() << '\n';
return true;
}
@@ -852,12 +1007,16 @@ static unsigned CountNumNewlinesBetween(StringRef Range) {
}
size_t CheckString::Check(const SourceMgr &SM, StringRef Buffer,
- bool IsLabel, size_t &MatchLen,
+ bool IsLabelScanMode, size_t &MatchLen,
StringMap<StringRef> &VariableTable) const {
size_t LastPos = 0;
std::vector<const Pattern *> NotStrings;
- if (!IsLabel) {
+ // IsLabelScanMode is true when we are scanning forward to find CHECK-LABEL
+ // bounds; we have not processed variable definitions within the bounded block
+ // yet so cannot handle any final CHECK-DAG yet; this is handled when going
+ // over the block again (including the last CHECK-LABEL) in normal mode.
+ if (!IsLabelScanMode) {
// Match "dag strings" (with mixed "not strings" if any).
LastPos = CheckDag(SM, Buffer, NotStrings, VariableTable);
if (LastPos == StringRef::npos)
@@ -873,7 +1032,9 @@ size_t CheckString::Check(const SourceMgr &SM, StringRef Buffer,
}
MatchPos += LastPos;
- if (!IsLabel) {
+ // Similar to the above, in "label-scan mode" we can't yet handle CHECK-NEXT
+ // or CHECK-NOT
+ if (!IsLabelScanMode) {
StringRef SkippedRegion = Buffer.substr(LastPos, MatchPos);
// If this check is a "CHECK-NEXT", verify that the previous match was on
@@ -891,7 +1052,7 @@ size_t CheckString::Check(const SourceMgr &SM, StringRef Buffer,
}
bool CheckString::CheckNext(const SourceMgr &SM, StringRef Buffer) const {
- if (!IsCheckNext)
+ if (CheckTy != Check::CheckNext)
return false;
// Count the number of newlines between the previous match and this one.
@@ -904,7 +1065,7 @@ bool CheckString::CheckNext(const SourceMgr &SM, StringRef Buffer) const {
unsigned NumNewLines = CountNumNewlinesBetween(Buffer);
if (NumNewLines == 0) {
- SM.PrintMessage(Loc, SourceMgr::DK_Error, CheckPrefix+
+ SM.PrintMessage(Loc, SourceMgr::DK_Error, Prefix +
"-NEXT: is on the same line as previous match");
SM.PrintMessage(SMLoc::getFromPointer(Buffer.end()),
SourceMgr::DK_Note, "'next' match was here");
@@ -914,7 +1075,7 @@ bool CheckString::CheckNext(const SourceMgr &SM, StringRef Buffer) const {
}
if (NumNewLines != 1) {
- SM.PrintMessage(Loc, SourceMgr::DK_Error, CheckPrefix+
+ SM.PrintMessage(Loc, SourceMgr::DK_Error, Prefix +
"-NEXT: is not on the line after the previous match");
SM.PrintMessage(SMLoc::getFromPointer(Buffer.end()),
SourceMgr::DK_Note, "'next' match was here");
@@ -932,7 +1093,7 @@ bool CheckString::CheckNot(const SourceMgr &SM, StringRef Buffer,
for (unsigned ChunkNo = 0, e = NotStrings.size();
ChunkNo != e; ++ChunkNo) {
const Pattern *Pat = NotStrings[ChunkNo];
- assert(Pat->getMatchNot() && "Expect CHECK-NOT!");
+ assert((Pat->getCheckTy() == Check::CheckNot) && "Expect CHECK-NOT!");
size_t MatchLen = 0;
size_t Pos = Pat->Match(Buffer, MatchLen, VariableTable);
@@ -941,9 +1102,9 @@ bool CheckString::CheckNot(const SourceMgr &SM, StringRef Buffer,
SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()+Pos),
SourceMgr::DK_Error,
- CheckPrefix+"-NOT: string occurred!");
+ Prefix + "-NOT: string occurred!");
SM.PrintMessage(Pat->getLoc(), SourceMgr::DK_Note,
- CheckPrefix+"-NOT: pattern specified here");
+ Prefix + "-NOT: pattern specified here");
return true;
}
@@ -963,15 +1124,16 @@ size_t CheckString::CheckDag(const SourceMgr &SM, StringRef Buffer,
ChunkNo != e; ++ChunkNo) {
const Pattern &Pat = DagNotStrings[ChunkNo];
- assert((Pat.getMatchDag() ^ Pat.getMatchNot()) &&
+ assert((Pat.getCheckTy() == Check::CheckDAG ||
+ Pat.getCheckTy() == Check::CheckNot) &&
"Invalid CHECK-DAG or CHECK-NOT!");
- if (Pat.getMatchNot()) {
+ if (Pat.getCheckTy() == Check::CheckNot) {
NotStrings.push_back(&Pat);
continue;
}
- assert(Pat.getMatchDag() && "Expect CHECK-DAG!");
+ assert((Pat.getCheckTy() == Check::CheckDAG) && "Expect CHECK-DAG!");
size_t MatchLen = 0, MatchPos;
@@ -992,17 +1154,17 @@ size_t CheckString::CheckDag(const SourceMgr &SM, StringRef Buffer,
// Reordered?
SM.PrintMessage(SMLoc::getFromPointer(Buffer.data() + MatchPos),
SourceMgr::DK_Error,
- CheckPrefix+"-DAG: found a match of CHECK-DAG"
+ Prefix + "-DAG: found a match of CHECK-DAG"
" reordering across a CHECK-NOT");
SM.PrintMessage(SMLoc::getFromPointer(Buffer.data() + LastPos),
SourceMgr::DK_Note,
- CheckPrefix+"-DAG: the farthest match of CHECK-DAG"
+ Prefix + "-DAG: the farthest match of CHECK-DAG"
" is found here");
SM.PrintMessage(NotStrings[0]->getLoc(), SourceMgr::DK_Note,
- CheckPrefix+"-NOT: the crossed pattern specified"
+ Prefix + "-NOT: the crossed pattern specified"
" here");
SM.PrintMessage(Pat.getLoc(), SourceMgr::DK_Note,
- CheckPrefix+"-DAG: the reordered pattern specified"
+ Prefix + "-DAG: the reordered pattern specified"
" here");
return StringRef::npos;
}
@@ -1026,11 +1188,50 @@ size_t CheckString::CheckDag(const SourceMgr &SM, StringRef Buffer,
return LastPos;
}
+// A check prefix must contain only alphanumeric, hyphens and underscores.
+static bool ValidateCheckPrefix(StringRef CheckPrefix) {
+ Regex Validator("^[a-zA-Z0-9_-]*$");
+ return Validator.match(CheckPrefix);
+}
+
+static bool ValidateCheckPrefixes() {
+ StringSet<> PrefixSet;
+
+ for (prefix_iterator I = CheckPrefixes.begin(), E = CheckPrefixes.end();
+ I != E; ++I) {
+ StringRef Prefix(*I);
+
+ if (!PrefixSet.insert(Prefix))
+ return false;
+
+ if (!ValidateCheckPrefix(Prefix))
+ return false;
+ }
+
+ return true;
+}
+
+// I don't think there's a way to specify an initial value for cl::list,
+// so if nothing was specified, add the default
+static void AddCheckPrefixIfNeeded() {
+ if (CheckPrefixes.empty())
+ CheckPrefixes.push_back("CHECK");
+}
+
int main(int argc, char **argv) {
sys::PrintStackTraceOnErrorSignal();
PrettyStackTraceProgram X(argc, argv);
cl::ParseCommandLineOptions(argc, argv);
+ if (!ValidateCheckPrefixes()) {
+ errs() << "Supplied check-prefix is invalid! Prefixes must be unique and "
+ "start with a letter and contain only alphanumeric characters, "
+ "hyphens and underscores\n";
+ return 2;
+ }
+
+ AddCheckPrefixIfNeeded();
+
SourceMgr SM;
// Read the expected strings from the check file.
@@ -1076,7 +1277,7 @@ int main(int argc, char **argv) {
CheckRegion = Buffer;
} else {
const CheckString &CheckLabelStr = CheckStrings[j];
- if (!CheckLabelStr.IsCheckLabel) {
+ if (CheckLabelStr.CheckTy != Check::CheckLabel) {
++j;
continue;
}
diff --git a/utils/FileUpdate/CMakeLists.txt b/utils/FileUpdate/CMakeLists.txt
index 655aaec..0114e50 100644
--- a/utils/FileUpdate/CMakeLists.txt
+++ b/utils/FileUpdate/CMakeLists.txt
@@ -4,7 +4,7 @@ add_llvm_utility(FileUpdate
target_link_libraries(FileUpdate LLVMSupport)
if( MINGW )
- target_link_libraries(FileUpdate imagehlp psapi)
+ target_link_libraries(FileUpdate imagehlp psapi shell32)
endif( MINGW )
if( LLVM_ENABLE_THREADS AND HAVE_LIBPTHREAD )
target_link_libraries(FileUpdate pthread)
diff --git a/utils/GetRepositoryPath b/utils/GetRepositoryPath
index f3b0cc5..2d1122e 100755
--- a/utils/GetRepositoryPath
+++ b/utils/GetRepositoryPath
@@ -15,11 +15,11 @@ fi
cd $1
if [ -d .svn ]; then
- svn info | grep 'URL:' | cut -d: -f2-
+ svn info | grep '^URL:' | cut -d: -f2-
elif [ -f .git/svn/.metadata ]; then
git svn info | grep 'URL:' | cut -d: -f2-
elif [ -d .git ]; then
- git remote -v | grep 'fetch' | awk '{ print $2 }'
+ git remote -v | grep 'fetch' | awk '{ print $2 }' | head -n1
else
exit 1;
fi
diff --git a/utils/Misc/mergefunctions.clang.svn.patch b/utils/Misc/mergefunctions.clang.svn.patch
new file mode 100644
index 0000000..6e2f0f5
--- /dev/null
+++ b/utils/Misc/mergefunctions.clang.svn.patch
@@ -0,0 +1,14 @@
+Index: lib/CodeGen/BackendUtil.cpp
+===================================================================
+--- lib/CodeGen/BackendUtil.cpp (revision 191330)
++++ lib/CodeGen/BackendUtil.cpp (working copy)
+@@ -336,6 +336,9 @@
+ MPM->add(createStripSymbolsPass(true));
+ }
+
++ // Force MergeFunctions pass.
++ MPM->add(createMergeFunctionsPass());
++
+ PMBuilder.populateModulePassManager(*MPM);
+ }
+
diff --git a/utils/TableGen/AsmMatcherEmitter.cpp b/utils/TableGen/AsmMatcherEmitter.cpp
index 468ce1c..de24cde 100644
--- a/utils/TableGen/AsmMatcherEmitter.cpp
+++ b/utils/TableGen/AsmMatcherEmitter.cpp
@@ -97,7 +97,6 @@
//===----------------------------------------------------------------------===//
#include "CodeGenTarget.h"
-#include "StringToOffsetTable.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/STLExtras.h"
@@ -110,8 +109,10 @@
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/StringMatcher.h"
+#include "llvm/TableGen/StringToOffsetTable.h"
#include "llvm/TableGen/TableGenBackend.h"
#include <cassert>
+#include <cctype>
#include <map>
#include <set>
#include <sstream>
@@ -125,6 +126,13 @@ namespace {
class AsmMatcherInfo;
struct SubtargetFeatureInfo;
+// Register sets are used as keys in some second-order sets TableGen creates
+// when generating its data structures. This means that the order of two
+// RegisterSets can be seen in the outputted AsmMatcher tables occasionally, and
+// can even affect compiler output (at least seen in diagnostics produced when
+// all matches fail). So we use a type that sorts them consistently.
+typedef std::set<Record*, LessRecordByID> RegisterSet;
+
class AsmMatcherEmitter {
RecordKeeper &Records;
public:
@@ -185,7 +193,7 @@ struct ClassInfo {
std::string ParserMethod;
/// For register classes, the records for all the registers in this class.
- std::set<Record*> Registers;
+ RegisterSet Registers;
/// For custom match classes, he diagnostic kind for when the predicate fails.
std::string DiagnosticType;
@@ -213,11 +221,11 @@ public:
if (!isRegisterClass() || !RHS.isRegisterClass())
return false;
- std::set<Record*> Tmp;
- std::insert_iterator< std::set<Record*> > II(Tmp, Tmp.begin());
+ RegisterSet Tmp;
+ std::insert_iterator<RegisterSet> II(Tmp, Tmp.begin());
std::set_intersection(Registers.begin(), Registers.end(),
RHS.Registers.begin(), RHS.Registers.end(),
- II);
+ II, LessRecordByID());
return !Tmp.empty();
}
@@ -430,6 +438,9 @@ struct MatchableInfo {
/// function.
std::string ConversionFnKind;
+ /// If this instruction is deprecated in some form.
+ bool HasDeprecation;
+
MatchableInfo(const CodeGenInstruction &CGI)
: AsmVariantID(0), TheDef(CGI.TheDef), DefRec(&CGI),
AsmString(CGI.AsmString) {
@@ -613,7 +624,7 @@ public:
RegisterClassesTy RegisterClasses;
/// Map of Predicate records to their subtarget information.
- std::map<Record*, SubtargetFeatureInfo*> SubtargetFeatures;
+ std::map<Record*, SubtargetFeatureInfo*, LessRecordByID> SubtargetFeatures;
/// Map of AsmOperandClass records to their class information.
std::map<Record*, ClassInfo*> AsmOperandClasses;
@@ -663,7 +674,7 @@ public:
/// given operand.
SubtargetFeatureInfo *getSubtargetFeature(Record *Def) const {
assert(Def->isSubClassOf("Predicate") && "Invalid predicate type!");
- std::map<Record*, SubtargetFeatureInfo*>::const_iterator I =
+ std::map<Record*, SubtargetFeatureInfo*, LessRecordByID>::const_iterator I =
SubtargetFeatures.find(Def);
return I == SubtargetFeatures.end() ? 0 : I->second;
}
@@ -779,6 +790,13 @@ void MatchableInfo::initialize(const AsmMatcherInfo &Info,
if (Record *Reg = AsmOperands[i].SingletonReg)
SingletonRegisters.insert(Reg);
}
+
+ const RecordVal *DepMask = TheDef->getValue("DeprecatedFeatureMask");
+ if (!DepMask)
+ DepMask = TheDef->getValue("ComplexDeprecationPredicate");
+
+ HasDeprecation =
+ DepMask ? !DepMask->getValue()->getAsUnquotedString().empty() : false;
}
/// tokenizeAsmString - Tokenize a simplified assembly string.
@@ -1047,6 +1065,18 @@ AsmMatcherInfo::getOperandClass(Record *Rec, int SubOpIdx) {
PrintFatalError(Rec->getLoc(), "operand has no match class!");
}
+struct LessRegisterSet {
+ bool operator() (const RegisterSet &LHS, const RegisterSet & RHS) const {
+ // std::set<T> defines its own compariso "operator<", but it
+ // performs a lexicographical comparison by T's innate comparison
+ // for some reason. We don't want non-deterministic pointer
+ // comparisons so use this instead.
+ return std::lexicographical_compare(LHS.begin(), LHS.end(),
+ RHS.begin(), RHS.end(),
+ LessRecordByID());
+ }
+};
+
void AsmMatcherInfo::
buildRegisterClasses(SmallPtrSet<Record*, 16> &SingletonRegisters) {
const std::vector<CodeGenRegister*> &Registers =
@@ -1054,33 +1084,35 @@ buildRegisterClasses(SmallPtrSet<Record*, 16> &SingletonRegisters) {
ArrayRef<CodeGenRegisterClass*> RegClassList =
Target.getRegBank().getRegClasses();
+ typedef std::set<RegisterSet, LessRegisterSet> RegisterSetSet;
+
// The register sets used for matching.
- std::set< std::set<Record*> > RegisterSets;
+ RegisterSetSet RegisterSets;
// Gather the defined sets.
for (ArrayRef<CodeGenRegisterClass*>::const_iterator it =
- RegClassList.begin(), ie = RegClassList.end(); it != ie; ++it)
- RegisterSets.insert(std::set<Record*>(
+ RegClassList.begin(), ie = RegClassList.end(); it != ie; ++it)
+ RegisterSets.insert(RegisterSet(
(*it)->getOrder().begin(), (*it)->getOrder().end()));
// Add any required singleton sets.
for (SmallPtrSet<Record*, 16>::iterator it = SingletonRegisters.begin(),
ie = SingletonRegisters.end(); it != ie; ++it) {
Record *Rec = *it;
- RegisterSets.insert(std::set<Record*>(&Rec, &Rec + 1));
+ RegisterSets.insert(RegisterSet(&Rec, &Rec + 1));
}
// Introduce derived sets where necessary (when a register does not determine
// a unique register set class), and build the mapping of registers to the set
// they should classify to.
- std::map<Record*, std::set<Record*> > RegisterMap;
+ std::map<Record*, RegisterSet> RegisterMap;
for (std::vector<CodeGenRegister*>::const_iterator it = Registers.begin(),
ie = Registers.end(); it != ie; ++it) {
const CodeGenRegister &CGR = **it;
// Compute the intersection of all sets containing this register.
- std::set<Record*> ContainingSet;
+ RegisterSet ContainingSet;
- for (std::set< std::set<Record*> >::iterator it = RegisterSets.begin(),
+ for (RegisterSetSet::iterator it = RegisterSets.begin(),
ie = RegisterSets.end(); it != ie; ++it) {
if (!it->count(CGR.TheDef))
continue;
@@ -1090,11 +1122,12 @@ buildRegisterClasses(SmallPtrSet<Record*, 16> &SingletonRegisters) {
continue;
}
- std::set<Record*> Tmp;
+ RegisterSet Tmp;
std::swap(Tmp, ContainingSet);
- std::insert_iterator< std::set<Record*> > II(ContainingSet,
- ContainingSet.begin());
- std::set_intersection(Tmp.begin(), Tmp.end(), it->begin(), it->end(), II);
+ std::insert_iterator<RegisterSet> II(ContainingSet,
+ ContainingSet.begin());
+ std::set_intersection(Tmp.begin(), Tmp.end(), it->begin(), it->end(), II,
+ LessRecordByID());
}
if (!ContainingSet.empty()) {
@@ -1104,9 +1137,9 @@ buildRegisterClasses(SmallPtrSet<Record*, 16> &SingletonRegisters) {
}
// Construct the register classes.
- std::map<std::set<Record*>, ClassInfo*> RegisterSetClasses;
+ std::map<RegisterSet, ClassInfo*, LessRegisterSet> RegisterSetClasses;
unsigned Index = 0;
- for (std::set< std::set<Record*> >::iterator it = RegisterSets.begin(),
+ for (RegisterSetSet::iterator it = RegisterSets.begin(),
ie = RegisterSets.end(); it != ie; ++it, ++Index) {
ClassInfo *CI = new ClassInfo();
CI->Kind = ClassInfo::RegisterClass0 + Index;
@@ -1124,13 +1157,14 @@ buildRegisterClasses(SmallPtrSet<Record*, 16> &SingletonRegisters) {
// Find the superclasses; we could compute only the subgroup lattice edges,
// but there isn't really a point.
- for (std::set< std::set<Record*> >::iterator it = RegisterSets.begin(),
+ for (RegisterSetSet::iterator it = RegisterSets.begin(),
ie = RegisterSets.end(); it != ie; ++it) {
ClassInfo *CI = RegisterSetClasses[*it];
- for (std::set< std::set<Record*> >::iterator it2 = RegisterSets.begin(),
+ for (RegisterSetSet::iterator it2 = RegisterSets.begin(),
ie2 = RegisterSets.end(); it2 != ie2; ++it2)
if (*it != *it2 &&
- std::includes(it2->begin(), it2->end(), it->begin(), it->end()))
+ std::includes(it2->begin(), it2->end(), it->begin(), it->end(),
+ LessRecordByID()))
CI->SuperClasses.push_back(RegisterSetClasses[*it2]);
}
@@ -1142,8 +1176,8 @@ buildRegisterClasses(SmallPtrSet<Record*, 16> &SingletonRegisters) {
Record *Def = RC.getDef();
if (!Def)
continue;
- ClassInfo *CI = RegisterSetClasses[std::set<Record*>(RC.getOrder().begin(),
- RC.getOrder().end())];
+ ClassInfo *CI = RegisterSetClasses[RegisterSet(RC.getOrder().begin(),
+ RC.getOrder().end())];
if (CI->ValueName.empty()) {
CI->ClassName = RC.getName();
CI->Name = "MCK_" + RC.getName();
@@ -1155,7 +1189,7 @@ buildRegisterClasses(SmallPtrSet<Record*, 16> &SingletonRegisters) {
}
// Populate the map for individual registers.
- for (std::map<Record*, std::set<Record*> >::iterator it = RegisterMap.begin(),
+ for (std::map<Record*, RegisterSet>::iterator it = RegisterMap.begin(),
ie = RegisterMap.end(); it != ie; ++it)
RegisterClasses[it->first] = RegisterSetClasses[it->second];
@@ -2179,7 +2213,7 @@ static void emitSubtargetFeatureFlagEnumeration(AsmMatcherInfo &Info,
OS << "// Flags for subtarget features that participate in "
<< "instruction matching.\n";
OS << "enum SubtargetFeatureFlag {\n";
- for (std::map<Record*, SubtargetFeatureInfo*>::const_iterator
+ for (std::map<Record*, SubtargetFeatureInfo*, LessRecordByID>::const_iterator
it = Info.SubtargetFeatures.begin(),
ie = Info.SubtargetFeatures.end(); it != ie; ++it) {
SubtargetFeatureInfo &SFI = *it->second;
@@ -2217,9 +2251,9 @@ static void emitGetSubtargetFeatureName(AsmMatcherInfo &Info, raw_ostream &OS) {
<< "static const char *getSubtargetFeatureName(unsigned Val) {\n";
if (!Info.SubtargetFeatures.empty()) {
OS << " switch(Val) {\n";
- for (std::map<Record*, SubtargetFeatureInfo*>::const_iterator
- it = Info.SubtargetFeatures.begin(),
- ie = Info.SubtargetFeatures.end(); it != ie; ++it) {
+ typedef std::map<Record*, SubtargetFeatureInfo*, LessRecordByID> RecFeatMap;
+ for (RecFeatMap::const_iterator it = Info.SubtargetFeatures.begin(),
+ ie = Info.SubtargetFeatures.end(); it != ie; ++it) {
SubtargetFeatureInfo &SFI = *it->second;
// FIXME: Totally just a placeholder name to get the algorithm working.
OS << " case " << SFI.getEnumName() << ": return \""
@@ -2244,7 +2278,7 @@ static void emitComputeAvailableFeatures(AsmMatcherInfo &Info,
OS << "unsigned " << Info.Target.getName() << ClassName << "::\n"
<< "ComputeAvailableFeatures(uint64_t FB) const {\n";
OS << " unsigned Features = 0;\n";
- for (std::map<Record*, SubtargetFeatureInfo*>::const_iterator
+ for (std::map<Record*, SubtargetFeatureInfo*, LessRecordByID>::const_iterator
it = Info.SubtargetFeatures.begin(),
ie = Info.SubtargetFeatures.end(); it != ie; ++it) {
SubtargetFeatureInfo &SFI = *it->second;
@@ -2743,11 +2777,13 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
size_t MaxNumOperands = 0;
unsigned MaxMnemonicIndex = 0;
+ bool HasDeprecation = false;
for (std::vector<MatchableInfo*>::const_iterator it =
Info.Matchables.begin(), ie = Info.Matchables.end();
it != ie; ++it) {
MatchableInfo &II = **it;
MaxNumOperands = std::max(MaxNumOperands, II.AsmOperands.size());
+ HasDeprecation |= II.HasDeprecation;
// Store a pascal-style length byte in the mnemonic.
std::string LenMnemonic = char(II.Mnemonic.size()) + II.Mnemonic.str();
@@ -2804,9 +2840,6 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
unsigned VariantCount = Target.getAsmParserVariantCount();
for (unsigned VC = 0; VC != VariantCount; ++VC) {
Record *AsmVariant = Target.getAsmParserVariant(VC);
- std::string CommentDelimiter =
- AsmVariant->getValueAsString("CommentDelimiter");
- std::string RegisterPrefix = AsmVariant->getValueAsString("RegisterPrefix");
int AsmVariantNo = AsmVariant->getValueAsInt("Variant");
OS << "static const MatchEntry MatchTable" << VC << "[] = {\n";
@@ -2857,9 +2890,6 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << " default: // unreachable\n";
for (unsigned VC = 0; VC != VariantCount; ++VC) {
Record *AsmVariant = Target.getAsmParserVariant(VC);
- std::string CommentDelimiter =
- AsmVariant->getValueAsString("CommentDelimiter");
- std::string RegisterPrefix = AsmVariant->getValueAsString("RegisterPrefix");
int AsmVariantNo = AsmVariant->getValueAsInt("Variant");
OS << " case " << AsmVariantNo << ": Start = MatchTable" << VC
<< "; End = array_endof(MatchTable" << VC << "); break;\n";
@@ -2915,9 +2945,6 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << " default: // unreachable\n";
for (unsigned VC = 0; VC != VariantCount; ++VC) {
Record *AsmVariant = Target.getAsmParserVariant(VC);
- std::string CommentDelimiter =
- AsmVariant->getValueAsString("CommentDelimiter");
- std::string RegisterPrefix = AsmVariant->getValueAsString("RegisterPrefix");
int AsmVariantNo = AsmVariant->getValueAsInt("Variant");
OS << " case " << AsmVariantNo << ": Start = MatchTable" << VC
<< "; End = array_endof(MatchTable" << VC << "); break;\n";
@@ -3018,6 +3045,14 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
if (!InsnCleanupFn.empty())
OS << " " << InsnCleanupFn << "(Inst);\n";
+ if (HasDeprecation) {
+ OS << " std::string Info;\n";
+ OS << " if (MII.get(Inst.getOpcode()).getDeprecatedInfo(Inst, STI, Info)) {\n";
+ OS << " SMLoc Loc = ((" << Target.getName() << "Operand*)Operands[0])->getStartLoc();\n";
+ OS << " Parser.Warning(Loc, Info, None);\n";
+ OS << " }\n";
+ }
+
OS << " return Match_Success;\n";
OS << " }\n\n";
diff --git a/utils/TableGen/AsmWriterEmitter.cpp b/utils/TableGen/AsmWriterEmitter.cpp
index ac8d896..a18b6b5 100644
--- a/utils/TableGen/AsmWriterEmitter.cpp
+++ b/utils/TableGen/AsmWriterEmitter.cpp
@@ -18,6 +18,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/Format.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
@@ -31,10 +32,12 @@ using namespace llvm;
namespace {
class AsmWriterEmitter {
RecordKeeper &Records;
+ CodeGenTarget Target;
std::map<const CodeGenInstruction*, AsmWriterInst*> CGIAWIMap;
std::vector<const CodeGenInstruction*> NumberedInstructions;
+ std::vector<AsmWriterInst> Instructions;
public:
- AsmWriterEmitter(RecordKeeper &R) : Records(R) {}
+ AsmWriterEmitter(RecordKeeper &R);
void run(raw_ostream &o);
@@ -272,9 +275,9 @@ static void UnescapeString(std::string &Str) {
}
/// EmitPrintInstruction - Generate the code for the "printInstruction" method
-/// implementation.
+/// implementation. Destroys all instances of AsmWriterInst information, by
+/// clearing the Instructions vector.
void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) {
- CodeGenTarget Target(Records);
Record *AsmWriter = Target.getAsmWriter();
std::string ClassName = AsmWriter->getValueAsString("AsmWriterClassName");
bool isMC = AsmWriter->getValueAsBit("isMCAsmWriter");
@@ -287,27 +290,6 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) {
<< "::printInstruction(const " << MachineInstrClassName
<< " *MI, raw_ostream &O) {\n";
- std::vector<AsmWriterInst> Instructions;
-
- for (CodeGenTarget::inst_iterator I = Target.inst_begin(),
- E = Target.inst_end(); I != E; ++I)
- if (!(*I)->AsmString.empty() &&
- (*I)->TheDef->getName() != "PHI")
- Instructions.push_back(
- AsmWriterInst(**I,
- AsmWriter->getValueAsInt("Variant"),
- AsmWriter->getValueAsInt("FirstOperandColumn"),
- AsmWriter->getValueAsInt("OperandSpacing")));
-
- // Get the instruction numbering.
- NumberedInstructions = Target.getInstructionsByEnumValue();
-
- // Compute the CodeGenInstruction -> AsmWriterInst mapping. Note that not
- // all machine instructions are necessarily being printed, so there may be
- // target instructions not in this map.
- for (unsigned i = 0, e = Instructions.size(); i != e; ++i)
- CGIAWIMap.insert(std::make_pair(Instructions[i].CGI, &Instructions[i]));
-
// Build an aggregate string, and build a table of offsets into it.
SequenceToOffsetTable<std::string> StringTable;
@@ -591,7 +573,6 @@ emitRegisterNameString(raw_ostream &O, StringRef AltName,
}
void AsmWriterEmitter::EmitGetRegisterName(raw_ostream &O) {
- CodeGenTarget Target(Records);
Record *AsmWriter = Target.getAsmWriter();
std::string ClassName = AsmWriter->getValueAsString("AsmWriterClassName");
const std::vector<CodeGenRegister*> &Registers =
@@ -657,7 +638,10 @@ public:
void addCond(const std::string &C) { Conds.push_back(C); }
- void addOperand(StringRef Op, unsigned Idx) { OpMap[Op] = Idx; }
+ void addOperand(StringRef Op, unsigned Idx) {
+ assert(Idx < 0xFF && "Index too large!");
+ OpMap[Op] = Idx;
+ }
unsigned getOpIndex(StringRef Op) { return OpMap[Op]; }
bool isOpMapped(StringRef Op) { return OpMap.find(Op) != OpMap.end(); }
@@ -681,12 +665,35 @@ public:
O << ") {\n";
O.indent(6) << "// " << Result << "\n";
- O.indent(6) << "AsmString = \"" << AsmString << "\";\n";
- for (std::map<StringRef, unsigned>::iterator
- I = OpMap.begin(), E = OpMap.end(); I != E; ++I)
- O.indent(6) << "OpMap.push_back(std::make_pair(\"" << I->first << "\", "
- << I->second << "));\n";
+ // Directly mangle mapped operands into the string. Each operand is
+ // identified by a '$' sign followed by a byte identifying the number of the
+ // operand. We add one to the index to avoid zero bytes.
+ std::pair<StringRef, StringRef> ASM = StringRef(AsmString).split(' ');
+ SmallString<128> OutString = ASM.first;
+ if (!ASM.second.empty()) {
+ raw_svector_ostream OS(OutString);
+ OS << ' ';
+ for (StringRef::iterator I = ASM.second.begin(), E = ASM.second.end();
+ I != E;) {
+ OS << *I;
+ if (*I == '$') {
+ StringRef::iterator Start = ++I;
+ while (I != E &&
+ ((*I >= 'a' && *I <= 'z') || (*I >= 'A' && *I <= 'Z') ||
+ (*I >= '0' && *I <= '9') || *I == '_'))
+ ++I;
+ StringRef Name(Start, I - Start);
+ assert(isOpMapped(Name) && "Unmapped operand!");
+ OS << format("\\x%02X", (unsigned char)getOpIndex(Name) + 1);
+ } else {
+ ++I;
+ }
+ }
+ }
+
+ // Emit the string.
+ O.indent(6) << "AsmString = \"" << OutString.str() << "\";\n";
O.indent(6) << "break;\n";
O.indent(4) << '}';
@@ -721,19 +728,6 @@ public:
} // end anonymous namespace
-static void EmitGetMapOperandNumber(raw_ostream &O) {
- O << "static unsigned getMapOperandNumber("
- << "const SmallVectorImpl<std::pair<StringRef, unsigned> > &OpMap,\n";
- O << " StringRef Name) {\n";
- O << " for (SmallVectorImpl<std::pair<StringRef, unsigned> >::"
- << "const_iterator\n";
- O << " I = OpMap.begin(), E = OpMap.end(); I != E; ++I)\n";
- O << " if (I->first == Name)\n";
- O << " return I->second;\n";
- O << " llvm_unreachable(\"Operand not in map!\");\n";
- O << "}\n\n";
-}
-
static unsigned CountNumOperands(StringRef AsmString) {
unsigned NumOps = 0;
std::pair<StringRef, StringRef> ASM = AsmString.split(' ');
@@ -768,7 +762,6 @@ static unsigned CountResultNumOperands(StringRef AsmString) {
}
void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) {
- CodeGenTarget Target(Records);
Record *AsmWriter = Target.getAsmWriter();
if (!AsmWriter->getValueAsBit("isMCAsmWriter"))
@@ -822,7 +815,6 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) {
Cond = std::string("MI->getNumOperands() == ") + llvm::utostr(LastOpNo);
IAP->addCond(Cond);
- std::map<StringRef, unsigned> OpMap;
bool CantHandle = false;
for (unsigned i = 0, e = LastOpNo; i != e; ++i) {
@@ -955,11 +947,8 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) {
return;
}
- EmitGetMapOperandNumber(O);
-
O << HeaderO.str();
- O.indent(2) << "StringRef AsmString;\n";
- O.indent(2) << "SmallVector<std::pair<StringRef, unsigned>, 4> OpMap;\n";
+ O.indent(2) << "const char *AsmString;\n";
O.indent(2) << "switch (MI->getOpcode()) {\n";
O.indent(2) << "default: return false;\n";
O << CasesO.str();
@@ -967,27 +956,21 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) {
// Code that prints the alias, replacing the operands with the ones from the
// MCInst.
- O << " std::pair<StringRef, StringRef> ASM = AsmString.split(' ');\n";
- O << " OS << '\\t' << ASM.first;\n";
+ O << " unsigned I = 0;\n";
+ O << " while (AsmString[I] != ' ' && AsmString[I] != '\\0')\n";
+ O << " ++I;\n";
+ O << " OS << '\\t' << StringRef(AsmString, I);\n";
- O << " if (!ASM.second.empty()) {\n";
+ O << " if (AsmString[I] != '\\0') {\n";
O << " OS << '\\t';\n";
- O << " for (StringRef::iterator\n";
- O << " I = ASM.second.begin(), E = ASM.second.end(); I != E; ) {\n";
- O << " if (*I == '$') {\n";
- O << " StringRef::iterator Start = ++I;\n";
- O << " while (I != E &&\n";
- O << " ((*I >= 'a' && *I <= 'z') ||\n";
- O << " (*I >= 'A' && *I <= 'Z') ||\n";
- O << " (*I >= '0' && *I <= '9') ||\n";
- O << " *I == '_'))\n";
- O << " ++I;\n";
- O << " StringRef Name(Start, I - Start);\n";
- O << " printOperand(MI, getMapOperandNumber(OpMap, Name), OS);\n";
+ O << " do {\n";
+ O << " if (AsmString[I] == '$') {\n";
+ O << " ++I;\n";
+ O << " printOperand(MI, unsigned(AsmString[I++]) - 1, OS);\n";
O << " } else {\n";
- O << " OS << *I++;\n";
+ O << " OS << AsmString[I++];\n";
O << " }\n";
- O << " }\n";
+ O << " } while (AsmString[I] != '\\0');\n";
O << " }\n\n";
O << " return true;\n";
@@ -996,6 +979,27 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) {
O << "#endif // PRINT_ALIAS_INSTR\n";
}
+AsmWriterEmitter::AsmWriterEmitter(RecordKeeper &R) : Records(R), Target(R) {
+ Record *AsmWriter = Target.getAsmWriter();
+ for (CodeGenTarget::inst_iterator I = Target.inst_begin(),
+ E = Target.inst_end();
+ I != E; ++I)
+ if (!(*I)->AsmString.empty() && (*I)->TheDef->getName() != "PHI")
+ Instructions.push_back(
+ AsmWriterInst(**I, AsmWriter->getValueAsInt("Variant"),
+ AsmWriter->getValueAsInt("FirstOperandColumn"),
+ AsmWriter->getValueAsInt("OperandSpacing")));
+
+ // Get the instruction numbering.
+ NumberedInstructions = Target.getInstructionsByEnumValue();
+
+ // Compute the CodeGenInstruction -> AsmWriterInst mapping. Note that not
+ // all machine instructions are necessarily being printed, so there may be
+ // target instructions not in this map.
+ for (unsigned i = 0, e = Instructions.size(); i != e; ++i)
+ CGIAWIMap.insert(std::make_pair(Instructions[i].CGI, &Instructions[i]));
+}
+
void AsmWriterEmitter::run(raw_ostream &O) {
EmitPrintInstruction(O);
EmitGetRegisterName(O);
diff --git a/utils/TableGen/CodeGenDAGPatterns.cpp b/utils/TableGen/CodeGenDAGPatterns.cpp
index ee025a0..717090a 100644
--- a/utils/TableGen/CodeGenDAGPatterns.cpp
+++ b/utils/TableGen/CodeGenDAGPatterns.cpp
@@ -30,16 +30,16 @@ using namespace llvm;
//===----------------------------------------------------------------------===//
static inline bool isInteger(MVT::SimpleValueType VT) {
- return EVT(VT).isInteger();
+ return MVT(VT).isInteger();
}
static inline bool isFloatingPoint(MVT::SimpleValueType VT) {
- return EVT(VT).isFloatingPoint();
+ return MVT(VT).isFloatingPoint();
}
static inline bool isVector(MVT::SimpleValueType VT) {
- return EVT(VT).isVector();
+ return MVT(VT).isVector();
}
static inline bool isScalar(MVT::SimpleValueType VT) {
- return !EVT(VT).isVector();
+ return !MVT(VT).isVector();
}
EEVT::TypeSet::TypeSet(MVT::SimpleValueType VT, TreePattern &TP) {
@@ -385,8 +385,8 @@ bool EEVT::TypeSet::EnforceSmallerThan(EEVT::TypeSet &Other, TreePattern &TP) {
// Otherwise, if these are both vector types, either this vector
// must have a larger bitsize than the other, or this element type
// must be larger than the other.
- EVT Type(TypeVec[0]);
- EVT OtherType(Other.TypeVec[0]);
+ MVT Type(TypeVec[0]);
+ MVT OtherType(Other.TypeVec[0]);
if (hasVectorTypes() && Other.hasVectorTypes()) {
if (Type.getSizeInBits() >= OtherType.getSizeInBits())
@@ -397,8 +397,7 @@ bool EEVT::TypeSet::EnforceSmallerThan(EEVT::TypeSet &Other, TreePattern &TP) {
Other.getName() +"'!");
return false;
}
- }
- else
+ } else
// For scalar types, the bitsize of this type must be larger
// than that of the other.
if (Type.getSizeInBits() >= OtherType.getSizeInBits()) {
@@ -450,8 +449,7 @@ bool EEVT::TypeSet::EnforceSmallerThan(EEVT::TypeSet &Other, TreePattern &TP) {
MadeChange = true;
continue;
}
- }
- else if (isFloatingPoint(*TVI)) {
+ } else if (isFloatingPoint(*TVI)) {
++OtherFPSize;
if (*TVI == SmallestFP) {
TVI = Other.TypeVec.erase(TVI);
@@ -465,8 +463,8 @@ bool EEVT::TypeSet::EnforceSmallerThan(EEVT::TypeSet &Other, TreePattern &TP) {
// If this is the only type in the large set, the constraint can never be
// satisfied.
- if ((Other.hasIntegerTypes() && OtherIntSize == 0)
- || (Other.hasFloatingPointTypes() && OtherFPSize == 0)) {
+ if ((Other.hasIntegerTypes() && OtherIntSize == 0) ||
+ (Other.hasFloatingPointTypes() && OtherFPSize == 0)) {
TP.error("Type inference contradiction found, '" +
Other.getName() + "' has nothing larger than '" + getName() +"'!");
return false;
@@ -508,8 +506,7 @@ bool EEVT::TypeSet::EnforceSmallerThan(EEVT::TypeSet &Other, TreePattern &TP) {
MadeChange = true;
continue;
}
- }
- else if (isFloatingPoint(*TVI)) {
+ } else if (isFloatingPoint(*TVI)) {
++FPSize;
if (*TVI == LargestFP) {
TVI = TypeVec.erase(TVI);
@@ -523,8 +520,8 @@ bool EEVT::TypeSet::EnforceSmallerThan(EEVT::TypeSet &Other, TreePattern &TP) {
// If this is the only type in the small set, the constraint can never be
// satisfied.
- if ((hasIntegerTypes() && IntSize == 0)
- || (hasFloatingPointTypes() && FPSize == 0)) {
+ if ((hasIntegerTypes() && IntSize == 0) ||
+ (hasFloatingPointTypes() && FPSize == 0)) {
TP.error("Type inference contradiction found, '" +
getName() + "' has nothing smaller than '" + Other.getName()+"'!");
return false;
@@ -547,10 +544,10 @@ bool EEVT::TypeSet::EnforceVectorEltTypeIs(EEVT::TypeSet &VTOperand,
// If we know the vector type, it forces the scalar to agree.
if (isConcrete()) {
- EVT IVT = getConcrete();
+ MVT IVT = getConcrete();
IVT = IVT.getVectorElementType();
return MadeChange |
- VTOperand.MergeInTypeInfo(IVT.getSimpleVT().SimpleTy, TP);
+ VTOperand.MergeInTypeInfo(IVT.SimpleTy, TP);
}
// If the scalar type is known, filter out vector types whose element types
@@ -565,7 +562,7 @@ bool EEVT::TypeSet::EnforceVectorEltTypeIs(EEVT::TypeSet &VTOperand,
// Filter out all the types which don't have the right element type.
for (unsigned i = 0; i != TypeVec.size(); ++i) {
assert(isVector(TypeVec[i]) && "EnforceVector didn't work");
- if (EVT(TypeVec[i]).getVectorElementType().getSimpleVT().SimpleTy != VT) {
+ if (MVT(TypeVec[i]).getVectorElementType().SimpleTy != VT) {
TypeVec.erase(TypeVec.begin()+i--);
MadeChange = true;
}
@@ -593,16 +590,16 @@ bool EEVT::TypeSet::EnforceVectorSubVectorTypeIs(EEVT::TypeSet &VTOperand,
// If we know the vector type, it forces the scalar types to agree.
if (isConcrete()) {
- EVT IVT = getConcrete();
+ MVT IVT = getConcrete();
IVT = IVT.getVectorElementType();
- EEVT::TypeSet EltTypeSet(IVT.getSimpleVT().SimpleTy, TP);
+ EEVT::TypeSet EltTypeSet(IVT.SimpleTy, TP);
MadeChange |= VTOperand.EnforceVectorEltTypeIs(EltTypeSet, TP);
} else if (VTOperand.isConcrete()) {
- EVT IVT = VTOperand.getConcrete();
+ MVT IVT = VTOperand.getConcrete();
IVT = IVT.getVectorElementType();
- EEVT::TypeSet EltTypeSet(IVT.getSimpleVT().SimpleTy, TP);
+ EEVT::TypeSet EltTypeSet(IVT.SimpleTy, TP);
MadeChange |= EnforceVectorEltTypeIs(EltTypeSet, TP);
}
@@ -1522,7 +1519,7 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) {
if (VT == MVT::iPTR || VT == MVT::iPTRAny)
return MadeChange;
- unsigned Size = EVT(VT).getSizeInBits();
+ unsigned Size = MVT(VT).getSizeInBits();
// Make sure that the value is representable for this type.
if (Size >= 32) return MadeChange;
@@ -2678,54 +2675,13 @@ static bool checkOperandClass(CGIOperandList::OperandInfo &OI,
return false;
}
-/// ParseInstructions - Parse all of the instructions, inlining and resolving
-/// any fragments involved. This populates the Instructions list with fully
-/// resolved instructions.
-void CodeGenDAGPatterns::ParseInstructions() {
- std::vector<Record*> Instrs = Records.getAllDerivedDefinitions("Instruction");
-
- for (unsigned i = 0, e = Instrs.size(); i != e; ++i) {
- ListInit *LI = 0;
+const DAGInstruction &CodeGenDAGPatterns::parseInstructionPattern(
+ CodeGenInstruction &CGI, ListInit *Pat, DAGInstMap &DAGInsts) {
- if (isa<ListInit>(Instrs[i]->getValueInit("Pattern")))
- LI = Instrs[i]->getValueAsListInit("Pattern");
-
- // If there is no pattern, only collect minimal information about the
- // instruction for its operand list. We have to assume that there is one
- // result, as we have no detailed info. A pattern which references the
- // null_frag operator is as-if no pattern were specified. Normally this
- // is from a multiclass expansion w/ a SDPatternOperator passed in as
- // null_frag.
- if (!LI || LI->getSize() == 0 || hasNullFragReference(LI)) {
- std::vector<Record*> Results;
- std::vector<Record*> Operands;
-
- CodeGenInstruction &InstInfo = Target.getInstruction(Instrs[i]);
-
- if (InstInfo.Operands.size() != 0) {
- if (InstInfo.Operands.NumDefs == 0) {
- // These produce no results
- for (unsigned j = 0, e = InstInfo.Operands.size(); j < e; ++j)
- Operands.push_back(InstInfo.Operands[j].Rec);
- } else {
- // Assume the first operand is the result.
- Results.push_back(InstInfo.Operands[0].Rec);
-
- // The rest are inputs.
- for (unsigned j = 1, e = InstInfo.Operands.size(); j < e; ++j)
- Operands.push_back(InstInfo.Operands[j].Rec);
- }
- }
-
- // Create and insert the instruction.
- std::vector<Record*> ImpResults;
- Instructions.insert(std::make_pair(Instrs[i],
- DAGInstruction(0, Results, Operands, ImpResults)));
- continue; // no pattern.
- }
+ assert(!DAGInsts.count(CGI.TheDef) && "Instruction already parsed!");
// Parse the instruction.
- TreePattern *I = new TreePattern(Instrs[i], LI, true, *this);
+ TreePattern *I = new TreePattern(CGI.TheDef, Pat, true, *this);
// Inline pattern fragments into it.
I->InlinePatternFragments();
@@ -2764,7 +2720,6 @@ void CodeGenDAGPatterns::ParseInstructions() {
// Parse the operands list from the (ops) list, validating it.
assert(I->getArgList().empty() && "Args list should still be empty here!");
- CodeGenInstruction &CGI = Target.getInstruction(Instrs[i]);
// Check that all of the results occur first in the list.
std::vector<Record*> Results;
@@ -2863,18 +2818,71 @@ void CodeGenDAGPatterns::ParseInstructions() {
// Create and insert the instruction.
// FIXME: InstImpResults should not be part of DAGInstruction.
DAGInstruction TheInst(I, Results, Operands, InstImpResults);
- Instructions.insert(std::make_pair(I->getRecord(), TheInst));
+ DAGInsts.insert(std::make_pair(I->getRecord(), TheInst));
// Use a temporary tree pattern to infer all types and make sure that the
// constructed result is correct. This depends on the instruction already
- // being inserted into the Instructions map.
+ // being inserted into the DAGInsts map.
TreePattern Temp(I->getRecord(), ResultPattern, false, *this);
Temp.InferAllTypes(&I->getNamedNodesMap());
- DAGInstruction &TheInsertedInst = Instructions.find(I->getRecord())->second;
+ DAGInstruction &TheInsertedInst = DAGInsts.find(I->getRecord())->second;
TheInsertedInst.setResultPattern(Temp.getOnlyTree());
- DEBUG(I->dump());
+ return TheInsertedInst;
+ }
+
+/// ParseInstructions - Parse all of the instructions, inlining and resolving
+/// any fragments involved. This populates the Instructions list with fully
+/// resolved instructions.
+void CodeGenDAGPatterns::ParseInstructions() {
+ std::vector<Record*> Instrs = Records.getAllDerivedDefinitions("Instruction");
+
+ for (unsigned i = 0, e = Instrs.size(); i != e; ++i) {
+ ListInit *LI = 0;
+
+ if (isa<ListInit>(Instrs[i]->getValueInit("Pattern")))
+ LI = Instrs[i]->getValueAsListInit("Pattern");
+
+ // If there is no pattern, only collect minimal information about the
+ // instruction for its operand list. We have to assume that there is one
+ // result, as we have no detailed info. A pattern which references the
+ // null_frag operator is as-if no pattern were specified. Normally this
+ // is from a multiclass expansion w/ a SDPatternOperator passed in as
+ // null_frag.
+ if (!LI || LI->getSize() == 0 || hasNullFragReference(LI)) {
+ std::vector<Record*> Results;
+ std::vector<Record*> Operands;
+
+ CodeGenInstruction &InstInfo = Target.getInstruction(Instrs[i]);
+
+ if (InstInfo.Operands.size() != 0) {
+ if (InstInfo.Operands.NumDefs == 0) {
+ // These produce no results
+ for (unsigned j = 0, e = InstInfo.Operands.size(); j < e; ++j)
+ Operands.push_back(InstInfo.Operands[j].Rec);
+ } else {
+ // Assume the first operand is the result.
+ Results.push_back(InstInfo.Operands[0].Rec);
+
+ // The rest are inputs.
+ for (unsigned j = 1, e = InstInfo.Operands.size(); j < e; ++j)
+ Operands.push_back(InstInfo.Operands[j].Rec);
+ }
+ }
+
+ // Create and insert the instruction.
+ std::vector<Record*> ImpResults;
+ Instructions.insert(std::make_pair(Instrs[i],
+ DAGInstruction(0, Results, Operands, ImpResults)));
+ continue; // no pattern.
+ }
+
+ CodeGenInstruction &CGI = Target.getInstruction(Instrs[i]);
+ const DAGInstruction &DI = parseInstructionPattern(CGI, LI, Instructions);
+
+ (void)DI;
+ DEBUG(DI.getPattern()->dump());
}
// If we can, convert the instructions to be patterns that are matched!
diff --git a/utils/TableGen/CodeGenDAGPatterns.h b/utils/TableGen/CodeGenDAGPatterns.h
index 7c2fa36..6fbdd4f 100644
--- a/utils/TableGen/CodeGenDAGPatterns.h
+++ b/utils/TableGen/CodeGenDAGPatterns.h
@@ -778,7 +778,11 @@ public:
ptm_iterator ptm_begin() const { return PatternsToMatch.begin(); }
ptm_iterator ptm_end() const { return PatternsToMatch.end(); }
-
+ /// Parse the Pattern for an instruction, and insert the result in DAGInsts.
+ typedef std::map<Record*, DAGInstruction, LessRecordByID> DAGInstMap;
+ const DAGInstruction &parseInstructionPattern(
+ CodeGenInstruction &CGI, ListInit *Pattern,
+ DAGInstMap &DAGInsts);
const DAGInstruction &getInstruction(Record *R) const {
assert(Instructions.count(R) && "Unknown instruction!");
diff --git a/utils/TableGen/CodeGenInstruction.cpp b/utils/TableGen/CodeGenInstruction.cpp
index 3673204..576388b 100644
--- a/utils/TableGen/CodeGenInstruction.cpp
+++ b/utils/TableGen/CodeGenInstruction.cpp
@@ -90,7 +90,7 @@ CGIOperandList::CGIOperandList(Record *R) : TheDef(R) {
if (unsigned NumArgs = MIOpInfo->getNumArgs())
NumOps = NumArgs;
- if (Rec->isSubClassOf("PredicateOperand"))
+ if (Rec->isSubClassOf("PredicateOp"))
isPredicable = true;
else if (Rec->isSubClassOf("OptionalDefOperand"))
hasOptionalDef = true;
@@ -192,6 +192,7 @@ CGIOperandList::ParseOperandName(const std::string &Op, bool AllowWholeOp) {
// Otherwise, didn't find it!
PrintFatalError(TheDef->getName() + ": unknown suboperand name in '" + Op + "'");
+ return std::make_pair(0U, 0U);
}
static void ParseConstraint(const std::string &CStr, CGIOperandList &Ops) {
@@ -336,6 +337,20 @@ CodeGenInstruction::CodeGenInstruction(Record *R)
// Parse the DisableEncoding field.
Operands.ProcessDisableEncoding(R->getValueAsString("DisableEncoding"));
+
+ // First check for a ComplexDeprecationPredicate.
+ if (R->getValue("ComplexDeprecationPredicate")) {
+ HasComplexDeprecationPredicate = true;
+ DeprecatedReason = R->getValueAsString("ComplexDeprecationPredicate");
+ } else if (RecordVal *Dep = R->getValue("DeprecatedFeatureMask")) {
+ // Check if we have a Subtarget feature mask.
+ HasComplexDeprecationPredicate = false;
+ DeprecatedReason = Dep->getValue()->getAsString();
+ } else {
+ // This instruction isn't deprecated.
+ HasComplexDeprecationPredicate = false;
+ DeprecatedReason = "";
+ }
}
/// HasOneImplicitDefWithKnownVT - If the instruction has at least one
diff --git a/utils/TableGen/CodeGenInstruction.h b/utils/TableGen/CodeGenInstruction.h
index d1e1153..6004f66 100644
--- a/utils/TableGen/CodeGenInstruction.h
+++ b/utils/TableGen/CodeGenInstruction.h
@@ -248,6 +248,9 @@ namespace llvm {
bool isCodeGenOnly;
bool isPseudo;
+ std::string DeprecatedReason;
+ bool HasComplexDeprecationPredicate;
+
/// Are there any undefined flags?
bool hasUndefFlags() const {
return mayLoad_Unset || mayStore_Unset || hasSideEffects_Unset;
diff --git a/utils/TableGen/CodeGenMapTable.cpp b/utils/TableGen/CodeGenMapTable.cpp
index ee32aa1..cb7ec3e 100644
--- a/utils/TableGen/CodeGenMapTable.cpp
+++ b/utils/TableGen/CodeGenMapTable.cpp
@@ -240,7 +240,6 @@ public:
void MapTableEmitter::buildRowInstrMap() {
for (unsigned i = 0, e = InstrDefs.size(); i < e; i++) {
- std::vector<Record*> InstrList;
Record *CurInstr = InstrDefs[i];
std::vector<Init*> KeyValue;
ListInit *RowFields = InstrMapDesc.getRowFields();
diff --git a/utils/TableGen/CodeGenRegisters.cpp b/utils/TableGen/CodeGenRegisters.cpp
index 43de2be..f2eef4f 100644
--- a/utils/TableGen/CodeGenRegisters.cpp
+++ b/utils/TableGen/CodeGenRegisters.cpp
@@ -813,9 +813,10 @@ static bool testSubClass(const CodeGenRegisterClass *A,
/// Register classes with the same registers, spill size, and alignment form a
/// clique. They will be ordered alphabetically.
///
-static int TopoOrderRC(const void *PA, const void *PB) {
- const CodeGenRegisterClass *A = *(const CodeGenRegisterClass* const*)PA;
- const CodeGenRegisterClass *B = *(const CodeGenRegisterClass* const*)PB;
+static int TopoOrderRC(CodeGenRegisterClass *const *PA,
+ CodeGenRegisterClass *const *PB) {
+ const CodeGenRegisterClass *A = *PA;
+ const CodeGenRegisterClass *B = *PB;
if (A == B)
return 0;
diff --git a/utils/TableGen/CodeGenSchedule.cpp b/utils/TableGen/CodeGenSchedule.cpp
index 001e97d..dd06433 100644
--- a/utils/TableGen/CodeGenSchedule.cpp
+++ b/utils/TableGen/CodeGenSchedule.cpp
@@ -36,10 +36,11 @@ static void dumpIdxVec(const SmallVectorImpl<unsigned> &V) {
}
#endif
+namespace {
// (instrs a, b, ...) Evaluate and union all arguments. Identical to AddOp.
struct InstrsOp : public SetTheory::Operator {
- void apply(SetTheory &ST, DagInit *Expr, SetTheory::RecSet &Elts,
- ArrayRef<SMLoc> Loc) {
+ virtual void apply(SetTheory &ST, DagInit *Expr, SetTheory::RecSet &Elts,
+ ArrayRef<SMLoc> Loc) {
ST.evaluate(Expr->arg_begin(), Expr->arg_end(), Elts, Loc);
}
};
@@ -84,6 +85,7 @@ struct InstRegexOp : public SetTheory::Operator {
DeleteContainerPointers(RegexList);
}
};
+} // end anonymous namespace
/// CodeGenModels ctor interprets machine model records and populates maps.
CodeGenSchedModels::CodeGenSchedModels(RecordKeeper &RK,
diff --git a/utils/TableGen/CodeGenTarget.cpp b/utils/TableGen/CodeGenTarget.cpp
index b2c883d..dd17059 100644
--- a/utils/TableGen/CodeGenTarget.cpp
+++ b/utils/TableGen/CodeGenTarget.cpp
@@ -75,6 +75,7 @@ std::string llvm::getEnumName(MVT::SimpleValueType T) {
case MVT::v16i1: return "MVT::v16i1";
case MVT::v32i1: return "MVT::v32i1";
case MVT::v64i1: return "MVT::v64i1";
+ case MVT::v1i8: return "MVT::v1i8";
case MVT::v2i8: return "MVT::v2i8";
case MVT::v4i8: return "MVT::v4i8";
case MVT::v8i8: return "MVT::v8i8";
@@ -98,10 +99,14 @@ std::string llvm::getEnumName(MVT::SimpleValueType T) {
case MVT::v8i64: return "MVT::v8i64";
case MVT::v16i64: return "MVT::v16i64";
case MVT::v2f16: return "MVT::v2f16";
+ case MVT::v4f16: return "MVT::v4f16";
+ case MVT::v8f16: return "MVT::v8f16";
+ case MVT::v1f32: return "MVT::v1f32";
case MVT::v2f32: return "MVT::v2f32";
case MVT::v4f32: return "MVT::v4f32";
case MVT::v8f32: return "MVT::v8f32";
case MVT::v16f32: return "MVT::v16f32";
+ case MVT::v1f64: return "MVT::v1f64";
case MVT::v2f64: return "MVT::v2f64";
case MVT::v4f64: return "MVT::v4f64";
case MVT::v8f64: return "MVT::v8f64";
@@ -316,6 +321,8 @@ void CodeGenTarget::ComputeInstrsByEnum() const {
"BUNDLE",
"LIFETIME_START",
"LIFETIME_END",
+ "STACKMAP",
+ "PATCHPOINT",
0
};
const DenseMap<const Record*, CodeGenInstruction*> &Insts = getInstructions();
diff --git a/utils/TableGen/DAGISelEmitter.cpp b/utils/TableGen/DAGISelEmitter.cpp
index b47dd71..a76ea32 100644
--- a/utils/TableGen/DAGISelEmitter.cpp
+++ b/utils/TableGen/DAGISelEmitter.cpp
@@ -81,15 +81,13 @@ struct PatternSortingPredicate {
const TreePatternNode *LHSSrc = LHS->getSrcPattern();
const TreePatternNode *RHSSrc = RHS->getSrcPattern();
- if (LHSSrc->getNumTypes() != 0 && RHSSrc->getNumTypes() != 0 &&
- LHSSrc->getType(0) != RHSSrc->getType(0)) {
- MVT::SimpleValueType V1 = LHSSrc->getType(0), V2 = RHSSrc->getType(0);
- if (MVT(V1).isVector() != MVT(V2).isVector())
- return MVT(V2).isVector();
-
- if (MVT(V1).isFloatingPoint() != MVT(V2).isFloatingPoint())
- return MVT(V2).isFloatingPoint();
- }
+ MVT LHSVT = (LHSSrc->getNumTypes() != 0 ? LHSSrc->getType(0) : MVT::Other);
+ MVT RHSVT = (RHSSrc->getNumTypes() != 0 ? RHSSrc->getType(0) : MVT::Other);
+ if (LHSVT.isVector() != RHSVT.isVector())
+ return RHSVT.isVector();
+
+ if (LHSVT.isFloatingPoint() != RHSVT.isFloatingPoint())
+ return RHSVT.isFloatingPoint();
// Otherwise, if the patterns might both match, sort based on complexity,
// which means that we prefer to match patterns that cover more nodes in the
diff --git a/utils/TableGen/DAGISelMatcher.cpp b/utils/TableGen/DAGISelMatcher.cpp
index d173cf0..5d6a11a 100644
--- a/utils/TableGen/DAGISelMatcher.cpp
+++ b/utils/TableGen/DAGISelMatcher.cpp
@@ -63,7 +63,7 @@ bool Matcher::canMoveBefore(const Matcher *Other) const {
}
}
-/// canMoveBefore - Return true if it is safe to move the current matcher
+/// canMoveBeforeNode - Return true if it is safe to move the current matcher
/// across the specified one.
bool Matcher::canMoveBeforeNode(const Matcher *Other) const {
// We can move simple predicates before record nodes.
@@ -134,6 +134,10 @@ void CheckSameMatcher::printImpl(raw_ostream &OS, unsigned indent) const {
OS.indent(indent) << "CheckSame " << MatchNumber << '\n';
}
+void CheckChildSameMatcher::printImpl(raw_ostream &OS, unsigned indent) const {
+ OS.indent(indent) << "CheckChild" << ChildNo << "Same\n";
+}
+
void CheckPatternPredicateMatcher::
printImpl(raw_ostream &OS, unsigned indent) const {
OS.indent(indent) << "CheckPatternPredicate " << Predicate << '\n';
diff --git a/utils/TableGen/DAGISelMatcher.h b/utils/TableGen/DAGISelMatcher.h
index f978188..70031fa 100644
--- a/utils/TableGen/DAGISelMatcher.h
+++ b/utils/TableGen/DAGISelMatcher.h
@@ -55,6 +55,7 @@ public:
// Predicate checking.
CheckSame, // Fail if not same as prev match.
+ CheckChildSame, // Fail if child not same as prev match.
CheckPatternPredicate,
CheckPredicate, // Fail if node predicate fails.
CheckOpcode, // Fail if not opcode.
@@ -122,6 +123,7 @@ public:
switch (getKind()) {
default: return false;
case CheckSame:
+ case CheckChildSame:
case CheckPatternPredicate:
case CheckPredicate:
case CheckOpcode:
@@ -154,7 +156,7 @@ public:
/// node. Other must be equal to or before this.
bool canMoveBefore(const Matcher *Other) const;
- /// canMoveBefore - Return true if it is safe to move the current matcher
+ /// canMoveBeforeNode - Return true if it is safe to move the current matcher
/// across the specified one.
bool canMoveBeforeNode(const Matcher *Other) const;
@@ -392,6 +394,34 @@ private:
virtual unsigned getHashImpl() const { return getMatchNumber(); }
};
+/// CheckChildSameMatcher - This checks to see if child node is exactly the same
+/// node as the specified match that was recorded with 'Record'. This is used
+/// when patterns have the same name in them, like '(mul GPR:$in, GPR:$in)'.
+class CheckChildSameMatcher : public Matcher {
+ unsigned ChildNo;
+ unsigned MatchNumber;
+public:
+ CheckChildSameMatcher(unsigned childno, unsigned matchnumber)
+ : Matcher(CheckChildSame), ChildNo(childno), MatchNumber(matchnumber) {}
+
+ unsigned getChildNo() const { return ChildNo; }
+ unsigned getMatchNumber() const { return MatchNumber; }
+
+ static inline bool classof(const Matcher *N) {
+ return N->getKind() == CheckChildSame;
+ }
+
+ virtual bool isSafeToReorderWithPatternPredicate() const { return true; }
+
+private:
+ virtual void printImpl(raw_ostream &OS, unsigned indent) const;
+ virtual bool isEqualImpl(const Matcher *M) const {
+ return cast<CheckChildSameMatcher>(M)->ChildNo == ChildNo &&
+ cast<CheckChildSameMatcher>(M)->MatchNumber == MatchNumber;
+ }
+ virtual unsigned getHashImpl() const { return (MatchNumber << 2) | ChildNo; }
+};
+
/// CheckPatternPredicateMatcher - This checks the target-specific predicate
/// to see if the entire pattern is capable of matching. This predicate does
/// not take a node as input. This is used for subtarget feature checks etc.
diff --git a/utils/TableGen/DAGISelMatcherEmitter.cpp b/utils/TableGen/DAGISelMatcherEmitter.cpp
index 93f84ce..04fe0d1 100644
--- a/utils/TableGen/DAGISelMatcherEmitter.cpp
+++ b/utils/TableGen/DAGISelMatcherEmitter.cpp
@@ -242,6 +242,12 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
<< cast<CheckSameMatcher>(N)->getMatchNumber() << ",\n";
return 2;
+ case Matcher::CheckChildSame:
+ OS << "OPC_CheckChild"
+ << cast<CheckChildSameMatcher>(N)->getChildNo() << "Same, "
+ << cast<CheckChildSameMatcher>(N)->getMatchNumber() << ",\n";
+ return 2;
+
case Matcher::CheckPatternPredicate: {
StringRef Pred =cast<CheckPatternPredicateMatcher>(N)->getPredicate();
OS << "OPC_CheckPatternPredicate, " << getPatternPredicate(Pred) << ',';
@@ -315,10 +321,12 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
assert(ChildSize != 0 && "Should not have a zero-sized child!");
if (i != 0) {
+ if (!OmitComments)
+ OS << "/*" << CurrentIdx << "*/";
OS.PadToColumn(Indent*2);
if (!OmitComments)
- OS << (isa<SwitchOpcodeMatcher>(N) ?
- "/*SwitchOpcode*/ " : "/*SwitchType*/ ");
+ OS << (isa<SwitchOpcodeMatcher>(N) ?
+ "/*SwitchOpcode*/ " : "/*SwitchType*/ ");
}
// Emit the VBR.
@@ -340,6 +348,8 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
}
// Emit the final zero to terminate the switch.
+ if (!OmitComments)
+ OS << "/*" << CurrentIdx << "*/";
OS.PadToColumn(Indent*2) << "0, ";
if (!OmitComments)
OS << (isa<SwitchOpcodeMatcher>(N) ?
@@ -749,6 +759,7 @@ void MatcherTableEmitter::EmitHistogram(const Matcher *M,
case Matcher::MoveChild: OS << "OPC_MoveChild"; break;
case Matcher::MoveParent: OS << "OPC_MoveParent"; break;
case Matcher::CheckSame: OS << "OPC_CheckSame"; break;
+ case Matcher::CheckChildSame: OS << "OPC_CheckChildSame"; break;
case Matcher::CheckPatternPredicate:
OS << "OPC_CheckPatternPredicate"; break;
case Matcher::CheckPredicate: OS << "OPC_CheckPredicate"; break;
diff --git a/utils/TableGen/DAGISelMatcherOpt.cpp b/utils/TableGen/DAGISelMatcherOpt.cpp
index f996422..82e5d63 100644
--- a/utils/TableGen/DAGISelMatcherOpt.cpp
+++ b/utils/TableGen/DAGISelMatcherOpt.cpp
@@ -51,7 +51,11 @@ static void ContractNodes(OwningPtr<Matcher> &MatcherPtr,
if (MC->getChildNo() < 8 && // Only have CheckChildType0...7
CT->getResNo() == 0) // CheckChildType checks res #0
New = new CheckChildTypeMatcher(MC->getChildNo(), CT->getType());
-
+
+ if (CheckSameMatcher *CS = dyn_cast<CheckSameMatcher>(MC->getNext()))
+ if (MC->getChildNo() < 4) // Only have CheckChildSame0...3
+ New = new CheckChildSameMatcher(MC->getChildNo(), CS->getMatchNumber());
+
if (New) {
// Insert the new node.
New->setNext(MatcherPtr.take());
diff --git a/utils/TableGen/FastISelEmitter.cpp b/utils/TableGen/FastISelEmitter.cpp
index ce7f8c8..e35cf0f 100644
--- a/utils/TableGen/FastISelEmitter.cpp
+++ b/utils/TableGen/FastISelEmitter.cpp
@@ -46,7 +46,7 @@ class ImmPredicateSet {
DenseMap<TreePattern *, unsigned> ImmIDs;
std::vector<TreePredicateFn> PredsByName;
public:
-
+
unsigned getIDFor(TreePredicateFn Pred) {
unsigned &Entry = ImmIDs[Pred.getOrigPatFragRecord()];
if (Entry == 0) {
@@ -55,16 +55,16 @@ public:
}
return Entry-1;
}
-
+
const TreePredicateFn &getPredicate(unsigned i) {
assert(i < PredsByName.size());
return PredsByName[i];
}
-
+
typedef std::vector<TreePredicateFn>::const_iterator iterator;
iterator begin() const { return PredsByName.begin(); }
iterator end() const { return PredsByName.end(); }
-
+
};
} // End anonymous namespace
@@ -77,9 +77,9 @@ struct OperandsSignature {
enum { OK_Reg, OK_FP, OK_Imm, OK_Invalid = -1 };
char Repr;
public:
-
+
OpKind() : Repr(OK_Invalid) {}
-
+
bool operator<(OpKind RHS) const { return Repr < RHS.Repr; }
bool operator==(OpKind RHS) const { return Repr == RHS.Repr; }
@@ -90,13 +90,13 @@ struct OperandsSignature {
"Too many integer predicates for the 'Repr' char");
OpKind K; K.Repr = OK_Imm+V; return K;
}
-
+
bool isReg() const { return Repr == OK_Reg; }
bool isFP() const { return Repr == OK_FP; }
bool isImm() const { return Repr >= OK_Imm; }
-
+
unsigned getImmCode() const { assert(isImm()); return Repr-OK_Imm; }
-
+
void printManglingSuffix(raw_ostream &OS, ImmPredicateSet &ImmPredicates,
bool StripImmCodes) const {
if (isReg())
@@ -111,8 +111,8 @@ struct OperandsSignature {
}
}
};
-
-
+
+
SmallVector<OpKind, 3> Operands;
bool operator<(const OperandsSignature &O) const {
@@ -130,7 +130,7 @@ struct OperandsSignature {
return true;
return false;
}
-
+
/// getWithoutImmCodes - Return a copy of this with any immediate codes forced
/// to zero.
OperandsSignature getWithoutImmCodes() const {
@@ -142,31 +142,31 @@ struct OperandsSignature {
Result.Operands.push_back(OpKind::getImm(0));
return Result;
}
-
+
void emitImmediatePredicate(raw_ostream &OS, ImmPredicateSet &ImmPredicates) {
bool EmittedAnything = false;
for (unsigned i = 0, e = Operands.size(); i != e; ++i) {
if (!Operands[i].isImm()) continue;
-
+
unsigned Code = Operands[i].getImmCode();
if (Code == 0) continue;
-
+
if (EmittedAnything)
OS << " &&\n ";
-
+
TreePredicateFn PredFn = ImmPredicates.getPredicate(Code-1);
-
+
// Emit the type check.
OS << "VT == "
<< getEnumName(PredFn.getOrigPatFragRecord()->getTree(0)->getType(0))
<< " && ";
-
-
+
+
OS << PredFn.getFnName() << "(imm" << i <<')';
EmittedAnything = true;
}
}
-
+
/// initialize - Examine the given pattern and initialize the contents
/// of the Operands array accordingly. Return true if all the operands
/// are supported, false otherwise.
@@ -177,12 +177,12 @@ struct OperandsSignature {
const CodeGenRegisterClass *OrigDstRC) {
if (InstPatNode->isLeaf())
return false;
-
+
if (InstPatNode->getOperator()->getName() == "imm") {
Operands.push_back(OpKind::getImm(0));
return true;
}
-
+
if (InstPatNode->getOperator()->getName() == "fpimm") {
Operands.push_back(OpKind::getFP());
return true;
@@ -211,19 +211,19 @@ struct OperandsSignature {
Record *Rec = PredFn.getOrigPatFragRecord()->getRecord();
if (Rec->getValueAsBit("FastIselShouldIgnore"))
return false;
-
+
PredNo = ImmediatePredicates.getIDFor(PredFn)+1;
}
-
+
// Handle unmatched immediate sizes here.
//if (Op->getType(0) != VT)
// return false;
-
+
Operands.push_back(OpKind::getImm(PredNo));
continue;
}
-
+
// For now, filter out any operand with a predicate.
// For now, filter out any operand with multiple values.
if (!Op->getPredicateFns().empty() || Op->getNumTypes() != 1)
@@ -237,7 +237,7 @@ struct OperandsSignature {
// For now, ignore other non-leaf nodes.
return false;
}
-
+
assert(Op->hasTypeSet(0) && "Type infererence not done?");
// For now, all the operands must have the same type (if they aren't
@@ -250,7 +250,7 @@ struct OperandsSignature {
if (!OpDI)
return false;
Record *OpLeafRec = OpDI->getDef();
-
+
// For now, the only other thing we accept is register operands.
const CodeGenRegisterClass *RC = 0;
if (OpLeafRec->isSubClassOf("RegisterOperand"))
@@ -375,7 +375,7 @@ class FastISelMap {
std::map<OperandsSignature, std::vector<OperandsSignature> >
SignaturesWithConstantForms;
-
+
std::string InstNS;
ImmPredicateSet ImmediatePredicates;
public:
@@ -551,13 +551,13 @@ void FastISelMap::collectPatterns(CodeGenDAGPatterns &CGP) {
SubRegNo,
PhysRegInputs
};
-
+
if (SimplePatterns[Operands][OpcodeName][VT][RetVT].count(PredicateCheck))
PrintFatalError(Pattern.getSrcRecord()->getLoc(),
"Duplicate record in FastISel table!");
SimplePatterns[Operands][OpcodeName][VT][RetVT][PredicateCheck] = Memo;
-
+
// If any of the operands were immediates with predicates on them, strip
// them down to a signature that doesn't have predicates so that we can
// associate them with the stripped predicate version.
@@ -571,14 +571,14 @@ void FastISelMap::collectPatterns(CodeGenDAGPatterns &CGP) {
void FastISelMap::printImmediatePredicates(raw_ostream &OS) {
if (ImmediatePredicates.begin() == ImmediatePredicates.end())
return;
-
+
OS << "\n// FastEmit Immediate Predicate functions.\n";
for (ImmPredicateSet::iterator I = ImmediatePredicates.begin(),
E = ImmediatePredicates.end(); I != E; ++I) {
OS << "static bool " << I->getFnName() << "(int64_t Imm) {\n";
OS << I->getImmediatePredicateCode() << "\n}\n";
}
-
+
OS << "\n\n";
}
@@ -804,11 +804,11 @@ void FastISelMap::printFunctionDefinitions(raw_ostream &OS) {
OS << ", ";
Operands.PrintParameters(OS);
OS << ") {\n";
-
- // If there are any forms of this signature available that operand on
- // constrained forms of the immediate (e.g. 32-bit sext immediate in a
+
+ // If there are any forms of this signature available that operate on
+ // constrained forms of the immediate (e.g., 32-bit sext immediate in a
// 64-bit operand), check them first.
-
+
std::map<OperandsSignature, std::vector<OperandsSignature> >::iterator MI
= SignaturesWithConstantForms.find(Operands);
if (MI != SignaturesWithConstantForms.end()) {
@@ -816,7 +816,7 @@ void FastISelMap::printFunctionDefinitions(raw_ostream &OS) {
std::sort(MI->second.begin(), MI->second.end());
MI->second.erase(std::unique(MI->second.begin(), MI->second.end()),
MI->second.end());
-
+
// Check each in order it was seen. It would be nice to have a good
// relative ordering between them, but we're not going for optimality
// here.
@@ -831,11 +831,11 @@ void FastISelMap::printFunctionDefinitions(raw_ostream &OS) {
MI->second[i].PrintArguments(OS);
OS << "))\n return Reg;\n\n";
}
-
+
// Done with this, remove it.
SignaturesWithConstantForms.erase(MI);
}
-
+
OS << " switch (Opcode) {\n";
for (OpcodeTypeRetPredMap::const_iterator I = OTM.begin(), E = OTM.end();
I != E; ++I) {
@@ -855,7 +855,7 @@ void FastISelMap::printFunctionDefinitions(raw_ostream &OS) {
OS << "}\n";
OS << "\n";
}
-
+
// TODO: SignaturesWithConstantForms should be empty here.
}
diff --git a/utils/TableGen/FixedLenDecoderEmitter.cpp b/utils/TableGen/FixedLenDecoderEmitter.cpp
index 6e45240..87d18cd 100644
--- a/utils/TableGen/FixedLenDecoderEmitter.cpp
+++ b/utils/TableGen/FixedLenDecoderEmitter.cpp
@@ -2038,7 +2038,6 @@ void FixedLenDecoderEmitter::run(raw_ostream &o) {
}
DecoderTableInfo TableInfo;
- std::set<unsigned> Sizes;
for (std::map<std::pair<std::string, unsigned>,
std::vector<unsigned> >::const_iterator
I = OpcMap.begin(), E = OpcMap.end(); I != E; ++I) {
diff --git a/utils/TableGen/InstrInfoEmitter.cpp b/utils/TableGen/InstrInfoEmitter.cpp
index c8304de..d3d9cc1 100644
--- a/utils/TableGen/InstrInfoEmitter.cpp
+++ b/utils/TableGen/InstrInfoEmitter.cpp
@@ -57,6 +57,7 @@ private:
std::map<std::vector<Record*>, unsigned> &EL,
const OperandInfoMapTy &OpInfo,
raw_ostream &OS);
+ void emitOperandTypesEnum(raw_ostream &OS, const CodeGenTarget &Target);
void initOperandMapData(
const std::vector<const CodeGenInstruction *> NumberedInstructions,
const std::string &Namespace,
@@ -132,8 +133,8 @@ InstrInfoEmitter::GetOperandInfo(const CodeGenInstruction &Inst) {
Res += "|(1<<MCOI::LookupPtrRegClass)";
// Predicate operands. Check to see if the original unexpanded operand
- // was of type PredicateOperand.
- if (Inst.Operands[i].Rec->isSubClassOf("PredicateOperand"))
+ // was of type PredicateOp.
+ if (Inst.Operands[i].Rec->isSubClassOf("PredicateOp"))
Res += "|(1<<MCOI::Predicate)";
// Optional def operands. Check to see if the original unexpanded operand
@@ -311,6 +312,34 @@ void InstrInfoEmitter::emitOperandNameMappings(raw_ostream &OS,
}
+/// Generate an enum for all the operand types for this target, under the
+/// llvm::TargetNamespace::OpTypes namespace.
+/// Operand types are all definitions derived of the Operand Target.td class.
+void InstrInfoEmitter::emitOperandTypesEnum(raw_ostream &OS,
+ const CodeGenTarget &Target) {
+
+ const std::string &Namespace = Target.getInstNamespace();
+ std::vector<Record *> Operands = Records.getAllDerivedDefinitions("Operand");
+
+ OS << "\n#ifdef GET_INSTRINFO_OPERAND_TYPES_ENUM\n";
+ OS << "#undef GET_INSTRINFO_OPERAND_TYPES_ENUM\n";
+ OS << "namespace llvm {";
+ OS << "namespace " << Namespace << " {\n";
+ OS << "namespace OpTypes { \n";
+ OS << "enum OperandType {\n";
+
+ for (unsigned oi = 0, oe = Operands.size(); oi != oe; ++oi) {
+ if (!Operands[oi]->isAnonymous())
+ OS << " " << Operands[oi]->getName() << " = " << oi << ",\n";
+ }
+
+ OS << " OPERAND_TYPE_LIST_END" << "\n};\n";
+ OS << "} // End namespace OpTypes\n";
+ OS << "} // End namespace " << Namespace << "\n";
+ OS << "} // End namespace llvm\n";
+ OS << "#endif // GET_INSTRINFO_OPERAND_TYPES_ENUM\n";
+}
+
//===----------------------------------------------------------------------===//
// Main Output.
//===----------------------------------------------------------------------===//
@@ -408,13 +437,14 @@ void InstrInfoEmitter::run(raw_ostream &OS) {
OS << "namespace llvm {\n";
OS << "struct " << ClassName << " : public TargetInstrInfo {\n"
<< " explicit " << ClassName << "(int SO = -1, int DO = -1);\n"
+ << " virtual ~" << ClassName << "();\n"
<< "};\n";
OS << "} // End llvm namespace \n";
OS << "#endif // GET_INSTRINFO_HEADER\n\n";
- OS << "\n#ifdef GET_INSTRINFO_CTOR\n";
- OS << "#undef GET_INSTRINFO_CTOR\n";
+ OS << "\n#ifdef GET_INSTRINFO_CTOR_DTOR\n";
+ OS << "#undef GET_INSTRINFO_CTOR_DTOR\n";
OS << "namespace llvm {\n";
OS << "extern const MCInstrDesc " << TargetName << "Insts[];\n";
@@ -424,12 +454,15 @@ void InstrInfoEmitter::run(raw_ostream &OS) {
<< " : TargetInstrInfo(SO, DO) {\n"
<< " InitMCInstrInfo(" << TargetName << "Insts, "
<< TargetName << "InstrNameIndices, " << TargetName << "InstrNameData, "
- << NumberedInstructions.size() << ");\n}\n";
+ << NumberedInstructions.size() << ");\n}\n"
+ << ClassName << "::~" << ClassName << "() {}\n";
OS << "} // End llvm namespace \n";
- OS << "#endif // GET_INSTRINFO_CTOR\n\n";
+ OS << "#endif // GET_INSTRINFO_CTOR_DTOR\n\n";
emitOperandNameMappings(OS, Target, NumberedInstructions);
+
+ emitOperandTypesEnum(OS, Target);
}
void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num,
@@ -514,6 +547,19 @@ void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num,
else
OS << "OperandInfo" << OpInfo.find(OperandInfo)->second;
+ CodeGenTarget &Target = CDP.getTargetInfo();
+ if (Inst.HasComplexDeprecationPredicate)
+ // Emit a function pointer to the complex predicate method.
+ OS << ",0"
+ << ",&get" << Inst.DeprecatedReason << "DeprecationInfo";
+ else if (!Inst.DeprecatedReason.empty())
+ // Emit the Subtarget feature.
+ OS << "," << Target.getInstNamespace() << "::" << Inst.DeprecatedReason
+ << ",0";
+ else
+ // Instruction isn't deprecated.
+ OS << ",0,0";
+
OS << " }, // Inst #" << Num << " = " << Inst.TheDef->getName() << "\n";
}
@@ -545,7 +591,15 @@ void InstrInfoEmitter::emitEnums(raw_ostream &OS) {
<< "\t= " << i << ",\n";
}
OS << " INSTRUCTION_LIST_END = " << NumberedInstructions.size() << "\n";
- OS << " };\n}\n";
+ OS << " };\n";
+ OS << "namespace Sched {\n";
+ OS << " enum {\n";
+ for (unsigned i = 0, e = SchedModels.numInstrSchedClasses(); i != e; ++i) {
+ OS << " " << SchedModels.getSchedClass(i).Name
+ << "\t= " << i << ",\n";
+ }
+ OS << " SCHED_LIST_END = " << SchedModels.numInstrSchedClasses() << "\n";
+ OS << " };\n}\n}\n";
OS << "} // End llvm namespace \n";
OS << "#endif // GET_INSTRINFO_ENUM\n\n";
diff --git a/utils/TableGen/IntrinsicEmitter.cpp b/utils/TableGen/IntrinsicEmitter.cpp
index c508795..8f137f8 100644
--- a/utils/TableGen/IntrinsicEmitter.cpp
+++ b/utils/TableGen/IntrinsicEmitter.cpp
@@ -84,10 +84,10 @@ void IntrinsicEmitter::run(raw_ostream &OS) {
// Emit the function name recognizer.
EmitFnNameRecognizer(Ints, OS);
-
+
// Emit the intrinsic declaration generator.
EmitGenerator(Ints, OS);
-
+
// Emit the intrinsic parameter attributes.
EmitAttributes(Ints, OS);
@@ -125,7 +125,7 @@ void IntrinsicEmitter::EmitEnumInfo(const std::vector<CodeGenIntrinsic> &Ints,
for (unsigned i = 0, e = Ints.size(); i != e; ++i) {
OS << " " << Ints[i].EnumName;
OS << ((i != e-1) ? ", " : " ");
- OS << std::string(40-Ints[i].EnumName.size(), ' ')
+ OS << std::string(40-Ints[i].EnumName.size(), ' ')
<< "// " << Ints[i].Name << "\n";
}
OS << "#endif\n\n";
@@ -146,13 +146,13 @@ private:
};
void IntrinsicEmitter::
-EmitFnNameRecognizer(const std::vector<CodeGenIntrinsic> &Ints,
+EmitFnNameRecognizer(const std::vector<CodeGenIntrinsic> &Ints,
raw_ostream &OS) {
// Build a 'first character of function name' -> intrinsic # mapping.
std::map<char, std::vector<unsigned> > IntMapping;
for (unsigned i = 0, e = Ints.size(); i != e; ++i)
IntMapping[Ints[i].Name[5]].push_back(i);
-
+
OS << "// Function name -> enum value recognizer code.\n";
OS << "#ifdef GET_FUNCTION_RECOGNIZER\n";
OS << " StringRef NameR(Name+6, Len-6); // Skip over 'llvm.'\n";
@@ -171,7 +171,7 @@ EmitFnNameRecognizer(const std::vector<CodeGenIntrinsic> &Ints,
// Emit all the overloaded intrinsics first, build a table of the
// non-overloaded ones.
std::vector<StringMatcher::StringPair> MatchTable;
-
+
for (unsigned i = 0, e = IntList.size(); i != e; ++i) {
unsigned IntNo = IntList[i];
std::string Result = "return " + TargetPrefix + "Intrinsic::" +
@@ -188,18 +188,18 @@ EmitFnNameRecognizer(const std::vector<CodeGenIntrinsic> &Ints,
OS << " if (NameR.startswith(\"" << TheStr << "\")) "
<< Result << '\n';
}
-
+
// Emit the matcher logic for the fixed length strings.
StringMatcher("NameR", MatchTable, OS).Emit(1);
OS << " break; // end of '" << I->first << "' case.\n";
}
-
+
OS << " }\n";
OS << "#endif\n\n";
}
void IntrinsicEmitter::
-EmitIntrinsicToNameTable(const std::vector<CodeGenIntrinsic> &Ints,
+EmitIntrinsicToNameTable(const std::vector<CodeGenIntrinsic> &Ints,
raw_ostream &OS) {
OS << "// Intrinsic ID to name table\n";
OS << "#ifdef GET_INTRINSIC_NAME_TABLE\n";
@@ -210,7 +210,7 @@ EmitIntrinsicToNameTable(const std::vector<CodeGenIntrinsic> &Ints,
}
void IntrinsicEmitter::
-EmitIntrinsicToOverloadTable(const std::vector<CodeGenIntrinsic> &Ints,
+EmitIntrinsicToOverloadTable(const std::vector<CodeGenIntrinsic> &Ints,
raw_ostream &OS) {
OS << "// Intrinsic ID to overload bitset\n";
OS << "#ifdef GET_INTRINSIC_OVERLOAD_TABLE\n";
@@ -260,7 +260,9 @@ enum IIT_Info {
IIT_STRUCT5 = 22,
IIT_EXTEND_VEC_ARG = 23,
IIT_TRUNC_VEC_ARG = 24,
- IIT_ANYPTR = 25
+ IIT_ANYPTR = 25,
+ IIT_V1 = 26,
+ IIT_VARARG = 27
};
@@ -277,7 +279,7 @@ static void EncodeFixedValueType(MVT::SimpleValueType VT,
case 64: return Sig.push_back(IIT_I64);
}
}
-
+
switch (VT) {
default: PrintFatalError("unhandled MVT in intrinsic!");
case MVT::f16: return Sig.push_back(IIT_F16);
@@ -287,16 +289,18 @@ static void EncodeFixedValueType(MVT::SimpleValueType VT,
case MVT::x86mmx: return Sig.push_back(IIT_MMX);
// MVT::OtherVT is used to mean the empty struct type here.
case MVT::Other: return Sig.push_back(IIT_EMPTYSTRUCT);
+ // MVT::isVoid is used to represent varargs here.
+ case MVT::isVoid: return Sig.push_back(IIT_VARARG);
}
}
#ifdef _MSC_VER
#pragma optimize("",off) // MSVC 2010 optimizer can't deal with this function.
-#endif
+#endif
static void EncodeFixedType(Record *R, std::vector<unsigned char> &ArgCodes,
std::vector<unsigned char> &Sig) {
-
+
if (R->isSubClassOf("LLVMMatchType")) {
unsigned Number = R->getValueAsInt("Number");
assert(Number < ArgCodes.size() && "Invalid matching number!");
@@ -308,7 +312,7 @@ static void EncodeFixedType(Record *R, std::vector<unsigned char> &ArgCodes,
Sig.push_back(IIT_ARG);
return Sig.push_back((Number << 2) | ArgCodes[Number]);
}
-
+
MVT::SimpleValueType VT = getValueType(R->getValueAsDef("VT"));
unsigned Tmp = 0;
@@ -319,17 +323,17 @@ static void EncodeFixedType(Record *R, std::vector<unsigned char> &ArgCodes,
case MVT::fAny: ++Tmp; // FALL THROUGH.
case MVT::iAny: {
// If this is an "any" valuetype, then the type is the type of the next
- // type in the list specified to getIntrinsic().
+ // type in the list specified to getIntrinsic().
Sig.push_back(IIT_ARG);
-
+
// Figure out what arg # this is consuming, and remember what kind it was.
unsigned ArgNo = ArgCodes.size();
ArgCodes.push_back(Tmp);
-
+
// Encode what sort of argument it must be in the low 2 bits of the ArgNo.
return Sig.push_back((ArgNo << 2) | Tmp);
}
-
+
case MVT::iPTR: {
unsigned AddrSpace = 0;
if (R->isSubClassOf("LLVMQualPointerType")) {
@@ -345,18 +349,19 @@ static void EncodeFixedType(Record *R, std::vector<unsigned char> &ArgCodes,
return EncodeFixedType(R->getValueAsDef("ElTy"), ArgCodes, Sig);
}
}
-
+
if (EVT(VT).isVector()) {
EVT VVT = VT;
switch (VVT.getVectorNumElements()) {
default: PrintFatalError("unhandled vector type width in intrinsic!");
+ case 1: Sig.push_back(IIT_V1); break;
case 2: Sig.push_back(IIT_V2); break;
case 4: Sig.push_back(IIT_V4); break;
case 8: Sig.push_back(IIT_V8); break;
case 16: Sig.push_back(IIT_V16); break;
case 32: Sig.push_back(IIT_V32); break;
}
-
+
return EncodeFixedValueType(VVT.getVectorElementType().
getSimpleVT().SimpleTy, Sig);
}
@@ -373,7 +378,7 @@ static void EncodeFixedType(Record *R, std::vector<unsigned char> &ArgCodes,
static void ComputeFixedEncoding(const CodeGenIntrinsic &Int,
std::vector<unsigned char> &TypeSig) {
std::vector<unsigned char> ArgCodes;
-
+
if (Int.IS.RetVTs.empty())
TypeSig.push_back(IIT_Done);
else if (Int.IS.RetVTs.size() == 1 &&
@@ -388,11 +393,11 @@ static void ComputeFixedEncoding(const CodeGenIntrinsic &Int,
case 5: TypeSig.push_back(IIT_STRUCT5); break;
default: assert(0 && "Unhandled case in struct");
}
-
+
for (unsigned i = 0, e = Int.IS.RetVTs.size(); i != e; ++i)
EncodeFixedType(Int.IS.RetTypeDefs[i], ArgCodes, TypeSig);
}
-
+
for (unsigned i = 0, e = Int.IS.ParamTypeDefs.size(); i != e; ++i)
EncodeFixedType(Int.IS.ParamTypeDefs[i], ArgCodes, TypeSig);
}
@@ -401,16 +406,16 @@ static void printIITEntry(raw_ostream &OS, unsigned char X) {
OS << (unsigned)X;
}
-void IntrinsicEmitter::EmitGenerator(const std::vector<CodeGenIntrinsic> &Ints,
+void IntrinsicEmitter::EmitGenerator(const std::vector<CodeGenIntrinsic> &Ints,
raw_ostream &OS) {
// If we can compute a 32-bit fixed encoding for this intrinsic, do so and
// capture it in this vector, otherwise store a ~0U.
std::vector<unsigned> FixedEncodings;
-
+
SequenceToOffsetTable<std::vector<unsigned char> > LongEncodingTable;
-
+
std::vector<unsigned char> TypeSig;
-
+
// Compute the unique argument type info.
for (unsigned i = 0, e = Ints.size(); i != e; ++i) {
// Get the signature for the intrinsic.
@@ -430,7 +435,7 @@ void IntrinsicEmitter::EmitGenerator(const std::vector<CodeGenIntrinsic> &Ints,
}
Result = (Result << 4) | TypeSig[e-i-1];
}
-
+
// If this could be encoded into a 31-bit word, return it.
if (!Failed && (Result >> 31) == 0) {
FixedEncodings.push_back(Result);
@@ -441,45 +446,45 @@ void IntrinsicEmitter::EmitGenerator(const std::vector<CodeGenIntrinsic> &Ints,
// Otherwise, we're going to unique the sequence into the
// LongEncodingTable, and use its offset in the 32-bit table instead.
LongEncodingTable.add(TypeSig);
-
+
// This is a placehold that we'll replace after the table is laid out.
FixedEncodings.push_back(~0U);
}
-
+
LongEncodingTable.layout();
-
+
OS << "// Global intrinsic function declaration type table.\n";
OS << "#ifdef GET_INTRINSIC_GENERATOR_GLOBAL\n";
OS << "static const unsigned IIT_Table[] = {\n ";
-
+
for (unsigned i = 0, e = FixedEncodings.size(); i != e; ++i) {
if ((i & 7) == 7)
OS << "\n ";
-
+
// If the entry fit in the table, just emit it.
if (FixedEncodings[i] != ~0U) {
OS << "0x" << utohexstr(FixedEncodings[i]) << ", ";
continue;
}
-
+
TypeSig.clear();
ComputeFixedEncoding(Ints[i], TypeSig);
-
+
// Otherwise, emit the offset into the long encoding table. We emit it this
// way so that it is easier to read the offset in the .def file.
OS << "(1U<<31) | " << LongEncodingTable.get(TypeSig) << ", ";
}
-
+
OS << "0\n};\n\n";
-
+
// Emit the shared table of register lists.
OS << "static const unsigned char IIT_LongEncodingTable[] = {\n";
if (!LongEncodingTable.empty())
LongEncodingTable.emit(OS, printIITEntry);
OS << " 255\n};\n\n";
-
+
OS << "#endif\n\n"; // End of GET_INTRINSIC_GENERATOR_GLOBAL
}
@@ -567,7 +572,6 @@ EmitAttributes(const std::vector<CodeGenIntrinsic> &Ints, raw_ostream &OS) {
OS << " AttributeSet AS[" << maxArgAttrs+1 << "];\n";
OS << " unsigned NumAttrs = 0;\n";
OS << " if (id != 0) {\n";
- OS << " SmallVector<Attribute::AttrKind, 8> AttrVec;\n";
OS << " switch(IntrinsicsToAttributesMap[id - ";
if (TargetOnly)
OS << "Intrinsic::num_intrinsics";
@@ -577,7 +581,7 @@ EmitAttributes(const std::vector<CodeGenIntrinsic> &Ints, raw_ostream &OS) {
OS << " default: llvm_unreachable(\"Invalid attribute number\");\n";
for (UniqAttrMapTy::const_iterator I = UniqAttributes.begin(),
E = UniqAttributes.end(); I != E; ++I) {
- OS << " case " << I->second << ":\n";
+ OS << " case " << I->second << ": {\n";
const CodeGenIntrinsic &intrinsic = *(I->first);
@@ -590,60 +594,82 @@ EmitAttributes(const std::vector<CodeGenIntrinsic> &Ints, raw_ostream &OS) {
while (ai != ae) {
unsigned argNo = intrinsic.ArgumentAttributes[ai].first;
- OS << " AttrVec.clear();\n";
+ OS << " const Attribute::AttrKind AttrParam" << argNo + 1 <<"[]= {";
+ bool addComma = false;
do {
switch (intrinsic.ArgumentAttributes[ai].second) {
case CodeGenIntrinsic::NoCapture:
- OS << " AttrVec.push_back(Attribute::NoCapture);\n";
+ if (addComma)
+ OS << ",";
+ OS << "Attribute::NoCapture";
+ addComma = true;
break;
case CodeGenIntrinsic::ReadOnly:
- OS << " AttrVec.push_back(Attribute::ReadOnly);\n";
+ if (addComma)
+ OS << ",";
+ OS << "Attribute::ReadOnly";
+ addComma = true;
break;
case CodeGenIntrinsic::ReadNone:
- OS << " AttrVec.push_back(Attribute::ReadNone);\n";
+ if (addComma)
+ OS << ",";
+ OS << "Attributes::ReadNone";
+ addComma = true;
break;
}
++ai;
} while (ai != ae && intrinsic.ArgumentAttributes[ai].first == argNo);
-
+ OS << "};\n";
OS << " AS[" << numAttrs++ << "] = AttributeSet::get(C, "
- << argNo+1 << ", AttrVec);\n";
+ << argNo+1 << ", AttrParam" << argNo +1 << ");\n";
}
}
ModRefKind modRef = getModRefKind(intrinsic);
if (!intrinsic.canThrow || modRef || intrinsic.isNoReturn) {
- OS << " AttrVec.clear();\n";
-
- if (!intrinsic.canThrow)
- OS << " AttrVec.push_back(Attribute::NoUnwind);\n";
- if (intrinsic.isNoReturn)
- OS << " AttrVec.push_back(Attribute::NoReturn);\n";
+ OS << " const Attribute::AttrKind Atts[] = {";
+ bool addComma = false;
+ if (!intrinsic.canThrow) {
+ OS << "Attribute::NoUnwind";
+ addComma = true;
+ }
+ if (intrinsic.isNoReturn) {
+ if (addComma)
+ OS << ",";
+ OS << "Attribute::NoReturn";
+ addComma = true;
+ }
switch (modRef) {
case MRK_none: break;
case MRK_readonly:
- OS << " AttrVec.push_back(Attribute::ReadOnly);\n";
+ if (addComma)
+ OS << ",";
+ OS << "Attribute::ReadOnly";
break;
case MRK_readnone:
- OS << " AttrVec.push_back(Attribute::ReadNone);\n";
+ if (addComma)
+ OS << ",";
+ OS << "Attribute::ReadNone";
break;
}
+ OS << "};\n";
OS << " AS[" << numAttrs++ << "] = AttributeSet::get(C, "
- << "AttributeSet::FunctionIndex, AttrVec);\n";
+ << "AttributeSet::FunctionIndex, Atts);\n";
}
if (numAttrs) {
OS << " NumAttrs = " << numAttrs << ";\n";
OS << " break;\n";
+ OS << " }\n";
} else {
OS << " return AttributeSet();\n";
}
}
-
+
OS << " }\n";
OS << " }\n";
OS << " return AttributeSet::get(C, ArrayRef<AttributeSet>(AS, "
@@ -692,9 +718,9 @@ EmitModRefBehavior(const std::vector<CodeGenIntrinsic> &Ints, raw_ostream &OS){
static void EmitTargetBuiltins(const std::map<std::string, std::string> &BIM,
const std::string &TargetPrefix,
raw_ostream &OS) {
-
+
std::vector<StringMatcher::StringPair> Results;
-
+
for (std::map<std::string, std::string>::const_iterator I = BIM.begin(),
E = BIM.end(); I != E; ++I) {
std::string ResultCode =
@@ -705,9 +731,9 @@ static void EmitTargetBuiltins(const std::map<std::string, std::string> &BIM,
StringMatcher("BuiltinName", Results, OS).Emit();
}
-
+
void IntrinsicEmitter::
-EmitIntrinsicToGCCBuiltinMap(const std::vector<CodeGenIntrinsic> &Ints,
+EmitIntrinsicToGCCBuiltinMap(const std::vector<CodeGenIntrinsic> &Ints,
raw_ostream &OS) {
typedef std::map<std::string, std::map<std::string, std::string> > BIMTy;
BIMTy BuiltinMap;
@@ -715,20 +741,20 @@ EmitIntrinsicToGCCBuiltinMap(const std::vector<CodeGenIntrinsic> &Ints,
if (!Ints[i].GCCBuiltinName.empty()) {
// Get the map for this target prefix.
std::map<std::string, std::string> &BIM =BuiltinMap[Ints[i].TargetPrefix];
-
+
if (!BIM.insert(std::make_pair(Ints[i].GCCBuiltinName,
Ints[i].EnumName)).second)
PrintFatalError("Intrinsic '" + Ints[i].TheDef->getName() +
"': duplicate GCC builtin name!");
}
}
-
+
OS << "// Get the LLVM intrinsic that corresponds to a GCC builtin.\n";
OS << "// This is used by the C front-end. The GCC builtin name is passed\n";
OS << "// in as BuiltinName, and a target prefix (e.g. 'ppc') is passed\n";
OS << "// in as TargetPrefix. The result is assigned to 'IntrinsicID'.\n";
OS << "#ifdef GET_LLVM_INTRINSIC_FOR_GCC_BUILTIN\n";
-
+
if (TargetOnly) {
OS << "static " << TargetPrefix << "Intrinsic::ID "
<< "getIntrinsicForGCCBuiltin(const char "
@@ -737,10 +763,10 @@ EmitIntrinsicToGCCBuiltinMap(const std::vector<CodeGenIntrinsic> &Ints,
OS << "Intrinsic::ID Intrinsic::getIntrinsicForGCCBuiltin(const char "
<< "*TargetPrefixStr, const char *BuiltinNameStr) {\n";
}
-
+
OS << " StringRef BuiltinName(BuiltinNameStr);\n";
OS << " StringRef TargetPrefix(TargetPrefixStr);\n\n";
-
+
// Note: this could emit significantly better code if we cared.
for (BIMTy::iterator I = BuiltinMap.begin(), E = BuiltinMap.end();I != E;++I){
OS << " ";
diff --git a/utils/TableGen/OptParserEmitter.cpp b/utils/TableGen/OptParserEmitter.cpp
index 86328bf..9c4daaf 100644
--- a/utils/TableGen/OptParserEmitter.cpp
+++ b/utils/TableGen/OptParserEmitter.cpp
@@ -13,18 +13,23 @@
#include "llvm/ADT/Twine.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/TableGenBackend.h"
+#include <cstring>
+#include <cctype>
#include <map>
using namespace llvm;
+// Ordering on Info. The logic should match with the consumer-side function in
+// llvm/Option/OptTable.h.
static int StrCmpOptionName(const char *A, const char *B) {
- char a = *A, b = *B;
+ const char *X = A, *Y = B;
+ char a = tolower(*A), b = tolower(*B);
while (a == b) {
if (a == '\0')
- return 0;
+ return strcmp(A, B);
- a = *++A;
- b = *++B;
+ a = tolower(*++X);
+ b = tolower(*++Y);
}
if (a == '\0') // A is a prefix of B.
@@ -36,9 +41,9 @@ static int StrCmpOptionName(const char *A, const char *B) {
return (a < b) ? -1 : 1;
}
-static int CompareOptionRecords(const void *Av, const void *Bv) {
- const Record *A = *(const Record*const*) Av;
- const Record *B = *(const Record*const*) Bv;
+static int CompareOptionRecords(Record *const *Av, Record *const *Bv) {
+ const Record *A = *Av;
+ const Record *B = *Bv;
// Sentinel options precede all others and are only ordered by precedence.
bool ASent = A->getValueAsDef("Kind")->getValueAsBit("Sentinel");
@@ -50,7 +55,7 @@ static int CompareOptionRecords(const void *Av, const void *Bv) {
if (!ASent)
if (int Cmp = StrCmpOptionName(A->getValueAsString("Name").c_str(),
B->getValueAsString("Name").c_str()))
- return Cmp;
+ return Cmp;
if (!ASent) {
std::vector<std::string> APrefixes = A->getValueAsListOfStrings("Prefixes");
@@ -74,7 +79,7 @@ static int CompareOptionRecords(const void *Av, const void *Bv) {
if (APrec == BPrec &&
A->getValueAsListOfStrings("Prefixes") ==
B->getValueAsListOfStrings("Prefixes")) {
- PrintError(A->getLoc(), Twine("Option is equivilent to"));
+ PrintError(A->getLoc(), Twine("Option is equivalent to"));
PrintError(B->getLoc(), Twine("Other defined here"));
PrintFatalError("Equivalent Options found.");
}
diff --git a/utils/TableGen/RegisterInfoEmitter.cpp b/utils/TableGen/RegisterInfoEmitter.cpp
index 731dccf..cc08df9 100644
--- a/utils/TableGen/RegisterInfoEmitter.cpp
+++ b/utils/TableGen/RegisterInfoEmitter.cpp
@@ -121,7 +121,7 @@ void RegisterInfoEmitter::runEnums(raw_ostream &OS,
OS << "}\n";
}
- const std::vector<Record*> RegAltNameIndices = Target.getRegAltNameIndices();
+ const std::vector<Record*> &RegAltNameIndices = Target.getRegAltNameIndices();
// If the only definition is the default NoRegAltName, we don't need to
// emit anything.
if (RegAltNameIndices.size() > 1) {
@@ -722,7 +722,7 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target,
// Keep track of sub-register names as well. These are not differentially
// encoded.
typedef SmallVector<const CodeGenSubRegIndex*, 4> SubRegIdxVec;
- SequenceToOffsetTable<SubRegIdxVec> SubRegIdxSeqs;
+ SequenceToOffsetTable<SubRegIdxVec, CodeGenSubRegIndex::Less> SubRegIdxSeqs;
SmallVector<SubRegIdxVec, 4> SubRegIdxLists(Regs.size());
SequenceToOffsetTable<std::string> RegStrings;
@@ -1090,7 +1090,7 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
// Compress the sub-reg index lists.
typedef std::vector<const CodeGenSubRegIndex*> IdxList;
SmallVector<IdxList, 8> SuperRegIdxLists(RegisterClasses.size());
- SequenceToOffsetTable<IdxList> SuperRegIdxSeqs;
+ SequenceToOffsetTable<IdxList, CodeGenSubRegIndex::Less> SuperRegIdxSeqs;
BitVector MaskBV(RegisterClasses.size());
for (unsigned rc = 0, e = RegisterClasses.size(); rc != e; ++rc) {
@@ -1314,9 +1314,21 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
OS << "0 };\n";
// Emit the *_RegMask bit mask of call-preserved registers.
+ BitVector Covered = RegBank.computeCoveredRegisters(*Regs);
+
+ // Check for an optional OtherPreserved set.
+ // Add those registers to RegMask, but not to SaveList.
+ if (DagInit *OPDag =
+ dyn_cast<DagInit>(CSRSet->getValueInit("OtherPreserved"))) {
+ SetTheory::RecSet OPSet;
+ RegBank.getSets().evaluate(OPDag, OPSet, CSRSet->getLoc());
+ Covered |= RegBank.computeCoveredRegisters(
+ ArrayRef<Record*>(OPSet.begin(), OPSet.end()));
+ }
+
OS << "static const uint32_t " << CSRSet->getName()
<< "_RegMask[] = { ";
- printBitVectorAsHex(OS, RegBank.computeCoveredRegisters(*Regs), 32);
+ printBitVectorAsHex(OS, Covered, 32);
OS << "};\n";
}
OS << "\n\n";
diff --git a/utils/TableGen/SequenceToOffsetTable.h b/utils/TableGen/SequenceToOffsetTable.h
index fcda233..e6ab664 100644
--- a/utils/TableGen/SequenceToOffsetTable.h
+++ b/utils/TableGen/SequenceToOffsetTable.h
@@ -21,6 +21,7 @@
#include <cassert>
#include <cctype>
#include <functional>
+#include <map>
#include <vector>
namespace llvm {
diff --git a/utils/TableGen/SetTheory.cpp b/utils/TableGen/SetTheory.cpp
index 3e5c38c..ad3d7c7 100644
--- a/utils/TableGen/SetTheory.cpp
+++ b/utils/TableGen/SetTheory.cpp
@@ -27,14 +27,16 @@ typedef SetTheory::RecVec RecVec;
// (add a, b, ...) Evaluate and union all arguments.
struct AddOp : public SetTheory::Operator {
- void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, ArrayRef<SMLoc> Loc) {
+ virtual void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts,
+ ArrayRef<SMLoc> Loc) {
ST.evaluate(Expr->arg_begin(), Expr->arg_end(), Elts, Loc);
}
};
// (sub Add, Sub, ...) Set difference.
struct SubOp : public SetTheory::Operator {
- void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, ArrayRef<SMLoc> Loc) {
+ virtual void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts,
+ ArrayRef<SMLoc> Loc) {
if (Expr->arg_size() < 2)
PrintFatalError(Loc, "Set difference needs at least two arguments: " +
Expr->getAsString());
@@ -49,7 +51,8 @@ struct SubOp : public SetTheory::Operator {
// (and S1, S2) Set intersection.
struct AndOp : public SetTheory::Operator {
- void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, ArrayRef<SMLoc> Loc) {
+ virtual void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts,
+ ArrayRef<SMLoc> Loc) {
if (Expr->arg_size() != 2)
PrintFatalError(Loc, "Set intersection requires two arguments: " +
Expr->getAsString());
@@ -68,7 +71,8 @@ struct SetIntBinOp : public SetTheory::Operator {
RecSet &Set, int64_t N,
RecSet &Elts, ArrayRef<SMLoc> Loc) =0;
- void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, ArrayRef<SMLoc> Loc) {
+ virtual void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts,
+ ArrayRef<SMLoc> Loc) {
if (Expr->arg_size() != 2)
PrintFatalError(Loc, "Operator requires (Op Set, Int) arguments: " +
Expr->getAsString());
@@ -84,9 +88,9 @@ struct SetIntBinOp : public SetTheory::Operator {
// (shl S, N) Shift left, remove the first N elements.
struct ShlOp : public SetIntBinOp {
- void apply2(SetTheory &ST, DagInit *Expr,
- RecSet &Set, int64_t N,
- RecSet &Elts, ArrayRef<SMLoc> Loc) {
+ virtual void apply2(SetTheory &ST, DagInit *Expr,
+ RecSet &Set, int64_t N,
+ RecSet &Elts, ArrayRef<SMLoc> Loc) {
if (N < 0)
PrintFatalError(Loc, "Positive shift required: " +
Expr->getAsString());
@@ -97,9 +101,9 @@ struct ShlOp : public SetIntBinOp {
// (trunc S, N) Truncate after the first N elements.
struct TruncOp : public SetIntBinOp {
- void apply2(SetTheory &ST, DagInit *Expr,
- RecSet &Set, int64_t N,
- RecSet &Elts, ArrayRef<SMLoc> Loc) {
+ virtual void apply2(SetTheory &ST, DagInit *Expr,
+ RecSet &Set, int64_t N,
+ RecSet &Elts, ArrayRef<SMLoc> Loc) {
if (N < 0)
PrintFatalError(Loc, "Positive length required: " +
Expr->getAsString());
@@ -115,9 +119,9 @@ struct RotOp : public SetIntBinOp {
RotOp(bool Rev) : Reverse(Rev) {}
- void apply2(SetTheory &ST, DagInit *Expr,
- RecSet &Set, int64_t N,
- RecSet &Elts, ArrayRef<SMLoc> Loc) {
+ virtual void apply2(SetTheory &ST, DagInit *Expr,
+ RecSet &Set, int64_t N,
+ RecSet &Elts, ArrayRef<SMLoc> Loc) {
if (Reverse)
N = -N;
// N > 0 -> rotate left, N < 0 -> rotate right.
@@ -134,9 +138,9 @@ struct RotOp : public SetIntBinOp {
// (decimate S, N) Pick every N'th element of S.
struct DecimateOp : public SetIntBinOp {
- void apply2(SetTheory &ST, DagInit *Expr,
- RecSet &Set, int64_t N,
- RecSet &Elts, ArrayRef<SMLoc> Loc) {
+ virtual void apply2(SetTheory &ST, DagInit *Expr,
+ RecSet &Set, int64_t N,
+ RecSet &Elts, ArrayRef<SMLoc> Loc) {
if (N <= 0)
PrintFatalError(Loc, "Positive stride required: " +
Expr->getAsString());
@@ -147,7 +151,8 @@ struct DecimateOp : public SetIntBinOp {
// (interleave S1, S2, ...) Interleave elements of the arguments.
struct InterleaveOp : public SetTheory::Operator {
- void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, ArrayRef<SMLoc> Loc) {
+ virtual void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts,
+ ArrayRef<SMLoc> Loc) {
// Evaluate the arguments individually.
SmallVector<RecSet, 4> Args(Expr->getNumArgs());
unsigned MaxSize = 0;
@@ -165,7 +170,8 @@ struct InterleaveOp : public SetTheory::Operator {
// (sequence "Format", From, To) Generate a sequence of records by name.
struct SequenceOp : public SetTheory::Operator {
- void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts, ArrayRef<SMLoc> Loc) {
+ virtual void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts,
+ ArrayRef<SMLoc> Loc) {
int Step = 1;
if (Expr->arg_size() > 4)
PrintFatalError(Loc, "Bad args to (sequence \"Format\", From, To): " +
@@ -232,15 +238,16 @@ struct FieldExpander : public SetTheory::Expander {
FieldExpander(StringRef fn) : FieldName(fn) {}
- void expand(SetTheory &ST, Record *Def, RecSet &Elts) {
+ virtual void expand(SetTheory &ST, Record *Def, RecSet &Elts) {
ST.evaluate(Def->getValueInit(FieldName), Elts, Def->getLoc());
}
};
} // end anonymous namespace
-void SetTheory::Operator::anchor() { }
+// Pin the vtables to this file.
+void SetTheory::Operator::anchor() {}
+void SetTheory::Expander::anchor() {}
-void SetTheory::Expander::anchor() { }
SetTheory::SetTheory() {
addOperator("add", new AddOp);
diff --git a/utils/TableGen/StringToOffsetTable.h b/utils/TableGen/StringToOffsetTable.h
deleted file mode 100644
index d94d3a2..0000000
--- a/utils/TableGen/StringToOffsetTable.h
+++ /dev/null
@@ -1,83 +0,0 @@
-//===- StringToOffsetTable.h - Emit a big concatenated string ---*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef TBLGEN_STRING_TO_OFFSET_TABLE_H
-#define TBLGEN_STRING_TO_OFFSET_TABLE_H
-
-#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/ADT/StringMap.h"
-#include "llvm/Support/raw_ostream.h"
-#include <cctype>
-
-namespace llvm {
-
-/// StringToOffsetTable - This class uniques a bunch of nul-terminated strings
-/// and keeps track of their offset in a massive contiguous string allocation.
-/// It can then output this string blob and use indexes into the string to
-/// reference each piece.
-class StringToOffsetTable {
- StringMap<unsigned> StringOffset;
- std::string AggregateString;
-public:
-
- unsigned GetOrAddStringOffset(StringRef Str, bool appendZero = true) {
- StringMapEntry<unsigned> &Entry = StringOffset.GetOrCreateValue(Str, -1U);
- if (Entry.getValue() == -1U) {
- // Add the string to the aggregate if this is the first time found.
- Entry.setValue(AggregateString.size());
- AggregateString.append(Str.begin(), Str.end());
- if (appendZero)
- AggregateString += '\0';
- }
-
- return Entry.getValue();
- }
-
- void EmitString(raw_ostream &O) {
- // Escape the string.
- SmallString<256> Str;
- raw_svector_ostream(Str).write_escaped(AggregateString);
- AggregateString = Str.str();
-
- O << " \"";
- unsigned CharsPrinted = 0;
- for (unsigned i = 0, e = AggregateString.size(); i != e; ++i) {
- if (CharsPrinted > 70) {
- O << "\"\n \"";
- CharsPrinted = 0;
- }
- O << AggregateString[i];
- ++CharsPrinted;
-
- // Print escape sequences all together.
- if (AggregateString[i] != '\\')
- continue;
-
- assert(i+1 < AggregateString.size() && "Incomplete escape sequence!");
- if (isdigit(AggregateString[i+1])) {
- assert(isdigit(AggregateString[i+2]) &&
- isdigit(AggregateString[i+3]) &&
- "Expected 3 digit octal escape!");
- O << AggregateString[++i];
- O << AggregateString[++i];
- O << AggregateString[++i];
- CharsPrinted += 3;
- } else {
- O << AggregateString[++i];
- ++CharsPrinted;
- }
- }
- O << "\"";
- }
-};
-
-} // end namespace llvm
-
-#endif
diff --git a/utils/TableGen/SubtargetEmitter.cpp b/utils/TableGen/SubtargetEmitter.cpp
index 81bb6f8..b9f9d06 100644
--- a/utils/TableGen/SubtargetEmitter.cpp
+++ b/utils/TableGen/SubtargetEmitter.cpp
@@ -1198,6 +1198,11 @@ void SubtargetEmitter::EmitProcessorModels(raw_ostream &OS) {
EmitProcessorProp(OS, PI->ModelDef, "LoadLatency", ',');
EmitProcessorProp(OS, PI->ModelDef, "HighLatency", ',');
EmitProcessorProp(OS, PI->ModelDef, "MispredictPenalty", ',');
+
+ OS << " " << (bool)(PI->ModelDef ?
+ PI->ModelDef->getValueAsBit("CompleteModel") : 0)
+ << ", // " << "CompleteModel\n";
+
OS << " " << PI->Index << ", // Processor ID\n";
if (PI->hasInstrSchedModel())
OS << " " << PI->ModelName << "ProcResources" << ",\n"
diff --git a/utils/TableGen/TGValueTypes.cpp b/utils/TableGen/TGValueTypes.cpp
index 3ac71a4..f4893f5 100644
--- a/utils/TableGen/TGValueTypes.cpp
+++ b/utils/TableGen/TGValueTypes.cpp
@@ -35,11 +35,15 @@ public:
}
Type(TypeKind K) : Kind(K) {}
virtual unsigned getSizeInBits() const = 0;
- virtual ~Type() {}
+ virtual ~Type();
};
+// Provide out-of-line definition to prevent weak vtable.
+Type::~Type() {}
+
}
+namespace {
class ExtendedIntegerType : public Type {
unsigned BitWidth;
public:
@@ -48,7 +52,7 @@ public:
static bool classof(const Type *T) {
return T->getKind() == TK_ExtendedIntegerType;
}
- unsigned getSizeInBits() const {
+ virtual unsigned getSizeInBits() const {
return getBitWidth();
}
unsigned getBitWidth() const {
@@ -65,7 +69,7 @@ public:
static bool classof(const Type *T) {
return T->getKind() == TK_ExtendedVectorType;
}
- unsigned getSizeInBits() const {
+ virtual unsigned getSizeInBits() const {
return getNumElements() * getElementType().getSizeInBits();
}
EVT getElementType() const {
@@ -75,6 +79,7 @@ public:
return NumElements;
}
};
+} // end anonymous namespace
static std::map<unsigned, const Type *>
ExtendedIntegerTypeMap;
diff --git a/utils/TableGen/X86DisassemblerTables.cpp b/utils/TableGen/X86DisassemblerTables.cpp
index 0838ac4..bdb4793 100644
--- a/utils/TableGen/X86DisassemblerTables.cpp
+++ b/utils/TableGen/X86DisassemblerTables.cpp
@@ -81,31 +81,37 @@ static inline bool inheritsFrom(InstructionContext child,
case IC_64BIT_REXW_OPSIZE:
return false;
case IC_VEX:
- return inheritsFrom(child, IC_VEX_L_W) ||
+ return (VEX_LIG && inheritsFrom(child, IC_VEX_L_W)) ||
inheritsFrom(child, IC_VEX_W) ||
(VEX_LIG && inheritsFrom(child, IC_VEX_L));
case IC_VEX_XS:
- return inheritsFrom(child, IC_VEX_L_W_XS) ||
+ return (VEX_LIG && inheritsFrom(child, IC_VEX_L_W_XS)) ||
inheritsFrom(child, IC_VEX_W_XS) ||
(VEX_LIG && inheritsFrom(child, IC_VEX_L_XS));
case IC_VEX_XD:
- return inheritsFrom(child, IC_VEX_L_W_XD) ||
+ return (VEX_LIG && inheritsFrom(child, IC_VEX_L_W_XD)) ||
inheritsFrom(child, IC_VEX_W_XD) ||
(VEX_LIG && inheritsFrom(child, IC_VEX_L_XD));
case IC_VEX_OPSIZE:
- return inheritsFrom(child, IC_VEX_L_W_OPSIZE) ||
+ return (VEX_LIG && inheritsFrom(child, IC_VEX_L_W_OPSIZE)) ||
inheritsFrom(child, IC_VEX_W_OPSIZE) ||
(VEX_LIG && inheritsFrom(child, IC_VEX_L_OPSIZE));
case IC_VEX_W:
+ return VEX_LIG && inheritsFrom(child, IC_VEX_L_W);
case IC_VEX_W_XS:
+ return VEX_LIG && inheritsFrom(child, IC_VEX_L_W_XS);
case IC_VEX_W_XD:
+ return VEX_LIG && inheritsFrom(child, IC_VEX_L_W_XD);
case IC_VEX_W_OPSIZE:
- return false;
+ return VEX_LIG && inheritsFrom(child, IC_VEX_L_W_OPSIZE);
case IC_VEX_L:
+ return inheritsFrom(child, IC_VEX_L_W);
case IC_VEX_L_XS:
+ return inheritsFrom(child, IC_VEX_L_W_XS);
case IC_VEX_L_XD:
+ return inheritsFrom(child, IC_VEX_L_W_XD);
case IC_VEX_L_OPSIZE:
- return false;
+ return inheritsFrom(child, IC_VEX_L_W_OPSIZE);
case IC_VEX_L_W:
case IC_VEX_L_W_XS:
case IC_VEX_L_W_XD:
@@ -122,7 +128,7 @@ static inline bool inheritsFrom(InstructionContext child,
inheritsFrom(child, IC_EVEX_L_W_XD);
case IC_EVEX_OPSIZE:
return inheritsFrom(child, IC_EVEX_W_OPSIZE) ||
- inheritsFrom(child, IC_EVEX_W_OPSIZE);
+ inheritsFrom(child, IC_EVEX_L_W_OPSIZE);
case IC_EVEX_W:
case IC_EVEX_W_XS:
case IC_EVEX_W_XD:
@@ -170,10 +176,24 @@ static inline bool inheritsFrom(InstructionContext child,
case IC_EVEX_L_XD_K:
case IC_EVEX_L_OPSIZE_K:
return false;
+ case IC_EVEX_W_KZ:
+ case IC_EVEX_W_XS_KZ:
+ case IC_EVEX_W_XD_KZ:
+ case IC_EVEX_W_OPSIZE_KZ:
+ return false;
+ case IC_EVEX_L_KZ:
+ case IC_EVEX_L_XS_KZ:
+ case IC_EVEX_L_XD_KZ:
+ case IC_EVEX_L_OPSIZE_KZ:
+ return false;
case IC_EVEX_L_W_K:
case IC_EVEX_L_W_XS_K:
case IC_EVEX_L_W_XD_K:
case IC_EVEX_L_W_OPSIZE_K:
+ case IC_EVEX_L_W_KZ:
+ case IC_EVEX_L_W_XS_KZ:
+ case IC_EVEX_L_W_XD_KZ:
+ case IC_EVEX_L_W_OPSIZE_KZ:
return false;
case IC_EVEX_L2_K:
case IC_EVEX_L2_B:
@@ -181,12 +201,25 @@ static inline bool inheritsFrom(InstructionContext child,
case IC_EVEX_L2_XD_K:
case IC_EVEX_L2_OPSIZE_K:
case IC_EVEX_L2_OPSIZE_B:
+ case IC_EVEX_L2_OPSIZE_K_B:
+ case IC_EVEX_L2_KZ:
+ case IC_EVEX_L2_XS_KZ:
+ case IC_EVEX_L2_XD_KZ:
+ case IC_EVEX_L2_OPSIZE_KZ:
+ case IC_EVEX_L2_OPSIZE_KZ_B:
return false;
case IC_EVEX_L2_W_K:
+ case IC_EVEX_L2_W_B:
case IC_EVEX_L2_W_XS_K:
case IC_EVEX_L2_W_XD_K:
case IC_EVEX_L2_W_OPSIZE_K:
case IC_EVEX_L2_W_OPSIZE_B:
+ case IC_EVEX_L2_W_OPSIZE_K_B:
+ case IC_EVEX_L2_W_KZ:
+ case IC_EVEX_L2_W_XS_KZ:
+ case IC_EVEX_L2_W_XD_KZ:
+ case IC_EVEX_L2_W_OPSIZE_KZ:
+ case IC_EVEX_L2_W_OPSIZE_KZ_B:
return false;
default:
llvm_unreachable("Unknown instruction class");
@@ -207,7 +240,8 @@ static inline bool outranks(InstructionContext upper,
#define ENUM_ENTRY(n, r, d) r,
#define ENUM_ENTRY_K_B(n, r, d) ENUM_ENTRY(n, r, d) \
- ENUM_ENTRY(n##_K_B, r, d) ENUM_ENTRY(n##_K, r, d) ENUM_ENTRY(n##_B, r, d)
+ ENUM_ENTRY(n##_K_B, r, d) ENUM_ENTRY(n##_KZ_B, r, d) \
+ ENUM_ENTRY(n##_KZ, r, d) ENUM_ENTRY(n##_K, r, d) ENUM_ENTRY(n##_B, r, d)
static int ranks[IC_max] = {
INSTRUCTION_CONTEXTS
};
@@ -229,7 +263,8 @@ static inline const char* stringForContext(InstructionContext insnContext) {
llvm_unreachable("Unhandled instruction class");
#define ENUM_ENTRY(n, r, d) case n: return #n; break;
#define ENUM_ENTRY_K_B(n, r, d) ENUM_ENTRY(n, r, d) ENUM_ENTRY(n##_K_B, r, d)\
- ENUM_ENTRY(n##_K, r, d) ENUM_ENTRY(n##_B, r, d)
+ ENUM_ENTRY(n##_KZ, r, d) ENUM_ENTRY(n##_K, r, d) ENUM_ENTRY(n##_B, r, d)\
+ ENUM_ENTRY(n##_KZ_B, r, d)
INSTRUCTION_CONTEXTS
#undef ENUM_ENTRY
#undef ENUM_ENTRY_K_B
@@ -259,35 +294,6 @@ static inline const char* stringForOperandEncoding(OperandEncoding encoding) {
}
}
-void DisassemblerTables::emitOneID(raw_ostream &o, unsigned &i, InstrUID id,
- bool addComma) const {
- if (id)
- o.indent(i * 2) << format("0x%hx", id);
- else
- o.indent(i * 2) << 0;
-
- if (addComma)
- o << ", ";
- else
- o << " ";
-
- o << "/* ";
- o << InstructionSpecifiers[id].name;
- o << "*/";
-
- o << "\n";
-}
-
-/// emitEmptyTable - Emits the modRMEmptyTable, which is used as a ID table by
-/// all ModR/M decisions for instructions that are invalid for all possible
-/// ModR/M byte values.
-///
-/// @param o - The output stream on which to emit the table.
-/// @param i - The indentation level for that output stream.
-static void emitEmptyTable(raw_ostream &o, unsigned &i) {
- o.indent(i * 2) << "0x0, /* EmptyTable */\n";
-}
-
/// getDecisionType - Determines whether a ModRM decision with 255 entries can
/// be compacted by eliminating redundant information.
///
@@ -387,6 +393,7 @@ DisassemblerTables::~DisassemblerTables() {
void DisassemblerTables::emitModRMDecision(raw_ostream &o1, raw_ostream &o2,
unsigned &i1, unsigned &i2,
+ unsigned &ModRMTableNum,
ModRMDecision &decision) const {
static uint32_t sTableNumber = 0;
static uint32_t sEntryNumber = 1;
@@ -405,44 +412,56 @@ void DisassemblerTables::emitModRMDecision(raw_ostream &o1, raw_ostream &o2,
return;
}
- o1 << "/* Table" << sTableNumber << " */\n";
- i1++;
+ std::vector<unsigned> ModRMDecision;
switch (dt) {
default:
llvm_unreachable("Unknown decision type");
case MODRM_ONEENTRY:
- emitOneID(o1, i1, decision.instructionIDs[0], true);
+ ModRMDecision.push_back(decision.instructionIDs[0]);
break;
case MODRM_SPLITRM:
- emitOneID(o1, i1, decision.instructionIDs[0x00], true); // mod = 0b00
- emitOneID(o1, i1, decision.instructionIDs[0xc0], true); // mod = 0b11
+ ModRMDecision.push_back(decision.instructionIDs[0x00]);
+ ModRMDecision.push_back(decision.instructionIDs[0xc0]);
break;
case MODRM_SPLITREG:
for (unsigned index = 0; index < 64; index += 8)
- emitOneID(o1, i1, decision.instructionIDs[index], true);
+ ModRMDecision.push_back(decision.instructionIDs[index]);
for (unsigned index = 0xc0; index < 256; index += 8)
- emitOneID(o1, i1, decision.instructionIDs[index], true);
+ ModRMDecision.push_back(decision.instructionIDs[index]);
break;
case MODRM_SPLITMISC:
for (unsigned index = 0; index < 64; index += 8)
- emitOneID(o1, i1, decision.instructionIDs[index], true);
+ ModRMDecision.push_back(decision.instructionIDs[index]);
for (unsigned index = 0xc0; index < 256; ++index)
- emitOneID(o1, i1, decision.instructionIDs[index], true);
+ ModRMDecision.push_back(decision.instructionIDs[index]);
break;
case MODRM_FULL:
for (unsigned index = 0; index < 256; ++index)
- emitOneID(o1, i1, decision.instructionIDs[index], true);
+ ModRMDecision.push_back(decision.instructionIDs[index]);
break;
}
- i1--;
+ unsigned &EntryNumber = ModRMTable[ModRMDecision];
+ if (EntryNumber == 0) {
+ EntryNumber = ModRMTableNum;
+
+ ModRMTableNum += ModRMDecision.size();
+ o1 << "/* Table" << EntryNumber << " */\n";
+ i1++;
+ for (std::vector<unsigned>::const_iterator I = ModRMDecision.begin(),
+ E = ModRMDecision.end(); I != E; ++I) {
+ o1.indent(i1 * 2) << format("0x%hx", *I) << ", /* "
+ << InstructionSpecifiers[*I].name << " */\n";
+ }
+ i1--;
+ }
o2.indent(i2) << "{ /* struct ModRMDecision */" << "\n";
i2++;
o2.indent(i2) << stringForDecisionType(dt) << "," << "\n";
- o2.indent(i2) << sEntryNumber << " /* Table" << sTableNumber << " */\n";
+ o2.indent(i2) << EntryNumber << " /* Table" << EntryNumber << " */\n";
i2--;
o2.indent(i2) << "}";
@@ -476,6 +495,7 @@ void DisassemblerTables::emitModRMDecision(raw_ostream &o1, raw_ostream &o2,
void DisassemblerTables::emitOpcodeDecision(raw_ostream &o1, raw_ostream &o2,
unsigned &i1, unsigned &i2,
+ unsigned &ModRMTableNum,
OpcodeDecision &decision) const {
o2.indent(i2) << "{ /* struct OpcodeDecision */" << "\n";
i2++;
@@ -487,7 +507,8 @@ void DisassemblerTables::emitOpcodeDecision(raw_ostream &o1, raw_ostream &o2,
o2 << "/* 0x" << format("%02hhx", index) << " */" << "\n";
- emitModRMDecision(o1, o2, i1, i2, decision.modRMDecisions[index]);
+ emitModRMDecision(o1, o2, i1, i2, ModRMTableNum,
+ decision.modRMDecisions[index]);
if (index < 255)
o2 << ",";
@@ -503,6 +524,7 @@ void DisassemblerTables::emitOpcodeDecision(raw_ostream &o1, raw_ostream &o2,
void DisassemblerTables::emitContextDecision(raw_ostream &o1, raw_ostream &o2,
unsigned &i1, unsigned &i2,
+ unsigned &ModRMTableNum,
ContextDecision &decision,
const char* name) const {
o2.indent(i2) << "static const struct ContextDecision " << name << " = {\n";
@@ -516,7 +538,8 @@ void DisassemblerTables::emitContextDecision(raw_ostream &o1, raw_ostream &o2,
o2 << " */";
o2 << "\n";
- emitOpcodeDecision(o1, o2, i1, i2, decision.opcodeDecisions[index]);
+ emitOpcodeDecision(o1, o2, i1, i2, ModRMTableNum,
+ decision.opcodeDecisions[index]);
if (index + 1 < IC_max)
o2 << ", ";
@@ -622,6 +645,12 @@ void DisassemblerTables::emitContextTable(raw_ostream &o, unsigned &i) const {
if ((index & ATTR_VEXL) && (index & ATTR_REXW) && (index & ATTR_OPSIZE))
o << "IC_VEX_L_W_OPSIZE";
+ else if ((index & ATTR_VEXL) && (index & ATTR_REXW) && (index & ATTR_XD))
+ o << "IC_VEX_L_W_XD";
+ else if ((index & ATTR_VEXL) && (index & ATTR_REXW) && (index & ATTR_XS))
+ o << "IC_VEX_L_W_XS";
+ else if ((index & ATTR_VEXL) && (index & ATTR_REXW))
+ o << "IC_VEX_L_W";
else if ((index & ATTR_VEXL) && (index & ATTR_OPSIZE))
o << "IC_VEX_L_OPSIZE";
else if ((index & ATTR_VEXL) && (index & ATTR_XD))
@@ -699,13 +728,17 @@ void DisassemblerTables::emitContextTable(raw_ostream &o, unsigned &i) const {
}
void DisassemblerTables::emitContextDecisions(raw_ostream &o1, raw_ostream &o2,
- unsigned &i1, unsigned &i2) const {
- emitContextDecision(o1, o2, i1, i2, *Tables[0], ONEBYTE_STR);
- emitContextDecision(o1, o2, i1, i2, *Tables[1], TWOBYTE_STR);
- emitContextDecision(o1, o2, i1, i2, *Tables[2], THREEBYTE38_STR);
- emitContextDecision(o1, o2, i1, i2, *Tables[3], THREEBYTE3A_STR);
- emitContextDecision(o1, o2, i1, i2, *Tables[4], THREEBYTEA6_STR);
- emitContextDecision(o1, o2, i1, i2, *Tables[5], THREEBYTEA7_STR);
+ unsigned &i1, unsigned &i2,
+ unsigned &ModRMTableNum) const {
+ emitContextDecision(o1, o2, i1, i2, ModRMTableNum, *Tables[0], ONEBYTE_STR);
+ emitContextDecision(o1, o2, i1, i2, ModRMTableNum, *Tables[1], TWOBYTE_STR);
+ emitContextDecision(o1, o2, i1, i2, ModRMTableNum, *Tables[2], THREEBYTE38_STR);
+ emitContextDecision(o1, o2, i1, i2, ModRMTableNum, *Tables[3], THREEBYTE3A_STR);
+ emitContextDecision(o1, o2, i1, i2, ModRMTableNum, *Tables[4], THREEBYTEA6_STR);
+ emitContextDecision(o1, o2, i1, i2, ModRMTableNum, *Tables[5], THREEBYTEA7_STR);
+ emitContextDecision(o1, o2, i1, i2, ModRMTableNum, *Tables[6], XOP8_MAP_STR);
+ emitContextDecision(o1, o2, i1, i2, ModRMTableNum, *Tables[7], XOP9_MAP_STR);
+ emitContextDecision(o1, o2, i1, i2, ModRMTableNum, *Tables[8], XOPA_MAP_STR);
}
void DisassemblerTables::emit(raw_ostream &o) const {
@@ -724,11 +757,17 @@ void DisassemblerTables::emit(raw_ostream &o) const {
emitContextTable(o, i2);
o << "\n";
+ unsigned ModRMTableNum = 0;
+
o << "static const InstrUID modRMTable[] = {\n";
i1++;
- emitEmptyTable(o1, i1);
+ std::vector<unsigned> EmptyTable(1, 0);
+ ModRMTable[EmptyTable] = ModRMTableNum;
+ ModRMTableNum += EmptyTable.size();
+ o1 << "/* EmptyTable */\n";
+ o1.indent(i1 * 2) << "0x0,\n";
i1--;
- emitContextDecisions(o1, o2, i1, i2);
+ emitContextDecisions(o1, o2, i1, i2, ModRMTableNum);
o << o1.str();
o << " 0x0\n";
diff --git a/utils/TableGen/X86DisassemblerTables.h b/utils/TableGen/X86DisassemblerTables.h
index 01aeaaf..bf8b127 100644
--- a/utils/TableGen/X86DisassemblerTables.h
+++ b/utils/TableGen/X86DisassemblerTables.h
@@ -20,6 +20,7 @@
#include "X86DisassemblerShared.h"
#include "X86ModRMFilters.h"
#include "llvm/Support/raw_ostream.h"
+#include <map>
#include <vector>
namespace llvm {
@@ -39,7 +40,14 @@ private:
/// [3] three-byte opcodes of the form 0f 3a __
/// [4] three-byte opcodes of the form 0f a6 __
/// [5] three-byte opcodes of the form 0f a7 __
- ContextDecision* Tables[6];
+ /// [6] XOP8 map opcode
+ /// [7] XOP9 map opcode
+ /// [8] XOPA map opcode
+ ContextDecision* Tables[9];
+
+ // Table of ModRM encodings.
+ typedef std::map<std::vector<unsigned>, unsigned> ModRMMapTy;
+ mutable ModRMMapTy ModRMTable;
/// The instruction information table
std::vector<InstructionSpecifier> InstructionSpecifiers;
@@ -47,22 +55,6 @@ private:
/// True if there are primary decode conflicts in the instruction set
bool HasConflicts;
- /// emitOneID - Emits a table entry for a single instruction entry, at the
- /// innermost level of the structure hierarchy. The entry is printed out
- /// in the format "nnnn, /* MNEMONIC */" where nnnn is the ID in decimal,
- /// the comma is printed if addComma is true, and the menonic is the name
- /// of the instruction as listed in the LLVM tables.
- ///
- /// @param o - The output stream to print the entry on.
- /// @param i - The indentation level for o.
- /// @param id - The unique ID of the instruction to print.
- /// @param addComma - Whether or not to print a comma after the ID. True if
- /// additional items will follow.
- void emitOneID(raw_ostream &o,
- uint32_t &i,
- InstrUID id,
- bool addComma) const;
-
/// emitModRMDecision - Emits a table of entries corresponding to a single
/// ModR/M decision. Compacts the ModR/M decision if possible. ModR/M
/// decisions are printed as:
@@ -91,12 +83,11 @@ private:
/// @param o2 - The output stream to print the decision structure to.
/// @param i1 - The indentation level to use with stream o1.
/// @param i2 - The indentation level to use with stream o2.
+ /// @param ModRMTableNum - next table number for adding to ModRMTable.
/// @param decision - The ModR/M decision to emit. This decision has 256
/// entries - emitModRMDecision decides how to compact it.
- void emitModRMDecision(raw_ostream &o1,
- raw_ostream &o2,
- uint32_t &i1,
- uint32_t &i2,
+ void emitModRMDecision(raw_ostream &o1, raw_ostream &o2,
+ unsigned &i1, unsigned &i2, unsigned &ModRMTableNum,
ModRMDecision &decision) const;
/// emitOpcodeDecision - Emits an OpcodeDecision and all its subsidiary ModR/M
@@ -120,12 +111,11 @@ private:
/// @param o2 - The output stream for the decision structure itself.
/// @param i1 - The indent level to use with stream o1.
/// @param i2 - The indent level to use with stream o2.
+ /// @param ModRMTableNum - next table number for adding to ModRMTable.
/// @param decision - The OpcodeDecision to emit along with its subsidiary
/// structures.
- void emitOpcodeDecision(raw_ostream &o1,
- raw_ostream &o2,
- uint32_t &i1,
- uint32_t &i2,
+ void emitOpcodeDecision(raw_ostream &o1, raw_ostream &o2,
+ unsigned &i1, unsigned &i2, unsigned &ModRMTableNum,
OpcodeDecision &decision) const;
/// emitContextDecision - Emits a ContextDecision and all its subsidiary
@@ -155,15 +145,13 @@ private:
/// @param o2 - The output stream to print the decision structure to.
/// @param i1 - The indent level to use with stream o1.
/// @param i2 - The indent level to use with stream o2.
+ /// @param ModRMTableNum - next table number for adding to ModRMTable.
/// @param decision - The ContextDecision to emit along with its subsidiary
/// structures.
/// @param name - The name for the ContextDecision.
- void emitContextDecision(raw_ostream &o1,
- raw_ostream &o2,
- uint32_t &i1,
- uint32_t &i2,
- ContextDecision &decision,
- const char* name) const;
+ void emitContextDecision(raw_ostream &o1, raw_ostream &o2,
+ unsigned &i1, unsigned &i2, unsigned &ModRMTableNum,
+ ContextDecision &decision, const char* name) const;
/// emitInstructionInfo - Prints the instruction specifier table, which has
/// one entry for each instruction, and contains name and operand
@@ -194,7 +182,7 @@ private:
/// @param o - The output stream to which the instruction table should be
/// written.
/// @param i - The indent level for use with the stream.
- void emitInstructionInfo(raw_ostream &o, uint32_t &i) const;
+ void emitInstructionInfo(raw_ostream &o, unsigned &i) const;
/// emitContextTable - Prints the table that is used to translate from an
/// instruction attribute mask to an instruction context. This table is
@@ -220,10 +208,10 @@ private:
/// @param o2 - The output stream to print the decision structures to.
/// @param i1 - The indent level to use with stream o1.
/// @param i2 - The indent level to use with stream o2.
- void emitContextDecisions(raw_ostream &o1,
- raw_ostream &o2,
- uint32_t &i1,
- uint32_t &i2) const;
+ /// @param ModRMTableNum - next table number for adding to ModRMTable.
+ void emitContextDecisions(raw_ostream &o1, raw_ostream &o2,
+ unsigned &i1, unsigned &i2,
+ unsigned &ModRMTableNum) const;
/// setTableFields - Uses a ModRMFilter to set the appropriate entries in a
/// ModRMDecision to refer to a particular instruction ID.
diff --git a/utils/TableGen/X86RecognizableInstr.cpp b/utils/TableGen/X86RecognizableInstr.cpp
index 7962f9b..708e72d 100644
--- a/utils/TableGen/X86RecognizableInstr.cpp
+++ b/utils/TableGen/X86RecognizableInstr.cpp
@@ -79,7 +79,8 @@ namespace X86Local {
DC = 7, DD = 8, DE = 9, DF = 10,
XD = 11, XS = 12,
T8 = 13, P_TA = 14,
- A6 = 15, A7 = 16, T8XD = 17, T8XS = 18, TAXD = 19
+ A6 = 15, A7 = 16, T8XD = 17, T8XS = 18, TAXD = 19,
+ XOP8 = 20, XOP9 = 21, XOPA = 22
};
}
@@ -134,6 +135,10 @@ namespace X86Local {
#define THREE_BYTE_38_EXTENSION_TABLES \
EXTENSION_TABLE(F3)
+#define XOP9_MAP_EXTENSION_TABLES \
+ EXTENSION_TABLE(01) \
+ EXTENSION_TABLE(02)
+
using namespace X86Disassembler;
/// needsModRMForDecode - Indicates whether a particular instruction requires a
@@ -239,6 +244,7 @@ RecognizableInstr::RecognizableInstr(DisassemblerTables &tables,
HasEVEXPrefix = Rec->getValueAsBit("hasEVEXPrefix");
HasEVEX_L2Prefix = Rec->getValueAsBit("hasEVEX_L2");
HasEVEX_K = Rec->getValueAsBit("hasEVEX_K");
+ HasEVEX_KZ = Rec->getValueAsBit("hasEVEX_Z");
HasEVEX_B = Rec->getValueAsBit("hasEVEX_B");
HasLockPrefix = Rec->getValueAsBit("hasLockPrefix");
IsCodeGenOnly = Rec->getValueAsBit("isCodeGenOnly");
@@ -299,8 +305,10 @@ void RecognizableInstr::processInstr(DisassemblerTables &tables,
recogInstr.emitDecodePath(tables);
}
-#define EVEX_KB(n) (HasEVEX_K && HasEVEX_B? n##_K_B : \
- (HasEVEX_K? n##_K : (HasEVEX_B ? n##_B : n)))
+#define EVEX_KB(n) (HasEVEX_KZ && HasEVEX_B ? n##_KZ_B : \
+ (HasEVEX_K && HasEVEX_B ? n##_K_B : \
+ (HasEVEX_KZ ? n##_KZ : \
+ (HasEVEX_K? n##_K : (HasEVEX_B ? n##_B : n)))))
InstructionContext RecognizableInstr::insnContext() const {
InstructionContext insnContext;
@@ -486,7 +494,8 @@ RecognizableInstr::filter_ret RecognizableInstr::filter() const {
assert(Rec->isSubClassOf("X86Inst") && "Can only filter X86 instructions");
if (Form == X86Local::Pseudo ||
- (IsCodeGenOnly && Name.find("_REV") == Name.npos))
+ (IsCodeGenOnly && Name.find("_REV") == Name.npos &&
+ Name.find("INC32") == Name.npos && Name.find("DEC32") == Name.npos))
return FILTER_STRONG;
@@ -516,35 +525,17 @@ RecognizableInstr::filter_ret RecognizableInstr::filter() const {
// Filter out alternate forms of AVX instructions
if (Name.find("_alt") != Name.npos ||
- Name.find("XrYr") != Name.npos ||
- (Name.find("r64r") != Name.npos && Name.find("r64r64") == Name.npos) ||
+ (Name.find("r64r") != Name.npos && Name.find("r64r64") == Name.npos && Name.find("r64r8") == Name.npos) ||
Name.find("_64mr") != Name.npos ||
- Name.find("Xrr") != Name.npos ||
Name.find("rr64") != Name.npos)
return FILTER_WEAK;
// Special cases.
- if (Name.find("PCMPISTRI") != Name.npos && Name != "PCMPISTRI")
- return FILTER_WEAK;
- if (Name.find("PCMPESTRI") != Name.npos && Name != "PCMPESTRI")
- return FILTER_WEAK;
-
- if (Name.find("MOV") != Name.npos && Name.find("r0") != Name.npos)
- return FILTER_WEAK;
- if (Name.find("MOVZ") != Name.npos && Name.find("MOVZX") == Name.npos)
- return FILTER_WEAK;
- if (Name.find("Fs") != Name.npos)
- return FILTER_WEAK;
if (Name == "PUSH64i16" ||
Name == "MOVPQI2QImr" ||
Name == "VMOVPQI2QImr" ||
- Name == "MMX_MOVD64rrv164" ||
- Name == "MOV64ri64i32" ||
- Name == "VMASKMOVDQU64" ||
- Name == "VEXTRACTPSrr64" ||
- Name == "VMOVQd64rr" ||
- Name == "VMOVQs64rr")
+ Name == "VMASKMOVDQU64")
return FILTER_WEAK;
// XACQUIRE and XRELEASE reuse REPNE and REP respectively.
@@ -553,11 +544,6 @@ RecognizableInstr::filter_ret RecognizableInstr::filter() const {
Name == "XRELEASE_PREFIX")
return FILTER_WEAK;
- if (HasFROperands && Name.find("MOV") != Name.npos &&
- ((Name.find("2") != Name.npos && Name.find("32") == Name.npos) ||
- (Name.find("to") != Name.npos)))
- return FILTER_STRONG;
-
return FILTER_NORMAL;
}
@@ -818,17 +804,20 @@ void RecognizableInstr::emitInstructionSpecifier(DisassemblerTables &tables) {
case X86Local::MRM5r:
case X86Local::MRM6r:
case X86Local::MRM7r:
- // Operand 1 is a register operand in the R/M field.
- // Operand 2 (optional) is an immediate or relocation.
- // Operand 3 (optional) is an immediate.
- if (HasVEX_4VPrefix)
- assert(numPhysicalOperands <= 3 &&
- "Unexpected number of operands for MRMnRFrm with VEX_4V");
- else
- assert(numPhysicalOperands <= 3 &&
- "Unexpected number of operands for MRMnRFrm");
+ {
+ // Operand 1 is a register operand in the R/M field.
+ // Operand 2 (optional) is an immediate or relocation.
+ // Operand 3 (optional) is an immediate.
+ unsigned kOp = (HasEVEX_K) ? 1:0;
+ unsigned Op4v = (HasVEX_4VPrefix) ? 1:0;
+ if (numPhysicalOperands > 3 + kOp + Op4v)
+ llvm_unreachable("Unexpected number of operands for MRMnr");
+ }
if (HasVEX_4VPrefix)
HANDLE_OPERAND(vvvvRegister)
+
+ if (HasEVEX_K)
+ HANDLE_OPERAND(writemaskRegister)
HANDLE_OPTIONAL(rmRegister)
HANDLE_OPTIONAL(relocation)
HANDLE_OPTIONAL(immediate)
@@ -841,16 +830,19 @@ void RecognizableInstr::emitInstructionSpecifier(DisassemblerTables &tables) {
case X86Local::MRM5m:
case X86Local::MRM6m:
case X86Local::MRM7m:
- // Operand 1 is a memory operand (possibly SIB-extended)
- // Operand 2 (optional) is an immediate or relocation.
- if (HasVEX_4VPrefix)
- assert(numPhysicalOperands >= 2 && numPhysicalOperands <= 3 &&
- "Unexpected number of operands for MRMnMFrm");
- else
- assert(numPhysicalOperands >= 1 && numPhysicalOperands <= 2 &&
- "Unexpected number of operands for MRMnMFrm");
+ {
+ // Operand 1 is a memory operand (possibly SIB-extended)
+ // Operand 2 (optional) is an immediate or relocation.
+ unsigned kOp = (HasEVEX_K) ? 1:0;
+ unsigned Op4v = (HasVEX_4VPrefix) ? 1:0;
+ if (numPhysicalOperands < 1 + kOp + Op4v ||
+ numPhysicalOperands > 2 + kOp + Op4v)
+ llvm_unreachable("Unexpected number of operands for MRMnm");
+ }
if (HasVEX_4VPrefix)
HANDLE_OPERAND(vvvvRegister)
+ if (HasEVEX_K)
+ HANDLE_OPERAND(writemaskRegister)
HANDLE_OPERAND(memory)
HANDLE_OPTIONAL(relocation)
break;
@@ -902,6 +894,7 @@ void RecognizableInstr::emitDecodePath(DisassemblerTables &tables) const {
uint8_t opcodeToSet = 0;
switch (Prefix) {
+ default: llvm_unreachable("Invalid prefix!");
// Extended two-byte opcodes can start with f2 0f, f3 0f, or 0f
case X86Local::XD:
case X86Local::XS:
@@ -1015,6 +1008,63 @@ void RecognizableInstr::emitDecodePath(DisassemblerTables &tables) const {
filter = new DumbFilter();
opcodeToSet = Opcode;
break;
+ case X86Local::XOP8:
+ opcodeType = XOP8_MAP;
+ if (needsModRMForDecode(Form))
+ filter = new ModFilter(isRegFormat(Form));
+ else
+ filter = new DumbFilter();
+ opcodeToSet = Opcode;
+ break;
+ case X86Local::XOP9:
+ opcodeType = XOP9_MAP;
+ switch (Opcode) {
+ default:
+ if (needsModRMForDecode(Form))
+ filter = new ModFilter(isRegFormat(Form));
+ else
+ filter = new DumbFilter();
+ break;
+#define EXTENSION_TABLE(n) case 0x##n:
+ XOP9_MAP_EXTENSION_TABLES
+#undef EXTENSION_TABLE
+ switch (Form) {
+ default:
+ llvm_unreachable("Unhandled XOP9 extended opcode");
+ case X86Local::MRM0r:
+ case X86Local::MRM1r:
+ case X86Local::MRM2r:
+ case X86Local::MRM3r:
+ case X86Local::MRM4r:
+ case X86Local::MRM5r:
+ case X86Local::MRM6r:
+ case X86Local::MRM7r:
+ filter = new ExtendedFilter(true, Form - X86Local::MRM0r);
+ break;
+ case X86Local::MRM0m:
+ case X86Local::MRM1m:
+ case X86Local::MRM2m:
+ case X86Local::MRM3m:
+ case X86Local::MRM4m:
+ case X86Local::MRM5m:
+ case X86Local::MRM6m:
+ case X86Local::MRM7m:
+ filter = new ExtendedFilter(false, Form - X86Local::MRM0m);
+ break;
+ MRM_MAPPING
+ } // switch (Form)
+ break;
+ } // switch (Opcode)
+ opcodeToSet = Opcode;
+ break;
+ case X86Local::XOPA:
+ opcodeType = XOPA_MAP;
+ if (needsModRMForDecode(Form))
+ filter = new ModFilter(isRegFormat(Form));
+ else
+ filter = new DumbFilter();
+ opcodeToSet = Opcode;
+ break;
case X86Local::D8:
case X86Local::D9:
case X86Local::DA:
@@ -1035,7 +1085,7 @@ void RecognizableInstr::emitDecodePath(DisassemblerTables &tables) const {
opcodeToSet = 0xd8 + (Prefix - X86Local::D8);
break;
case X86Local::REP:
- default:
+ case 0:
opcodeType = ONEBYTE;
switch (Opcode) {
#define EXTENSION_TABLE(n) case 0x##n:
@@ -1166,6 +1216,7 @@ OperandType RecognizableInstr::typeFromString(const std::string &s,
TYPE("i32i8imm", TYPE_IMM32)
TYPE("u32u8imm", TYPE_IMM32)
TYPE("GR32", TYPE_Rv)
+ TYPE("GR32orGR64", TYPE_R32)
TYPE("i64mem", TYPE_Mv)
TYPE("i64i32imm", TYPE_IMM64)
TYPE("i64i8imm", TYPE_IMM64)
@@ -1276,6 +1327,7 @@ OperandEncoding RecognizableInstr::rmRegisterEncodingFromString
bool hasOpSizePrefix) {
ENCODING("GR16", ENCODING_RM)
ENCODING("GR32", ENCODING_RM)
+ ENCODING("GR32orGR64", ENCODING_RM)
ENCODING("GR64", ENCODING_RM)
ENCODING("GR8", ENCODING_RM)
ENCODING("VR128", ENCODING_RM)
@@ -1299,6 +1351,7 @@ OperandEncoding RecognizableInstr::roRegisterEncodingFromString
bool hasOpSizePrefix) {
ENCODING("GR16", ENCODING_REG)
ENCODING("GR32", ENCODING_REG)
+ ENCODING("GR32orGR64", ENCODING_REG)
ENCODING("GR64", ENCODING_REG)
ENCODING("GR8", ENCODING_REG)
ENCODING("VR128", ENCODING_REG)
diff --git a/utils/TableGen/X86RecognizableInstr.h b/utils/TableGen/X86RecognizableInstr.h
index 7e1d362..4d4686e 100644
--- a/utils/TableGen/X86RecognizableInstr.h
+++ b/utils/TableGen/X86RecognizableInstr.h
@@ -72,6 +72,8 @@ private:
bool HasEVEX_L2Prefix;
/// The hasEVEX_K field from the record
bool HasEVEX_K;
+ /// The hasEVEX_KZ field from the record
+ bool HasEVEX_KZ;
/// The hasEVEX_B field from the record
bool HasEVEX_B;
/// The hasLockPrefix field from the record
diff --git a/utils/buildit/build_llvm b/utils/buildit/build_llvm
index 4ed25f2..9e93216 100755
--- a/utils/buildit/build_llvm
+++ b/utils/buildit/build_llvm
@@ -104,7 +104,8 @@ COMMON_CONFIGURE_OPTS="\
--enable-assertions=$LLVM_ASSERTIONS \
--enable-optimized=$LLVM_OPTIMIZED \
--disable-bindings \
- --disable-zlib"
+ --disable-zlib \
+ --enable-terminfo=no"
COMMON_MAKEFLAGS="\
UNIVERSAL=1 \
diff --git a/utils/emacs/llvm-mode.el b/utils/emacs/llvm-mode.el
index 25d9742..99d3294 100644
--- a/utils/emacs/llvm-mode.el
+++ b/utils/emacs/llvm-mode.el
@@ -32,16 +32,23 @@
"null" "undef" "to" "except" "not" "target" "endian" "little" "big"
"pointersize" "volatile" "fastcc" "coldcc" "cc") 'words) . font-lock-keyword-face)
;; Arithmetic and Logical Operators
- `(,(regexp-opt '("add" "sub" "mul" "div" "rem" "and" "or" "xor"
+ `(,(regexp-opt '("add" "sub" "mul" "sdiv" "udiv" "urem" "srem" "and" "or" "xor"
"setne" "seteq" "setlt" "setgt" "setle" "setge") 'words) . font-lock-keyword-face)
;; Floating-point operators
`(,(regexp-opt '("fadd" "fsub" "fmul" "fdiv" "frem") 'words) . font-lock-keyword-face)
;; Special instructions
- `(,(regexp-opt '("phi" "tail" "call" "cast" "select" "to" "shl" "shr" "fcmp" "icmp" "vaarg" "vanext") 'words) . font-lock-keyword-face)
+ `(,(regexp-opt '("phi" "tail" "call" "select" "to" "shl" "lshr" "ashr" "fcmp" "icmp" "va_arg" "landingpad") 'words) . font-lock-keyword-face)
;; Control instructions
- `(,(regexp-opt '("ret" "br" "switch" "invoke" "unwind" "unreachable") 'words) . font-lock-keyword-face)
+ `(,(regexp-opt '("ret" "br" "switch" "invoke" "resume" "unwind" "unreachable" "indirectbr") 'words) . font-lock-keyword-face)
;; Memory operators
- `(,(regexp-opt '("malloc" "alloca" "free" "load" "store" "getelementptr") 'words) . font-lock-keyword-face)
+ `(,(regexp-opt '("malloc" "alloca" "free" "load" "store" "getelementptr" "fence" "cmpxchg" "atomicrmw") 'words) . font-lock-keyword-face)
+ ;; Casts
+ `(,(regexp-opt '("bitcast" "inttoptr" "ptrtoint" "trunc" "zext" "sext" "fptrunc" "fpext" "fptoui" "fptosi" "uitofp" "sitofp" "addrspacecast") 'words) . font-lock-keyword-face)
+ ;; Vector ops
+ `(,(regexp-opt '("extractelement" "insertelement" "shufflevector") 'words) . font-lock-keyword-face)
+ ;; Aggregate ops
+ `(,(regexp-opt '("extractvalue" "insertvalue") 'words) . font-lock-keyword-face)
+
)
"Syntax highlighting for LLVM"
)
diff --git a/utils/kate/llvm.xml b/utils/kate/llvm.xml
index 1778cfc..dfacfb5 100644
--- a/utils/kate/llvm.xml
+++ b/utils/kate/llvm.xml
@@ -41,7 +41,6 @@
<item> private </item>
<item> linker_private </item>
<item> linker_private_weak </item>
- <item> linker_private_weak_def_auto </item>
<item> internal </item>
<item> available_externally </item>
<item> linkonce </item>
@@ -85,6 +84,7 @@
<item> noredzone </item>
<item> noreturn </item>
<item> nounwind </item>
+ <item> optnone </item>
<item> optsize </item>
<item> readnone </item>
<item> readonly </item>
@@ -157,6 +157,7 @@
<item> ptrtoint </item>
<item> inttoptr </item>
<item> bitcast </item>
+ <item> addrspacecast </item>
<item> icmp </item>
<item> fcmp </item>
<item> phi </item>
diff --git a/utils/lit/TODO b/utils/lit/TODO
index d2ff842..c1a60c6 100644
--- a/utils/lit/TODO
+++ b/utils/lit/TODO
@@ -1,26 +1,166 @@
- - Move temp directory name into local test config.
+================
+ lit TODO Items
+================
- - Add --show-unsupported, don't show by default?
+Infrastructure
+==============
- - Optionally use multiprocessing.
+1. Change to always load suites, then resolve command line arguments?
- - Support valgrind in all configs, and LLVM style valgrind.
+ Currently we expect each input argument to be a path on disk; we do a
+ recursive search to find the test suite for each item, but then we only do a
+ local search based at the input path to find tests. Additionally, for any path
+ that matches a file on disk we explicitly construct a test instance (bypassing
+ the formats on discovery implementation).
- - Support a timeout / ulimit.
+ This has a couple problems:
- - Rename 'lit' injected variable for config to be lit_config.
+ * The test format doesn't have control over the test instances that result
+ from file paths.
- - Allow import of 'lit' in test suite definitions.
+ * It isn't possible to specify virtual tests as inputs. For example, it is not
+ possible to specify an individual subtest to run with the googletest format.
- - Create an explicit test suite object (instead of using the top-level
- TestingConfig object).
+ * The test format doesn't have full control over the discovery of tests in
+ subdirectories.
- - Allow 'lit' driver to cooperate with test suites to add options (or at least
- sanitize accepted params).
+ Instead, we should move to a model whereby first all of the input specifiers
+ are resolved to test suites, and then the resolution of the input specifier is
+ delegated to each test suite. This could take a couple forms:
- - Consider move to identifying all tests by path-to-test-suite and then path to
+ * We could resolve to test suites, then fully load each test suite, then have
+ a fixed process to map input specifiers to tests in the test suite
+ (presumably based on path-in-suite derivations). This has the benefit of
+ being consistent across all test formats, but the downside of requiring
+ loading the entire test suite.
+
+ * We could delegate all of the resolution of specifiers to the test
+ suite. This would allow formats that anticipate large test suites to manage
+ their own resolution for better performance. We could provide a default
+ resolution strategy that was similar to what we do now (start at subpaths
+ for directories, but allow the test format control over what happens for
+ individual tests).
+
+2. Consider move to identifying all tests by path-to-test-suite and then path to
subtest, and don't use test suite names.
- - Consider move to change workflow to always load suites, then resolve command
- line arguments.
+ Currently the test suite name is presented as part of test names, but it has
+ no other useful function, and it is something that has to be skipped over to
+ cut-and-paste a name to subsequently use to rerun a test. If we just
+ represented each test suite by the path to its suite, then it would allow more
+ easy cut-and-paste of the test output lines. This has the downside that the
+ lines might get rather long.
+
+3. Allow 'lit' driver to cooperate with test formats and suites to add options
+ (or at least sanitize accepted params).
+
+ We have started to use the --params method more and more extensively, and it is
+ cumbersome and error prone. Additionally, there are currently various options
+ ``lit`` honors that should more correctly be specified as belonging to the
+ ShTest test format.
+
+ It would be really nice if we could allow test formats and test suites to add
+ their own options to be parsed. The difficulty here, of course, is that we
+ don't know what test formats or test suites are in use until we have parsed the
+ input specifiers. For test formats we could ostensibly require all the possible
+ formats to be registered in order to have options, but for test suites we would
+ certainly have to load the suite before we can query it for what options it
+ understands.
+
+ That leaves us with the following options:
+
+ * Currently we could almost get away with parsing the input specifiers without
+ having done option parsing first (the exception is ``--config-prefix``) but
+ that isn't a very extensible design.
+
+ * We could make a distinction in the command line syntax for test format and
+ test suite options. For example, we could require something like::
+
+ lit -j 1 -sv input-specifier -- --some-format-option
+
+ which would be relatively easy to implement with optparser (I think).
+
+ * We could allow fully interspersed arguments by first extracting the options
+ lit knows about and parsing them, then dispatching the remainder to the
+ formats. This seems the most convenient for users, who are unlikely to care
+ about (or even be aware of) the distinction between the generic lit
+ infrastructure and format or suite specific options.
+
+4. Eliminate duplicate execution models for ShTest tests.
+
+ Currently, the ShTest format uses tests written with shell-script like syntax,
+ and executes them in one of two ways. The first way is by converting them into
+ a bash script and literally executing externally them using bash. The second
+ way is through the use of an internal shell parser and shell execution code
+ (built on the subprocess module). The external execution mode is used on most
+ Unix systems that have bash, the internal execution mode is used on Windows.
+
+ Having two ways to do the same thing is error prone and leads to unnecessary
+ complexity in the testing environment. Additionally, because the mode that
+ converts scripts to bash doesn't try and validate the syntax, it is possible
+ to write tests that use bash shell features unsupported by the internal
+ shell. Such tests won't work on Windows but this may not be obvious to the
+ developer writing the test.
+
+ Another limitation is that when executing the scripts externally, the ShTest
+ format has no idea which commands fail, or what output comes from which
+ commands, so this limits how convenient the output of ShTest failures can be
+ and limits other features (for example, knowing what temporary files were
+ written).
+
+ We should eliminate having two ways of executing the same tests to reduce
+ platform differences and make it easier to develop new features in the ShTest
+ module. This is currently blocked on:
+
+ * The external execution mode is faster in some situations, because it avoids
+ being bottlenecked on the GIL. This can hopefully be obviated simply by
+ using --use-processes.
+
+ * Some tests in LLVM/Clang are explicitly disabled with the internal shell
+ (because they use features specific to bash). We would need to rewrite these
+ tests, or add additional features to the internal shell handling to allow
+ them to pass.
+
+5. Consider changing core to support setup vs. execute distinction.
+
+ Many of the existing test formats are cleanly divided into two phases, once
+ parses the test format and extracts XFAIL and REQUIRES information, etc., and
+ the other code actually executes the test.
+
+ We could make this distinction part of the core infrastructure and that would
+ enable a couple things:
+
+ * The REQUIREs handling could be lifted to the core, which is nice.
+
+ * This would provide a clear place to insert subtest support, because the
+ setup phase could be responsible for providing subtests back to the
+ core. That would provide part of the infrastructure to parallelize them, for
+ example, and would probably interact well with other possible features like
+ parameterized tests.
+
+ * This affords a clean implementation of --no-execute.
+
+ * One possible downside could be for test formats that cannot determine their
+ subtests without having executed the test. Supporting such formats would
+ either force the test to actually be executed in the setup stage (which
+ might be ok, as long as the API was explicitly phrased to support that), or
+ would mean we are forced into supporting subtests as return values from the
+ execute phase.
+
+ Any format can just keep all of its code in execute, presumably, so the only
+ cost of implementing this is its impact on the API and futures changes.
+
+
+Miscellaneous
+=============
+
+* Move temp directory name into local test config.
+
+* Add --show-unsupported, don't show by default?
+
+* Support valgrind in all configs, and LLVM style valgrind.
+
+* Support a timeout / ulimit.
+* Create an explicit test suite object (instead of using the top-level
+ TestingConfig object).
diff --git a/utils/lit/examples/README.txt b/utils/lit/examples/README.txt
new file mode 100644
index 0000000..a59daa8
--- /dev/null
+++ b/utils/lit/examples/README.txt
@@ -0,0 +1,7 @@
+==============
+ lit Examples
+==============
+
+This directory contains examples of 'lit' test suite configurations. The test
+suites they define can be run with 'lit examples/example-name', for more details
+see the README in each example.
diff --git a/utils/lit/examples/many-tests/README.txt b/utils/lit/examples/many-tests/README.txt
new file mode 100644
index 0000000..6bffff1
--- /dev/null
+++ b/utils/lit/examples/many-tests/README.txt
@@ -0,0 +1,10 @@
+========================
+ Many Tests lit Example
+========================
+
+This directory contains a trivial lit test suite configuration that defines a
+custom test format which just generates a large (N=10000) number of tests that
+do a small amount of work in the Python test execution code.
+
+This test suite is useful for testing the performance of lit on large numbers of
+tests.
diff --git a/utils/lit/lit/ExampleTests/ManyTests/lit.local.cfg b/utils/lit/examples/many-tests/lit.cfg
index 6cc4752..8f7b940 100644
--- a/utils/lit/lit/ExampleTests/ManyTests/lit.local.cfg
+++ b/utils/lit/examples/many-tests/lit.cfg
@@ -1,6 +1,6 @@
# -*- Python -*-
-Test = lit.Test
+from lit import Test
class ManyTests(object):
def __init__(self, N=10000):
diff --git a/utils/lit/lit/ExampleTests/Clang/fsyntax-only.c b/utils/lit/lit/ExampleTests/Clang/fsyntax-only.c
deleted file mode 100644
index a4a064b..0000000
--- a/utils/lit/lit/ExampleTests/Clang/fsyntax-only.c
+++ /dev/null
@@ -1,4 +0,0 @@
-// RUN: clang -fsyntax-only -Xclang -verify %s
-
-int f0(void) {} // expected-warning {{control reaches end of non-void function}}
-
diff --git a/utils/lit/lit/ExampleTests/Clang/lit.cfg b/utils/lit/lit/ExampleTests/Clang/lit.cfg
deleted file mode 100644
index 9295bd9..0000000
--- a/utils/lit/lit/ExampleTests/Clang/lit.cfg
+++ /dev/null
@@ -1,47 +0,0 @@
-# -*- Python -*-
-
-# Configuration file for the 'lit' test runner.
-
-# name: The name of this test suite.
-config.name = 'Clang'
-
-# testFormat: The test format to use to interpret tests.
-#
-# For now we require '&&' between commands, until they get globally killed and
-# the test runner updated.
-config.test_format = lit.formats.ShTest(execute_external = True)
-
-# suffixes: A list of file extensions to treat as test files.
-config.suffixes = ['.c', '.cpp', '.m', '.mm']
-
-# target_triple: Used by ShTest format for XFAIL checks.
-config.target_triple = 'foo'
-
-###
-
-# Discover the 'clang' and 'clangcc' to use.
-
-import os
-
-def inferClang(PATH):
- # Determine which clang to use.
- clang = os.getenv('CLANG')
-
- # If the user set clang in the environment, definitely use that and don't
- # try to validate.
- if clang:
- return clang
-
- # Otherwise look in the path.
- clang = lit.util.which('clang', PATH)
-
- if not clang:
- lit.fatal("couldn't find 'clang' program, try setting "
- "CLANG in your environment")
-
- return clang
-
-clang = inferClang(config.environment['PATH'])
-if not lit.quiet:
- lit.note('using clang: %r' % clang)
-config.substitutions.append( (' clang ', ' ' + clang + ' ') )
diff --git a/utils/lit/lit/ExampleTests/LLVM.InTree/test/Bar/data.txt b/utils/lit/lit/ExampleTests/LLVM.InTree/test/Bar/data.txt
deleted file mode 100644
index 45b983b..0000000
--- a/utils/lit/lit/ExampleTests/LLVM.InTree/test/Bar/data.txt
+++ /dev/null
@@ -1 +0,0 @@
-hi
diff --git a/utils/lit/lit/ExampleTests/LLVM.InTree/test/Bar/pct-S.ll b/utils/lit/lit/ExampleTests/LLVM.InTree/test/Bar/pct-S.ll
deleted file mode 100644
index 3ff3633..0000000
--- a/utils/lit/lit/ExampleTests/LLVM.InTree/test/Bar/pct-S.ll
+++ /dev/null
@@ -1 +0,0 @@
-; RUN: grep "hi" %S/data.txt
diff --git a/utils/lit/lit/ExampleTests/LLVM.InTree/test/lit.cfg b/utils/lit/lit/ExampleTests/LLVM.InTree/test/lit.cfg
deleted file mode 100644
index 533c445..0000000
--- a/utils/lit/lit/ExampleTests/LLVM.InTree/test/lit.cfg
+++ /dev/null
@@ -1,66 +0,0 @@
-# -*- Python -*-
-
-# Configuration file for the 'lit' test runner.
-
-import os
-
-# name: The name of this test suite.
-config.name = 'LLVM'
-
-# testFormat: The test format to use to interpret tests.
-config.test_format = lit.formats.ShTest()
-
-# suffixes: A list of file extensions to treat as test files, this is actually
-# set by on_clone().
-config.suffixes = [ '.ll' ]
-
-# test_source_root: The root path where tests are located.
-config.test_source_root = os.path.dirname(__file__)
-
-# test_exec_root: The root path where tests should be run.
-llvm_obj_root = getattr(config, 'llvm_obj_root', None)
-if llvm_obj_root is not None:
- config.test_exec_root = os.path.join(llvm_obj_root, 'test')
-
-###
-
-import os
-
-# Check that the object root is known.
-if config.test_exec_root is None:
- # Otherwise, we haven't loaded the site specific configuration (the user is
- # probably trying to run on a test file directly, and either the site
- # configuration hasn't been created by the build system, or we are in an
- # out-of-tree build situation).
-
- # Try to detect the situation where we are using an out-of-tree build by
- # looking for 'llvm-config'.
- #
- # FIXME: I debated (i.e., wrote and threw away) adding logic to
- # automagically generate the lit.site.cfg if we are in some kind of fresh
- # build situation. This means knowing how to invoke the build system
- # though, and I decided it was too much magic.
-
- llvm_config = lit.util.which('llvm-config', config.environment['PATH'])
- if not llvm_config:
- lit.fatal('No site specific configuration available!')
-
- # Get the source and object roots.
- llvm_src_root = lit.util.capture(['llvm-config', '--src-root']).strip()
- llvm_obj_root = lit.util.capture(['llvm-config', '--obj-root']).strip()
-
- # Validate that we got a tree which points to here.
- this_src_root = os.path.dirname(config.test_source_root)
- if os.path.realpath(llvm_src_root) != os.path.realpath(this_src_root):
- lit.fatal('No site specific configuration available!')
-
- # Check that the site specific configuration exists.
- site_cfg = os.path.join(llvm_obj_root, 'test', 'lit.site.cfg')
- if not os.path.exists(site_cfg):
- lit.fatal('No site specific configuration available!')
-
- # Okay, that worked. Notify the user of the automagic, and reconfigure.
- lit.note('using out-of-tree build at %r' % llvm_obj_root)
- lit.load_config(config, site_cfg)
- raise SystemExit
-
diff --git a/utils/lit/lit/ExampleTests/LLVM.InTree/test/lit.site.cfg b/utils/lit/lit/ExampleTests/LLVM.InTree/test/lit.site.cfg
deleted file mode 100644
index d45f3ac..0000000
--- a/utils/lit/lit/ExampleTests/LLVM.InTree/test/lit.site.cfg
+++ /dev/null
@@ -1,7 +0,0 @@
-# -*- Python -*-
-
-# Preserve some key paths for use by main LLVM test suite config.
-config.llvm_obj_root = os.path.dirname(os.path.dirname(__file__))
-
-# Let the main config do the real work.
-lit.load_config(config, os.path.join(config.llvm_obj_root, 'test/lit.cfg'))
diff --git a/utils/lit/lit/ExampleTests/LLVM.OutOfTree/lit.local.cfg b/utils/lit/lit/ExampleTests/LLVM.OutOfTree/lit.local.cfg
deleted file mode 100644
index 80d0c7e..0000000
--- a/utils/lit/lit/ExampleTests/LLVM.OutOfTree/lit.local.cfg
+++ /dev/null
@@ -1 +0,0 @@
-config.excludes = ['src']
diff --git a/utils/lit/lit/ExampleTests/LLVM.OutOfTree/obj/test/Foo/lit.local.cfg b/utils/lit/lit/ExampleTests/LLVM.OutOfTree/obj/test/Foo/lit.local.cfg
deleted file mode 100644
index e69de29..0000000
--- a/utils/lit/lit/ExampleTests/LLVM.OutOfTree/obj/test/Foo/lit.local.cfg
+++ /dev/null
diff --git a/utils/lit/lit/ExampleTests/LLVM.OutOfTree/obj/test/lit.site.cfg b/utils/lit/lit/ExampleTests/LLVM.OutOfTree/obj/test/lit.site.cfg
deleted file mode 100644
index 94a02d8..0000000
--- a/utils/lit/lit/ExampleTests/LLVM.OutOfTree/obj/test/lit.site.cfg
+++ /dev/null
@@ -1,8 +0,0 @@
-# -*- Python -*-
-
-# Preserve some key paths for use by main LLVM test suite config.
-config.llvm_obj_root = os.path.dirname(os.path.dirname(__file__))
-
-# Let the main config do the real work.
-lit.load_config(config, os.path.join(config.llvm_obj_root,
- '../src/test/lit.cfg'))
diff --git a/utils/lit/lit/ExampleTests/LLVM.OutOfTree/src/test/Foo/data.txt b/utils/lit/lit/ExampleTests/LLVM.OutOfTree/src/test/Foo/data.txt
deleted file mode 100644
index 45b983b..0000000
--- a/utils/lit/lit/ExampleTests/LLVM.OutOfTree/src/test/Foo/data.txt
+++ /dev/null
@@ -1 +0,0 @@
-hi
diff --git a/utils/lit/lit/ExampleTests/LLVM.OutOfTree/src/test/Foo/pct-S.ll b/utils/lit/lit/ExampleTests/LLVM.OutOfTree/src/test/Foo/pct-S.ll
deleted file mode 100644
index 3ff3633..0000000
--- a/utils/lit/lit/ExampleTests/LLVM.OutOfTree/src/test/Foo/pct-S.ll
+++ /dev/null
@@ -1 +0,0 @@
-; RUN: grep "hi" %S/data.txt
diff --git a/utils/lit/lit/ExampleTests/LLVM.OutOfTree/src/test/lit.cfg b/utils/lit/lit/ExampleTests/LLVM.OutOfTree/src/test/lit.cfg
deleted file mode 100644
index 533c445..0000000
--- a/utils/lit/lit/ExampleTests/LLVM.OutOfTree/src/test/lit.cfg
+++ /dev/null
@@ -1,66 +0,0 @@
-# -*- Python -*-
-
-# Configuration file for the 'lit' test runner.
-
-import os
-
-# name: The name of this test suite.
-config.name = 'LLVM'
-
-# testFormat: The test format to use to interpret tests.
-config.test_format = lit.formats.ShTest()
-
-# suffixes: A list of file extensions to treat as test files, this is actually
-# set by on_clone().
-config.suffixes = [ '.ll' ]
-
-# test_source_root: The root path where tests are located.
-config.test_source_root = os.path.dirname(__file__)
-
-# test_exec_root: The root path where tests should be run.
-llvm_obj_root = getattr(config, 'llvm_obj_root', None)
-if llvm_obj_root is not None:
- config.test_exec_root = os.path.join(llvm_obj_root, 'test')
-
-###
-
-import os
-
-# Check that the object root is known.
-if config.test_exec_root is None:
- # Otherwise, we haven't loaded the site specific configuration (the user is
- # probably trying to run on a test file directly, and either the site
- # configuration hasn't been created by the build system, or we are in an
- # out-of-tree build situation).
-
- # Try to detect the situation where we are using an out-of-tree build by
- # looking for 'llvm-config'.
- #
- # FIXME: I debated (i.e., wrote and threw away) adding logic to
- # automagically generate the lit.site.cfg if we are in some kind of fresh
- # build situation. This means knowing how to invoke the build system
- # though, and I decided it was too much magic.
-
- llvm_config = lit.util.which('llvm-config', config.environment['PATH'])
- if not llvm_config:
- lit.fatal('No site specific configuration available!')
-
- # Get the source and object roots.
- llvm_src_root = lit.util.capture(['llvm-config', '--src-root']).strip()
- llvm_obj_root = lit.util.capture(['llvm-config', '--obj-root']).strip()
-
- # Validate that we got a tree which points to here.
- this_src_root = os.path.dirname(config.test_source_root)
- if os.path.realpath(llvm_src_root) != os.path.realpath(this_src_root):
- lit.fatal('No site specific configuration available!')
-
- # Check that the site specific configuration exists.
- site_cfg = os.path.join(llvm_obj_root, 'test', 'lit.site.cfg')
- if not os.path.exists(site_cfg):
- lit.fatal('No site specific configuration available!')
-
- # Okay, that worked. Notify the user of the automagic, and reconfigure.
- lit.note('using out-of-tree build at %r' % llvm_obj_root)
- lit.load_config(config, site_cfg)
- raise SystemExit
-
diff --git a/utils/lit/lit/ExampleTests/ShExternal/lit.local.cfg b/utils/lit/lit/ExampleTests/ShExternal/lit.local.cfg
deleted file mode 100644
index 1061da6..0000000
--- a/utils/lit/lit/ExampleTests/ShExternal/lit.local.cfg
+++ /dev/null
@@ -1,6 +0,0 @@
-# -*- Python -*-
-
-config.test_format = lit.formats.ShTest(execute_external = True)
-
-config.suffixes = ['.c']
-
diff --git a/utils/lit/lit/ExampleTests/ShInternal/lit.local.cfg b/utils/lit/lit/ExampleTests/ShInternal/lit.local.cfg
deleted file mode 100644
index 448eaa4..0000000
--- a/utils/lit/lit/ExampleTests/ShInternal/lit.local.cfg
+++ /dev/null
@@ -1,6 +0,0 @@
-# -*- Python -*-
-
-config.test_format = lit.formats.ShTest(execute_external = False)
-
-config.suffixes = ['.c']
-
diff --git a/utils/lit/lit/ExampleTests/fail.c b/utils/lit/lit/ExampleTests/fail.c
deleted file mode 100644
index 84db41a..0000000
--- a/utils/lit/lit/ExampleTests/fail.c
+++ /dev/null
@@ -1,2 +0,0 @@
-// RUN: echo 'I am some stdout'
-// RUN: false
diff --git a/utils/lit/lit/ExampleTests/lit.cfg b/utils/lit/lit/ExampleTests/lit.cfg
deleted file mode 100644
index 164daba..0000000
--- a/utils/lit/lit/ExampleTests/lit.cfg
+++ /dev/null
@@ -1,26 +0,0 @@
-# -*- Python -*-
-
-# Configuration file for the 'lit' test runner.
-
-# name: The name of this test suite.
-config.name = 'Examples'
-
-# suffixes: A list of file extensions to treat as test files.
-config.suffixes = ['.c', '.cpp', '.m', '.mm', '.ll']
-
-# testFormat: The test format to use to interpret tests.
-config.test_format = lit.formats.ShTest()
-
-# test_source_root: The path where tests are located (default is the test suite
-# root).
-config.test_source_root = None
-
-# test_exec_root: The path where tests are located (default is the test suite
-# root).
-config.test_exec_root = None
-
-# target_triple: Used by ShTest format for XFAIL checks.
-config.target_triple = 'foo'
-
-# available_features: Used by ShTest format for REQUIRES checks.
-config.available_features.add('some-feature-name')
diff --git a/utils/lit/lit/ExampleTests/pass.c b/utils/lit/lit/ExampleTests/pass.c
deleted file mode 100644
index 5c1031c..0000000
--- a/utils/lit/lit/ExampleTests/pass.c
+++ /dev/null
@@ -1 +0,0 @@
-// RUN: true
diff --git a/utils/lit/lit/ExampleTests/required-and-missing.c b/utils/lit/lit/ExampleTests/required-and-missing.c
deleted file mode 100644
index 47ba72e..0000000
--- a/utils/lit/lit/ExampleTests/required-and-missing.c
+++ /dev/null
@@ -1,4 +0,0 @@
-// This test shouldn't be run, the required feature is missing.
-//
-// RUN: false
-// REQUIRES: some-missing-feature-name
diff --git a/utils/lit/lit/ExampleTests/required-and-present.c b/utils/lit/lit/ExampleTests/required-and-present.c
deleted file mode 100644
index 2a09e08..0000000
--- a/utils/lit/lit/ExampleTests/required-and-present.c
+++ /dev/null
@@ -1,2 +0,0 @@
-// RUN: true
-// REQUIRES: some-feature-name
diff --git a/utils/lit/lit/ExampleTests/vg-fail.c b/utils/lit/lit/ExampleTests/vg-fail.c
deleted file mode 100644
index e3339ff..0000000
--- a/utils/lit/lit/ExampleTests/vg-fail.c
+++ /dev/null
@@ -1,4 +0,0 @@
-// This test should XPASS, when run without valgrind.
-
-// RUN: true
-// XFAIL: valgrind
diff --git a/utils/lit/lit/ExampleTests/xfail-feature.c b/utils/lit/lit/ExampleTests/xfail-feature.c
deleted file mode 100644
index 3444bf8..0000000
--- a/utils/lit/lit/ExampleTests/xfail-feature.c
+++ /dev/null
@@ -1,4 +0,0 @@
-// This test should XPASS.
-
-// RUN: true
-// XFAIL: some-feature-name
diff --git a/utils/lit/lit/ExampleTests/xfail.c b/utils/lit/lit/ExampleTests/xfail.c
deleted file mode 100644
index b36cd99..0000000
--- a/utils/lit/lit/ExampleTests/xfail.c
+++ /dev/null
@@ -1,2 +0,0 @@
-// RUN: false
-// XFAIL: *
diff --git a/utils/lit/lit/ExampleTests/xpass.c b/utils/lit/lit/ExampleTests/xpass.c
deleted file mode 100644
index ad84990..0000000
--- a/utils/lit/lit/ExampleTests/xpass.c
+++ /dev/null
@@ -1,2 +0,0 @@
-// RUN: true
-// XFAIL
diff --git a/utils/lit/lit/LitConfig.py b/utils/lit/lit/LitConfig.py
index bd7a603..b0dde5d 100644
--- a/utils/lit/lit/LitConfig.py
+++ b/utils/lit/lit/LitConfig.py
@@ -1,10 +1,12 @@
from __future__ import absolute_import
+import inspect
import os
+import sys
import lit.Test
-import lit.TestFormats
+import lit.formats
import lit.TestingConfig
-import lit.Util
+import lit.util
class LitConfig:
"""LitConfig - Configuration data for a 'lit' test runner instance, shared
@@ -16,15 +18,6 @@ class LitConfig:
easily.
"""
- # Provide access to Test module.
- Test = lit.Test
-
- # Provide access to built-in formats.
- formats = lit.TestFormats
-
- # Provide access to built-in utility functions.
- util = lit.Util
-
def __init__(self, progname, path, quiet,
useValgrind, valgrindLeakCheck, valgrindArgs,
noExecute, debug, isWindows,
@@ -32,7 +25,7 @@ class LitConfig:
# The name of the test runner.
self.progname = progname
# The items to add to the PATH environment variable.
- self.path = list(map(str, path))
+ self.path = [str(p) for p in path]
self.quiet = bool(quiet)
self.useValgrind = bool(useValgrind)
self.valgrindLeakCheck = bool(valgrindLeakCheck)
@@ -70,23 +63,17 @@ class LitConfig:
path."""
if self.debug:
self.note('load_config from %r' % path)
- return lit.TestingConfig.TestingConfig.frompath(
- path, config.parent, self, mustExist = True, config = config)
+ config.load_from_path(path, self)
+ return config
def getBashPath(self):
"""getBashPath - Get the path to 'bash'"""
- import os
-
if self.bashPath is not None:
return self.bashPath
- self.bashPath = lit.Util.which('bash', os.pathsep.join(self.path))
+ self.bashPath = lit.util.which('bash', os.pathsep.join(self.path))
if self.bashPath is None:
- # Check some known paths.
- for path in ('/bin/bash', '/usr/bin/bash', '/usr/local/bin/bash'):
- if os.path.exists(path):
- self.bashPath = path
- break
+ self.bashPath = lit.util.which('bash')
if self.bashPath is None:
self.warning("Unable to find 'bash'.")
@@ -96,13 +83,13 @@ class LitConfig:
def getToolsPath(self, dir, paths, tools):
if dir is not None and os.path.isabs(dir) and os.path.isdir(dir):
- if not lit.Util.checkToolsPath(dir, tools):
+ if not lit.util.checkToolsPath(dir, tools):
return None
else:
- dir = lit.Util.whichTools(tools, paths)
+ dir = lit.util.whichTools(tools, paths)
# bash
- self.bashPath = lit.Util.which('bash', dir)
+ self.bashPath = lit.util.which('bash', dir)
if self.bashPath is None:
self.note("Unable to find 'bash.exe'.")
self.bashPath = ''
@@ -110,8 +97,6 @@ class LitConfig:
return dir
def _write_message(self, kind, message):
- import inspect, os, sys
-
# Get the file/line where this message was generated.
f = inspect.currentframe()
# Step out of _write_message, and then out of wrapper.
@@ -134,6 +119,5 @@ class LitConfig:
self.numErrors += 1
def fatal(self, message):
- import sys
self._write_message('fatal', message)
sys.exit(2)
diff --git a/utils/lit/lit/LitTestCase.py b/utils/lit/lit/LitTestCase.py
index 8951185..e04846c 100644
--- a/utils/lit/lit/LitTestCase.py
+++ b/utils/lit/lit/LitTestCase.py
@@ -1,5 +1,7 @@
+from __future__ import absolute_import
import unittest
-import Test
+
+import lit.Test
"""
TestCase adaptor for providing a 'unittest' compatible interface to 'lit' tests.
@@ -9,10 +11,10 @@ class UnresolvedError(RuntimeError):
pass
class LitTestCase(unittest.TestCase):
- def __init__(self, test, lit_config):
+ def __init__(self, test, run):
unittest.TestCase.__init__(self)
self._test = test
- self._lit_config = lit_config
+ self._run = run
def id(self):
return self._test.getFullName()
@@ -21,10 +23,12 @@ class LitTestCase(unittest.TestCase):
return self._test.getFullName()
def runTest(self):
- tr, output = self._test.config.test_format.execute(
- self._test, self._lit_config)
+ # Run the test.
+ self._run.execute_test(self._test)
- if tr is Test.UNRESOLVED:
- raise UnresolvedError(output)
- elif tr.isFailure:
- self.fail(output)
+ # Adapt the result to unittest.
+ result = self._test.result
+ if result.code is lit.Test.UNRESOLVED:
+ raise UnresolvedError(result.output)
+ elif result.code.isFailure:
+ self.fail(result.output)
diff --git a/utils/lit/lit/ProgressBar.py b/utils/lit/lit/ProgressBar.py
index 0454ba2..e3644f1 100644
--- a/utils/lit/lit/ProgressBar.py
+++ b/utils/lit/lit/ProgressBar.py
@@ -5,6 +5,10 @@
import sys, re, time
+def to_bytes(str):
+ # Encode to Latin1 to get binary data.
+ return str.encode('ISO-8859-1')
+
class TerminalController:
"""
A class that can be used to portably generate formatted output to
@@ -116,26 +120,34 @@ class TerminalController:
set_fg = self._tigetstr('setf')
if set_fg:
for i,color in zip(range(len(self._COLORS)), self._COLORS):
- setattr(self, color, curses.tparm(set_fg, i) or '')
+ setattr(self, color, self._tparm(set_fg, i))
set_fg_ansi = self._tigetstr('setaf')
if set_fg_ansi:
for i,color in zip(range(len(self._ANSICOLORS)), self._ANSICOLORS):
- setattr(self, color, curses.tparm(set_fg_ansi, i) or '')
+ setattr(self, color, self._tparm(set_fg_ansi, i))
set_bg = self._tigetstr('setb')
if set_bg:
for i,color in zip(range(len(self._COLORS)), self._COLORS):
- setattr(self, 'BG_'+color, curses.tparm(set_bg, i) or '')
+ setattr(self, 'BG_'+color, self._tparm(set_bg, i))
set_bg_ansi = self._tigetstr('setab')
if set_bg_ansi:
for i,color in zip(range(len(self._ANSICOLORS)), self._ANSICOLORS):
- setattr(self, 'BG_'+color, curses.tparm(set_bg_ansi, i) or '')
+ setattr(self, 'BG_'+color, self._tparm(set_bg_ansi, i))
+
+ def _tparm(self, arg, index):
+ import curses
+ return curses.tparm(to_bytes(arg), index).decode('ascii') or ''
def _tigetstr(self, cap_name):
# String capabilities can include "delays" of the form "$<2>".
# For any modern terminal, we should be able to just ignore
# these, so strip them out.
import curses
- cap = curses.tigetstr(cap_name) or ''
+ cap = curses.tigetstr(cap_name)
+ if cap is None:
+ cap = ''
+ else:
+ cap = cap.decode('ascii')
return re.sub(r'\$<\d+>[/*]?', '', cap)
def render(self, template):
@@ -269,7 +281,6 @@ class ProgressBar:
self.cleared = 1
def test():
- import time
tc = TerminalController()
p = ProgressBar(tc, 'Tests')
for i in range(101):
diff --git a/utils/lit/lit/ShUtil.py b/utils/lit/lit/ShUtil.py
index fb0689b..1945ba7 100644
--- a/utils/lit/lit/ShUtil.py
+++ b/utils/lit/lit/ShUtil.py
@@ -1,7 +1,7 @@
from __future__ import absolute_import
import itertools
-import lit.Util
+import lit.util
from lit.ShCommands import Command, Pipeline, Seq
class ShLexer:
@@ -75,7 +75,7 @@ class ShLexer:
# Outside of a string, '\\' escapes everything.
self.eat()
if self.pos == self.end:
- lit.Util.warning(
+ lit.util.warning(
"escape at end of quoted argument in: %r" % self.data)
return str
str += self.eat()
@@ -93,7 +93,7 @@ class ShLexer:
# Inside a '"' quoted string, '\\' only escapes the quote
# character and backslash, otherwise it is preserved.
if self.pos == self.end:
- lit.Util.warning(
+ lit.util.warning(
"escape at end of quoted argument in: %r" % self.data)
return str
c = self.eat()
@@ -105,7 +105,7 @@ class ShLexer:
str += '\\' + c
else:
str += c
- lit.Util.warning("missing quote character in %r" % self.data)
+ lit.util.warning("missing quote character in %r" % self.data)
return str
def lex_arg_checked(self, c):
diff --git a/utils/lit/lit/Test.py b/utils/lit/lit/Test.py
index 9471e3a..b4988f5 100644
--- a/utils/lit/lit/Test.py
+++ b/utils/lit/lit/Test.py
@@ -1,8 +1,21 @@
import os
-# Test results.
+# Test result codes.
+
+class ResultCode(object):
+ """Test result codes."""
+
+ # We override __new__ and __getnewargs__ to ensure that pickling still
+ # provides unique ResultCode objects in any particular instance.
+ _instances = {}
+ def __new__(cls, name, isFailure):
+ res = cls._instances.get(name)
+ if res is None:
+ cls._instances[name] = res = super(ResultCode, cls).__new__(cls)
+ return res
+ def __getnewargs__(self):
+ return (self.name, self.isFailure)
-class TestResult:
def __init__(self, name, isFailure):
self.name = name
self.isFailure = isFailure
@@ -11,20 +24,87 @@ class TestResult:
return '%s%r' % (self.__class__.__name__,
(self.name, self.isFailure))
-PASS = TestResult('PASS', False)
-XFAIL = TestResult('XFAIL', False)
-FAIL = TestResult('FAIL', True)
-XPASS = TestResult('XPASS', True)
-UNRESOLVED = TestResult('UNRESOLVED', True)
-UNSUPPORTED = TestResult('UNSUPPORTED', False)
+PASS = ResultCode('PASS', False)
+XFAIL = ResultCode('XFAIL', False)
+FAIL = ResultCode('FAIL', True)
+XPASS = ResultCode('XPASS', True)
+UNRESOLVED = ResultCode('UNRESOLVED', True)
+UNSUPPORTED = ResultCode('UNSUPPORTED', False)
-# Test classes.
+# Test metric values.
-class TestFormat:
- """TestFormat - Test information provider."""
+class MetricValue(object):
+ def format(self):
+ """
+ format() -> str
- def __init__(self, name):
- self.name = name
+ Convert this metric to a string suitable for displaying as part of the
+ console output.
+ """
+ raise RuntimeError("abstract method")
+
+ def todata(self):
+ """
+ todata() -> json-serializable data
+
+ Convert this metric to content suitable for serializing in the JSON test
+ output.
+ """
+ raise RuntimeError("abstract method")
+
+class IntMetricValue(MetricValue):
+ def __init__(self, value):
+ self.value = value
+
+ def format(self):
+ return str(self.value)
+
+ def todata(self):
+ return self.value
+
+class RealMetricValue(MetricValue):
+ def __init__(self, value):
+ self.value = value
+
+ def format(self):
+ return '%.4f' % self.value
+
+ def todata(self):
+ return self.value
+
+# Test results.
+
+class Result(object):
+ """Wrapper for the results of executing an individual test."""
+
+ def __init__(self, code, output='', elapsed=None):
+ # The result code.
+ self.code = code
+ # The test output.
+ self.output = output
+ # The wall timing to execute the test, if timing.
+ self.elapsed = elapsed
+ # The metrics reported by this test.
+ self.metrics = {}
+
+ def addMetric(self, name, value):
+ """
+ addMetric(name, value)
+
+ Attach a test metric to the test result, with the given name and list of
+ values. It is an error to attempt to attach the metrics with the same
+ name multiple times.
+
+ Each value must be an instance of a MetricValue subclass.
+ """
+ if name in self.metrics:
+ raise ValueError("result already includes metrics for %r" % (
+ name,))
+ if not isinstance(value, MetricValue):
+ raise TypeError("unexpected metric value: %r" % (value,))
+ self.metrics[name] = value
+
+# Test classes.
class TestSuite:
"""TestSuite - Information on a group of tests.
@@ -52,27 +132,28 @@ class Test:
self.suite = suite
self.path_in_suite = path_in_suite
self.config = config
- # The test result code, once complete.
+ # A list of conditions under which this test is expected to fail. These
+ # can optionally be provided by test format handlers, and will be
+ # honored when the test result is supplied.
+ self.xfails = []
+ # The test result, once complete.
self.result = None
- # Any additional output from the test, once complete.
- self.output = None
- # The wall time to execute this test, if timing and once complete.
- self.elapsed = None
- # The repeat index of this test, or None.
- self.index = None
-
- def copyWithIndex(self, index):
- import copy
- res = copy.copy(self)
- res.index = index
- return res
- def setResult(self, result, output, elapsed):
- assert self.result is None, "Test result already set!"
+ def setResult(self, result):
+ if self.result is not None:
+ raise ArgumentError("test result already set")
+ if not isinstance(result, Result):
+ raise ArgumentError("unexpected result type")
+
self.result = result
- self.output = output
- self.elapsed = elapsed
+ # Apply the XFAIL handling to resolve the result exit code.
+ if self.isExpectedToFail():
+ if self.result.code == PASS:
+ self.result.code = XPASS
+ elif self.result.code == FAIL:
+ self.result.code = XFAIL
+
def getFullName(self):
return self.suite.config.name + ' :: ' + '/'.join(self.path_in_suite)
@@ -81,3 +162,29 @@ class Test:
def getExecPath(self):
return self.suite.getExecPath(self.path_in_suite)
+
+ def isExpectedToFail(self):
+ """
+ isExpectedToFail() -> bool
+
+ Check whether this test is expected to fail in the current
+ configuration. This check relies on the test xfails property which by
+ some test formats may not be computed until the test has first been
+ executed.
+ """
+
+ # Check if any of the xfails match an available feature or the target.
+ for item in self.xfails:
+ # If this is the wildcard, it always fails.
+ if item == '*':
+ return True
+
+ # If this is an exact match for one of the features, it fails.
+ if item in self.config.available_features:
+ return True
+
+ # If this is a part of the target triple, it fails.
+ if item in self.suite.config.target_triple:
+ return True
+
+ return False
diff --git a/utils/lit/lit/TestFormats.py b/utils/lit/lit/TestFormats.py
deleted file mode 100644
index 9e0c7a0..0000000
--- a/utils/lit/lit/TestFormats.py
+++ /dev/null
@@ -1,229 +0,0 @@
-from __future__ import absolute_import
-import os
-import sys
-
-import lit.Test
-import lit.TestRunner
-import lit.Util
-
-kIsWindows = sys.platform in ['win32', 'cygwin']
-
-class GoogleTest(object):
- def __init__(self, test_sub_dir, test_suffix):
- self.test_sub_dir = os.path.normcase(str(test_sub_dir)).split(';')
- self.test_suffix = str(test_suffix)
-
- # On Windows, assume tests will also end in '.exe'.
- if kIsWindows:
- self.test_suffix += '.exe'
-
- def getGTestTests(self, path, litConfig, localConfig):
- """getGTestTests(path) - [name]
-
- Return the tests available in gtest executable.
-
- Args:
- path: String path to a gtest executable
- litConfig: LitConfig instance
- localConfig: TestingConfig instance"""
-
- try:
- lines = lit.Util.capture([path, '--gtest_list_tests'],
- env=localConfig.environment)
- if kIsWindows:
- lines = lines.replace('\r', '')
- lines = lines.split('\n')
- except:
- litConfig.error("unable to discover google-tests in %r" % path)
- raise StopIteration
-
- nested_tests = []
- for ln in lines:
- if not ln.strip():
- continue
-
- prefix = ''
- index = 0
- while ln[index*2:index*2+2] == ' ':
- index += 1
- while len(nested_tests) > index:
- nested_tests.pop()
-
- ln = ln[index*2:]
- if ln.endswith('.'):
- nested_tests.append(ln)
- else:
- yield ''.join(nested_tests) + ln
-
- # Note: path_in_suite should not include the executable name.
- def getTestsInExecutable(self, testSuite, path_in_suite, execpath,
- litConfig, localConfig):
- if not execpath.endswith(self.test_suffix):
- return
- (dirname, basename) = os.path.split(execpath)
- # Discover the tests in this executable.
- for testname in self.getGTestTests(execpath, litConfig, localConfig):
- testPath = path_in_suite + (basename, testname)
- yield lit.Test.Test(testSuite, testPath, localConfig)
-
- def getTestsInDirectory(self, testSuite, path_in_suite,
- litConfig, localConfig):
- source_path = testSuite.getSourcePath(path_in_suite)
- for filename in os.listdir(source_path):
- filepath = os.path.join(source_path, filename)
- if os.path.isdir(filepath):
- # Iterate over executables in a directory.
- if not os.path.normcase(filename) in self.test_sub_dir:
- continue
- dirpath_in_suite = path_in_suite + (filename, )
- for subfilename in os.listdir(filepath):
- execpath = os.path.join(filepath, subfilename)
- for test in self.getTestsInExecutable(
- testSuite, dirpath_in_suite, execpath,
- litConfig, localConfig):
- yield test
- elif ('.' in self.test_sub_dir):
- for test in self.getTestsInExecutable(
- testSuite, path_in_suite, filepath,
- litConfig, localConfig):
- yield test
-
- def execute(self, test, litConfig):
- testPath,testName = os.path.split(test.getSourcePath())
- while not os.path.exists(testPath):
- # Handle GTest parametrized and typed tests, whose name includes
- # some '/'s.
- testPath, namePrefix = os.path.split(testPath)
- testName = os.path.join(namePrefix, testName)
-
- cmd = [testPath, '--gtest_filter=' + testName]
- if litConfig.useValgrind:
- cmd = litConfig.valgrindArgs + cmd
-
- if litConfig.noExecute:
- return lit.Test.PASS, ''
-
- out, err, exitCode = lit.TestRunner.executeCommand(
- cmd, env=test.config.environment)
-
- if not exitCode:
- return lit.Test.PASS,''
-
- return lit.Test.FAIL, out + err
-
-###
-
-class FileBasedTest(object):
- def getTestsInDirectory(self, testSuite, path_in_suite,
- litConfig, localConfig):
- source_path = testSuite.getSourcePath(path_in_suite)
- for filename in os.listdir(source_path):
- # Ignore dot files and excluded tests.
- if (filename.startswith('.') or
- filename in localConfig.excludes):
- continue
-
- filepath = os.path.join(source_path, filename)
- if not os.path.isdir(filepath):
- base,ext = os.path.splitext(filename)
- if ext in localConfig.suffixes:
- yield lit.Test.Test(testSuite, path_in_suite + (filename,),
- localConfig)
-
-class ShTest(FileBasedTest):
- def __init__(self, execute_external = False):
- self.execute_external = execute_external
-
- def execute(self, test, litConfig):
- return lit.TestRunner.executeShTest(test, litConfig,
- self.execute_external)
-
-###
-
-import re
-import tempfile
-
-class OneCommandPerFileTest:
- # FIXME: Refactor into generic test for running some command on a directory
- # of inputs.
-
- def __init__(self, command, dir, recursive=False,
- pattern=".*", useTempInput=False):
- if isinstance(command, str):
- self.command = [command]
- else:
- self.command = list(command)
- if dir is not None:
- dir = str(dir)
- self.dir = dir
- self.recursive = bool(recursive)
- self.pattern = re.compile(pattern)
- self.useTempInput = useTempInput
-
- def getTestsInDirectory(self, testSuite, path_in_suite,
- litConfig, localConfig):
- dir = self.dir
- if dir is None:
- dir = testSuite.getSourcePath(path_in_suite)
-
- for dirname,subdirs,filenames in os.walk(dir):
- if not self.recursive:
- subdirs[:] = []
-
- subdirs[:] = [d for d in subdirs
- if (d != '.svn' and
- d not in localConfig.excludes)]
-
- for filename in filenames:
- if (filename.startswith('.') or
- not self.pattern.match(filename) or
- filename in localConfig.excludes):
- continue
-
- path = os.path.join(dirname,filename)
- suffix = path[len(dir):]
- if suffix.startswith(os.sep):
- suffix = suffix[1:]
- test = lit.Test.Test(
- testSuite, path_in_suite + tuple(suffix.split(os.sep)),
- localConfig)
- # FIXME: Hack?
- test.source_path = path
- yield test
-
- def createTempInput(self, tmp, test):
- abstract
-
- def execute(self, test, litConfig):
- if test.config.unsupported:
- return (lit.Test.UNSUPPORTED, 'Test is unsupported')
-
- cmd = list(self.command)
-
- # If using temp input, create a temporary file and hand it to the
- # subclass.
- if self.useTempInput:
- tmp = tempfile.NamedTemporaryFile(suffix='.cpp')
- self.createTempInput(tmp, test)
- tmp.flush()
- cmd.append(tmp.name)
- elif hasattr(test, 'source_path'):
- cmd.append(test.source_path)
- else:
- cmd.append(test.getSourcePath())
-
- out, err, exitCode = lit.TestRunner.executeCommand(cmd)
-
- diags = out + err
- if not exitCode and not diags.strip():
- return lit.Test.PASS,''
-
- # Try to include some useful information.
- report = """Command: %s\n""" % ' '.join(["'%s'" % a
- for a in cmd])
- if self.useTempInput:
- report += """Temporary File: %s\n""" % tmp.name
- report += "--\n%s--\n""" % open(tmp.name).read()
- report += """Output:\n--\n%s--""" % diags
-
- return lit.Test.FAIL, report
diff --git a/utils/lit/lit/TestRunner.py b/utils/lit/lit/TestRunner.py
index 989a992..9752417 100644
--- a/utils/lit/lit/TestRunner.py
+++ b/utils/lit/lit/TestRunner.py
@@ -3,14 +3,10 @@ import os, signal, subprocess, sys
import re
import platform
import tempfile
-try:
- from io import StringIO
-except ImportError:
- from StringIO import StringIO
import lit.ShUtil as ShUtil
import lit.Test as Test
-import lit.Util as Util
+import lit.util
class InternalShellError(Exception):
def __init__(self, command, message):
@@ -25,25 +21,6 @@ kUseCloseFDs = not kIsWindows
# Use temporary files to replace /dev/null on Windows.
kAvoidDevNull = kIsWindows
-def executeCommand(command, cwd=None, env=None):
- # Close extra file handles on UNIX (on Windows this cannot be done while
- # also redirecting input).
- close_fds = not kIsWindows
-
- p = subprocess.Popen(command, cwd=cwd,
- stdin=subprocess.PIPE,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
- env=env, close_fds=close_fds)
- out,err = p.communicate()
- exitCode = p.wait()
-
- # Detect Ctrl-C in subprocess.
- if exitCode == -signal.SIGINT:
- raise KeyboardInterrupt
-
- return out, err, exitCode
-
def executeShCmd(cmd, cfg, cwd, results):
if isinstance(cmd, ShUtil.Seq):
if cmd.op == ';':
@@ -154,8 +131,8 @@ def executeShCmd(cmd, cfg, cwd, results):
# Resolve the executable path ourselves.
args = list(j.args)
- args[0] = Util.which(args[0], cfg.environment['PATH'])
- if not args[0]:
+ executable = lit.util.which(args[0], cfg.environment['PATH'])
+ if not executable:
raise InternalShellError(j, '%r: command not found' % j.args[0])
# Replace uses of /dev/null with temporary files.
@@ -168,6 +145,7 @@ def executeShCmd(cmd, cfg, cwd, results):
args[i] = f.name
procs.append(subprocess.Popen(args, cwd=cwd,
+ executable = executable,
stdin = stdin,
stdout = stdout,
stderr = stderr,
@@ -221,10 +199,22 @@ def executeShCmd(cmd, cfg, cwd, results):
if res == -signal.SIGINT:
raise KeyboardInterrupt
+ # Ensure the resulting output is always of string type.
+ try:
+ out = str(out.decode('ascii'))
+ except:
+ out = str(out)
+ try:
+ err = str(err.decode('ascii'))
+ except:
+ err = str(err)
+
results.append((cmd.commands[i], out, err, res))
if cmd.pipe_err:
# Python treats the exit code as a signed char.
- if res < 0:
+ if exitCode is None:
+ exitCode = res
+ elif res < 0:
exitCode = min(exitCode, res)
else:
exitCode = max(exitCode, res)
@@ -250,7 +240,7 @@ def executeScriptInternal(test, litConfig, tmpBase, commands, cwd):
cmds.append(ShUtil.ShParser(ln, litConfig.isWindows,
test.config.pipefail).parse())
except:
- return (Test.FAIL, "shell parser error on: %r" % ln)
+ return lit.Test.Result(Test.FAIL, "shell parser error on: %r" % ln)
cmd = cmds[0]
for c in cmds[1:]:
@@ -306,24 +296,60 @@ def executeScript(test, litConfig, tmpBase, commands, cwd):
# run on clang with no real loss.
command = litConfig.valgrindArgs + command
- return executeCommand(command, cwd=cwd, env=test.config.environment)
+ return lit.util.executeCommand(command, cwd=cwd,
+ env=test.config.environment)
-def isExpectedFail(test, xfails):
- # Check if any of the xfails match an available feature or the target.
- for item in xfails:
- # If this is the wildcard, it always fails.
- if item == '*':
- return True
-
- # If this is an exact match for one of the features, it fails.
- if item in test.config.available_features:
- return True
+def parseIntegratedTestScriptCommands(source_path):
+ """
+ parseIntegratedTestScriptCommands(source_path) -> commands
- # If this is a part of the target triple, it fails.
- if item in test.suite.config.target_triple:
- return True
+ Parse the commands in an integrated test script file into a list of
+ (line_number, command_type, line).
+ """
- return False
+ # This code is carefully written to be dual compatible with Python 2.5+ and
+ # Python 3 without requiring input files to always have valid codings. The
+ # trick we use is to open the file in binary mode and use the regular
+ # expression library to find the commands, with it scanning strings in
+ # Python2 and bytes in Python3.
+ #
+ # Once we find a match, we do require each script line to be decodable to
+ # ascii, so we convert the outputs to ascii before returning. This way the
+ # remaining code can work with "strings" agnostic of the executing Python
+ # version.
+
+ def to_bytes(str):
+ # Encode to Latin1 to get binary data.
+ return str.encode('ISO-8859-1')
+ keywords = ('RUN:', 'XFAIL:', 'REQUIRES:', 'END.')
+ keywords_re = re.compile(
+ to_bytes("(%s)(.*)\n" % ("|".join(k for k in keywords),)))
+
+ f = open(source_path, 'rb')
+ try:
+ # Read the entire file contents.
+ data = f.read()
+
+ # Iterate over the matches.
+ line_number = 1
+ last_match_position = 0
+ for match in keywords_re.finditer(data):
+ # Compute the updated line number by counting the intervening
+ # newlines.
+ match_position = match.start()
+ line_number += data.count(to_bytes('\n'), last_match_position,
+ match_position)
+ last_match_position = match_position
+
+ # Convert the keyword and line to ascii strings and yield the
+ # command. Note that we take care to return regular strings in
+ # Python 2, to avoid other code having to differentiate between the
+ # str and unicode types.
+ keyword,ln = match.groups()
+ yield (line_number, str(keyword[:-1].decode('ascii')),
+ str(ln.decode('ascii')))
+ finally:
+ f.close()
def parseIntegratedTestScript(test, normalize_slashes=False,
extra_substitutions=[]):
@@ -342,8 +368,6 @@ def parseIntegratedTestScript(test, normalize_slashes=False,
execdir,execbase = os.path.split(execpath)
tmpDir = os.path.join(execdir, 'Output')
tmpBase = os.path.join(tmpDir, execbase)
- if test.index is not None:
- tmpBase += '_%d' % test.index
# Normalize slashes, if requested.
if normalize_slashes:
@@ -364,18 +388,21 @@ def parseIntegratedTestScript(test, normalize_slashes=False,
('%T', tmpDir),
('#_MARKER_#', '%')])
+ # "%/[STpst]" should be normalized.
+ substitutions.extend([
+ ('%/s', sourcepath.replace('\\', '/')),
+ ('%/S', sourcedir.replace('\\', '/')),
+ ('%/p', sourcedir.replace('\\', '/')),
+ ('%/t', tmpBase.replace('\\', '/') + '.tmp'),
+ ('%/T', tmpDir.replace('\\', '/')),
+ ])
+
# Collect the test lines from the script.
script = []
- xfails = []
requires = []
- line_number = 0
- for ln in open(sourcepath):
- line_number += 1
- if 'RUN:' in ln:
- # Isolate the command to run.
- index = ln.index('RUN:')
- ln = ln[index+4:]
-
+ for line_number, command_type, ln in \
+ parseIntegratedTestScriptCommands(sourcepath):
+ if command_type == 'RUN':
# Trim trailing whitespace.
ln = ln.rstrip()
@@ -393,16 +420,17 @@ def parseIntegratedTestScript(test, normalize_slashes=False,
script[-1] = script[-1][:-1] + ln
else:
script.append(ln)
- elif 'XFAIL:' in ln:
- items = ln[ln.index('XFAIL:') + 6:].split(',')
- xfails.extend([s.strip() for s in items])
- elif 'REQUIRES:' in ln:
- items = ln[ln.index('REQUIRES:') + 9:].split(',')
- requires.extend([s.strip() for s in items])
- elif 'END.' in ln:
- # Check for END. lines.
- if ln[ln.index('END.'):].strip() == 'END.':
+ elif command_type == 'XFAIL':
+ test.xfails.extend([s.strip() for s in ln.split(',')])
+ elif command_type == 'REQUIRES':
+ requires.extend([s.strip() for s in ln.split(',')])
+ elif command_type == 'END':
+ # END commands are only honored if the rest of the line is empty.
+ if not ln.strip():
break
+ else:
+ raise ValueError("unknown script command type: %r" % (
+ command_type,))
# Apply substitutions to the script. Allow full regular
# expression syntax. Replace each matching occurrence of regular
@@ -416,45 +444,27 @@ def parseIntegratedTestScript(test, normalize_slashes=False,
# Strip the trailing newline and any extra whitespace.
return ln.strip()
- script = map(processLine, script)
+ script = [processLine(ln)
+ for ln in script]
# Verify the script contains a run line.
if not script:
- return (Test.UNRESOLVED, "Test has no run line!")
+ return lit.Test.Result(Test.UNRESOLVED, "Test has no run line!")
# Check for unterminated run lines.
if script[-1][-1] == '\\':
- return (Test.UNRESOLVED, "Test has unterminated run lines (with '\\')")
+ return lit.Test.Result(Test.UNRESOLVED,
+ "Test has unterminated run lines (with '\\')")
# Check that we have the required features:
missing_required_features = [f for f in requires
if f not in test.config.available_features]
if missing_required_features:
msg = ', '.join(missing_required_features)
- return (Test.UNSUPPORTED,
- "Test requires the following features: %s" % msg)
-
- isXFail = isExpectedFail(test, xfails)
- return script,isXFail,tmpBase,execdir
-
-def formatTestOutput(status, out, err, exitCode, script):
- output = StringIO()
- output.write(u"Script:\n")
- output.write(u"--\n")
- output.write(u'\n'.join(script))
- output.write(u"\n--\n")
- output.write(u"Exit Code: %r\n\n" % exitCode)
- if out:
- output.write(u"Command Output (stdout):\n")
- output.write(u"--\n")
- output.write(unicode(out))
- output.write(u"--\n")
- if err:
- output.write(u"Command Output (stderr):\n")
- output.write(u"--\n")
- output.write(unicode(err))
- output.write(u"--\n")
- return (status, output.getvalue())
+ return lit.Test.Result(Test.UNSUPPORTED,
+ "Test requires the following features: %s" % msg)
+
+ return script,tmpBase,execdir
def executeShTest(test, litConfig, useExternalSh,
extra_substitutions=[]):
@@ -462,39 +472,37 @@ def executeShTest(test, litConfig, useExternalSh,
return (Test.UNSUPPORTED, 'Test is unsupported')
res = parseIntegratedTestScript(test, useExternalSh, extra_substitutions)
- if len(res) == 2:
+ if isinstance(res, lit.Test.Result):
return res
-
- script, isXFail, tmpBase, execdir = res
-
if litConfig.noExecute:
- return (Test.PASS, '')
+ return lit.Test.Result(Test.PASS)
+
+ script, tmpBase, execdir = res
# Create the output directory if it does not already exist.
- Util.mkdir_p(os.path.dirname(tmpBase))
+ lit.util.mkdir_p(os.path.dirname(tmpBase))
if useExternalSh:
res = executeScript(test, litConfig, tmpBase, script, execdir)
else:
res = executeScriptInternal(test, litConfig, tmpBase, script, execdir)
- if len(res) == 2:
+ if isinstance(res, lit.Test.Result):
return res
out,err,exitCode = res
- if isXFail:
- ok = exitCode != 0
- if ok:
- status = Test.XFAIL
- else:
- status = Test.XPASS
+ if exitCode == 0:
+ status = Test.PASS
else:
- ok = exitCode == 0
- if ok:
- status = Test.PASS
- else:
- status = Test.FAIL
+ status = Test.FAIL
- if ok:
- return (status,'')
+ # Form the output log.
+ output = """Script:\n--\n%s\n--\nExit Code: %d\n\n""" % (
+ '\n'.join(script), exitCode)
+
+ # Append the outputs, if present.
+ if out:
+ output += """Command Output (stdout):\n--\n%s\n--\n""" % (out,)
+ if err:
+ output += """Command Output (stderr):\n--\n%s\n--\n""" % (err,)
- return formatTestOutput(status, out, err, exitCode, script)
+ return lit.Test.Result(status, output)
diff --git a/utils/lit/lit/TestingConfig.py b/utils/lit/lit/TestingConfig.py
index f4ff89f..4a34b77 100644
--- a/utils/lit/lit/TestingConfig.py
+++ b/utils/lit/lit/TestingConfig.py
@@ -9,83 +9,106 @@ class TestingConfig:
"""
@staticmethod
- def frompath(path, parent, litConfig, mustExist, config = None):
- if config is None:
- # Set the environment based on the command line arguments.
- environment = {
- 'LIBRARY_PATH' : os.environ.get('LIBRARY_PATH',''),
- 'LD_LIBRARY_PATH' : os.environ.get('LD_LIBRARY_PATH',''),
- 'PATH' : os.pathsep.join(litConfig.path +
- [os.environ.get('PATH','')]),
- 'SYSTEMROOT' : os.environ.get('SYSTEMROOT',''),
- 'TERM' : os.environ.get('TERM',''),
- 'LLVM_DISABLE_CRASH_REPORT' : '1',
- }
-
- if sys.platform == 'win32':
- environment.update({
- 'INCLUDE' : os.environ.get('INCLUDE',''),
- 'PATHEXT' : os.environ.get('PATHEXT',''),
- 'PYTHONUNBUFFERED' : '1',
- 'TEMP' : os.environ.get('TEMP',''),
- 'TMP' : os.environ.get('TMP',''),
- })
-
- # Set the default available features based on the LitConfig.
- available_features = []
- if litConfig.useValgrind:
- available_features.append('valgrind')
- if litConfig.valgrindLeakCheck:
- available_features.append('vg_leak')
-
- config = TestingConfig(parent,
- name = '<unnamed>',
- suffixes = set(),
- test_format = None,
- environment = environment,
- substitutions = [],
- unsupported = False,
- on_clone = None,
- test_exec_root = None,
- test_source_root = None,
- excludes = [],
- available_features = available_features,
- pipefail = True)
-
- if os.path.exists(path):
- # FIXME: Improve detection and error reporting of errors in the
- # config file.
- f = open(path)
- cfg_globals = dict(globals())
- cfg_globals['config'] = config
- cfg_globals['lit'] = litConfig
- cfg_globals['__file__'] = path
- try:
- data = f.read()
- if PY2:
- exec("exec data in cfg_globals")
- else:
- exec(data, cfg_globals)
- if litConfig.debug:
- litConfig.note('... loaded config %r' % path)
- except SystemExit:
- e = sys.exc_info()[1]
- # We allow normal system exit inside a config file to just
- # return control without error.
- if e.args:
- raise
- f.close()
- else:
- if mustExist:
- litConfig.fatal('unable to load config from %r ' % path)
- elif litConfig.debug:
- litConfig.note('... config not found - %r' %path)
+ def fromdefaults(litConfig):
+ """
+ fromdefaults(litConfig) -> TestingConfig
+
+ Create a TestingConfig object with default values.
+ """
+ # Set the environment based on the command line arguments.
+ environment = {
+ 'LIBRARY_PATH' : os.environ.get('LIBRARY_PATH',''),
+ 'LD_LIBRARY_PATH' : os.environ.get('LD_LIBRARY_PATH',''),
+ 'PATH' : os.pathsep.join(litConfig.path +
+ [os.environ.get('PATH','')]),
+ 'SYSTEMROOT' : os.environ.get('SYSTEMROOT',''),
+ 'TERM' : os.environ.get('TERM',''),
+ 'LLVM_DISABLE_CRASH_REPORT' : '1',
+ }
+
+ if sys.platform == 'win32':
+ environment.update({
+ 'INCLUDE' : os.environ.get('INCLUDE',''),
+ 'PATHEXT' : os.environ.get('PATHEXT',''),
+ 'PYTHONUNBUFFERED' : '1',
+ 'TEMP' : os.environ.get('TEMP',''),
+ 'TMP' : os.environ.get('TMP',''),
+ })
+
+ # The option to preserve TEMP, TMP, and TMPDIR.
+ # This is intended to check how many temporary files would be generated
+ # (and be not cleaned up) in automated builders.
+ if os.environ.has_key('LIT_PRESERVES_TMP'):
+ environment.update({
+ 'TEMP' : os.environ.get('TEMP',''),
+ 'TMP' : os.environ.get('TMP',''),
+ 'TMPDIR' : os.environ.get('TMPDIR',''),
+ })
+
+ # Set the default available features based on the LitConfig.
+ available_features = []
+ if litConfig.useValgrind:
+ available_features.append('valgrind')
+ if litConfig.valgrindLeakCheck:
+ available_features.append('vg_leak')
+
+ return TestingConfig(None,
+ name = '<unnamed>',
+ suffixes = set(),
+ test_format = None,
+ environment = environment,
+ substitutions = [],
+ unsupported = False,
+ test_exec_root = None,
+ test_source_root = None,
+ excludes = [],
+ available_features = available_features,
+ pipefail = True)
- config.finish(litConfig)
- return config
+ def load_from_path(self, path, litConfig):
+ """
+ load_from_path(path, litConfig)
+
+ Load the configuration module at the provided path into the given config
+ object.
+ """
+
+ # Load the config script data.
+ f = open(path)
+ try:
+ data = f.read()
+ except:
+ litConfig.fatal('unable to load config file: %r' % (path,))
+ f.close()
+
+ # Execute the config script to initialize the object.
+ cfg_globals = dict(globals())
+ cfg_globals['config'] = self
+ cfg_globals['lit_config'] = litConfig
+ cfg_globals['__file__'] = path
+ try:
+ if PY2:
+ exec("exec data in cfg_globals")
+ else:
+ exec(data, cfg_globals)
+ if litConfig.debug:
+ litConfig.note('... loaded config %r' % path)
+ except SystemExit:
+ e = sys.exc_info()[1]
+ # We allow normal system exit inside a config file to just
+ # return control without error.
+ if e.args:
+ raise
+ except:
+ import traceback
+ litConfig.fatal(
+ 'unable to parse config file %r, traceback: %s' % (
+ path, traceback.format_exc()))
+
+ self.finish(litConfig)
def __init__(self, parent, name, suffixes, test_format,
- environment, substitutions, unsupported, on_clone,
+ environment, substitutions, unsupported,
test_exec_root, test_source_root, excludes,
available_features, pipefail):
self.parent = parent
@@ -95,27 +118,12 @@ class TestingConfig:
self.environment = dict(environment)
self.substitutions = list(substitutions)
self.unsupported = unsupported
- self.on_clone = on_clone
self.test_exec_root = test_exec_root
self.test_source_root = test_source_root
self.excludes = set(excludes)
self.available_features = set(available_features)
self.pipefail = pipefail
- def clone(self, path):
- # FIXME: Chain implementations?
- #
- # FIXME: Allow extra parameters?
- cfg = TestingConfig(self, self.name, self.suffixes, self.test_format,
- self.environment, self.substitutions,
- self.unsupported, self.on_clone,
- self.test_exec_root, self.test_source_root,
- self.excludes, self.available_features,
- self.pipefail)
- if cfg.on_clone:
- cfg.on_clone(self, cfg, path)
- return cfg
-
def finish(self, litConfig):
"""finish() - Finish this config object, after loading is complete."""
diff --git a/utils/lit/lit/__init__.py b/utils/lit/lit/__init__.py
index b9f573d..3967fdd 100644
--- a/utils/lit/lit/__init__.py
+++ b/utils/lit/lit/__init__.py
@@ -6,6 +6,6 @@ from .main import main
__author__ = 'Daniel Dunbar'
__email__ = 'daniel@zuster.org'
__versioninfo__ = (0, 3, 0)
-__version__ = '.'.join(map(str, __versioninfo__)) + 'dev'
+__version__ = '.'.join(str(v) for v in __versioninfo__) + 'dev'
__all__ = []
diff --git a/utils/lit/lit/discovery.py b/utils/lit/lit/discovery.py
index f76bd22..c3c0f28 100644
--- a/utils/lit/lit/discovery.py
+++ b/utils/lit/lit/discovery.py
@@ -2,9 +2,11 @@
Test discovery functions.
"""
+import copy
import os
import sys
+import lit.run
from lit.TestingConfig import TestingConfig
from lit import LitConfig, Test
@@ -38,11 +40,12 @@ def getTestSuite(item, litConfig, cache):
ts, relative = search(parent)
return (ts, relative + (base,))
- # We found a config file, load it.
+ # We found a test suite, create a new config for it and load it.
if litConfig.debug:
litConfig.note('loading suite config %r' % cfgpath)
- cfg = TestingConfig.frompath(cfgpath, None, litConfig, mustExist = True)
+ cfg = TestingConfig.fromdefaults(litConfig)
+ cfg.load_from_path(cfgpath, litConfig)
source_root = os.path.realpath(cfg.test_source_root or path)
exec_root = os.path.realpath(cfg.test_exec_root or path)
return Test.TestSuite(cfg.name, source_root, exec_root, cfg), ()
@@ -78,14 +81,21 @@ def getLocalConfig(ts, path_in_suite, litConfig, cache):
else:
parent = search(path_in_suite[:-1])
- # Load the local configuration.
+ # Check if there is a local configuration file.
source_path = ts.getSourcePath(path_in_suite)
cfgpath = os.path.join(source_path, litConfig.local_config_name)
+
+ # If not, just reuse the parent config.
+ if not os.path.exists(cfgpath):
+ return parent
+
+ # Otherwise, copy the current config and load the local configuration
+ # file into it.
+ config = copy.copy(parent)
if litConfig.debug:
litConfig.note('loading local config %r' % cfgpath)
- return TestingConfig.frompath(cfgpath, parent, litConfig,
- mustExist = False,
- config = parent.clone(cfgpath))
+ config.load_from_path(cfgpath, litConfig)
+ return config
def search(path_in_suite):
key = (ts, path_in_suite)
@@ -237,7 +247,9 @@ def load_test_suite(inputs):
isWindows = (platform.system()=='Windows'),
params = {})
- tests = find_tests_for_inputs(litConfig, inputs)
+ # Perform test discovery.
+ run = lit.run.Run(litConfig, find_tests_for_inputs(litConfig, inputs))
# Return a unittest test suite which just runs the tests in order.
- return unittest.TestSuite([LitTestCase(test, litConfig) for test in tests])
+ return unittest.TestSuite([LitTestCase(test, run)
+ for test in run.tests])
diff --git a/utils/lit/lit/formats/__init__.py b/utils/lit/lit/formats/__init__.py
new file mode 100644
index 0000000..6862708
--- /dev/null
+++ b/utils/lit/lit/formats/__init__.py
@@ -0,0 +1,4 @@
+from __future__ import absolute_import
+from lit.formats.base import TestFormat, FileBasedTest, OneCommandPerFileTest
+from lit.formats.googletest import GoogleTest
+from lit.formats.shtest import ShTest
diff --git a/utils/lit/lit/formats/base.py b/utils/lit/lit/formats/base.py
new file mode 100644
index 0000000..9e5420b
--- /dev/null
+++ b/utils/lit/lit/formats/base.py
@@ -0,0 +1,118 @@
+from __future__ import absolute_import
+import os
+import sys
+
+import lit.Test
+import lit.util
+
+class TestFormat(object):
+ pass
+
+###
+
+class FileBasedTest(TestFormat):
+ def getTestsInDirectory(self, testSuite, path_in_suite,
+ litConfig, localConfig):
+ source_path = testSuite.getSourcePath(path_in_suite)
+ for filename in os.listdir(source_path):
+ # Ignore dot files and excluded tests.
+ if (filename.startswith('.') or
+ filename in localConfig.excludes):
+ continue
+
+ filepath = os.path.join(source_path, filename)
+ if not os.path.isdir(filepath):
+ base,ext = os.path.splitext(filename)
+ if ext in localConfig.suffixes:
+ yield lit.Test.Test(testSuite, path_in_suite + (filename,),
+ localConfig)
+
+###
+
+import re
+import tempfile
+
+class OneCommandPerFileTest(TestFormat):
+ # FIXME: Refactor into generic test for running some command on a directory
+ # of inputs.
+
+ def __init__(self, command, dir, recursive=False,
+ pattern=".*", useTempInput=False):
+ if isinstance(command, str):
+ self.command = [command]
+ else:
+ self.command = list(command)
+ if dir is not None:
+ dir = str(dir)
+ self.dir = dir
+ self.recursive = bool(recursive)
+ self.pattern = re.compile(pattern)
+ self.useTempInput = useTempInput
+
+ def getTestsInDirectory(self, testSuite, path_in_suite,
+ litConfig, localConfig):
+ dir = self.dir
+ if dir is None:
+ dir = testSuite.getSourcePath(path_in_suite)
+
+ for dirname,subdirs,filenames in os.walk(dir):
+ if not self.recursive:
+ subdirs[:] = []
+
+ subdirs[:] = [d for d in subdirs
+ if (d != '.svn' and
+ d not in localConfig.excludes)]
+
+ for filename in filenames:
+ if (filename.startswith('.') or
+ not self.pattern.match(filename) or
+ filename in localConfig.excludes):
+ continue
+
+ path = os.path.join(dirname,filename)
+ suffix = path[len(dir):]
+ if suffix.startswith(os.sep):
+ suffix = suffix[1:]
+ test = lit.Test.Test(
+ testSuite, path_in_suite + tuple(suffix.split(os.sep)),
+ localConfig)
+ # FIXME: Hack?
+ test.source_path = path
+ yield test
+
+ def createTempInput(self, tmp, test):
+ abstract
+
+ def execute(self, test, litConfig):
+ if test.config.unsupported:
+ return (lit.Test.UNSUPPORTED, 'Test is unsupported')
+
+ cmd = list(self.command)
+
+ # If using temp input, create a temporary file and hand it to the
+ # subclass.
+ if self.useTempInput:
+ tmp = tempfile.NamedTemporaryFile(suffix='.cpp')
+ self.createTempInput(tmp, test)
+ tmp.flush()
+ cmd.append(tmp.name)
+ elif hasattr(test, 'source_path'):
+ cmd.append(test.source_path)
+ else:
+ cmd.append(test.getSourcePath())
+
+ out, err, exitCode = lit.util.executeCommand(cmd)
+
+ diags = out + err
+ if not exitCode and not diags.strip():
+ return lit.Test.PASS,''
+
+ # Try to include some useful information.
+ report = """Command: %s\n""" % ' '.join(["'%s'" % a
+ for a in cmd])
+ if self.useTempInput:
+ report += """Temporary File: %s\n""" % tmp.name
+ report += "--\n%s--\n""" % open(tmp.name).read()
+ report += """Output:\n--\n%s--""" % diags
+
+ return lit.Test.FAIL, report
diff --git a/utils/lit/lit/formats/googletest.py b/utils/lit/lit/formats/googletest.py
new file mode 100644
index 0000000..b77e184
--- /dev/null
+++ b/utils/lit/lit/formats/googletest.py
@@ -0,0 +1,114 @@
+from __future__ import absolute_import
+import os
+import sys
+
+import lit.Test
+import lit.TestRunner
+import lit.util
+from .base import TestFormat
+
+kIsWindows = sys.platform in ['win32', 'cygwin']
+
+class GoogleTest(TestFormat):
+ def __init__(self, test_sub_dir, test_suffix):
+ self.test_sub_dir = os.path.normcase(str(test_sub_dir)).split(';')
+ self.test_suffix = str(test_suffix)
+
+ # On Windows, assume tests will also end in '.exe'.
+ if kIsWindows:
+ self.test_suffix += '.exe'
+
+ def getGTestTests(self, path, litConfig, localConfig):
+ """getGTestTests(path) - [name]
+
+ Return the tests available in gtest executable.
+
+ Args:
+ path: String path to a gtest executable
+ litConfig: LitConfig instance
+ localConfig: TestingConfig instance"""
+
+ try:
+ lines = lit.util.capture([path, '--gtest_list_tests'],
+ env=localConfig.environment)
+ lines = lines.decode('ascii')
+ if kIsWindows:
+ lines = lines.replace('\r', '')
+ lines = lines.split('\n')
+ except:
+ litConfig.error("unable to discover google-tests in %r" % path)
+ raise StopIteration
+
+ nested_tests = []
+ for ln in lines:
+ if not ln.strip():
+ continue
+
+ prefix = ''
+ index = 0
+ while ln[index*2:index*2+2] == ' ':
+ index += 1
+ while len(nested_tests) > index:
+ nested_tests.pop()
+
+ ln = ln[index*2:]
+ if ln.endswith('.'):
+ nested_tests.append(ln)
+ else:
+ yield ''.join(nested_tests) + ln
+
+ # Note: path_in_suite should not include the executable name.
+ def getTestsInExecutable(self, testSuite, path_in_suite, execpath,
+ litConfig, localConfig):
+ if not execpath.endswith(self.test_suffix):
+ return
+ (dirname, basename) = os.path.split(execpath)
+ # Discover the tests in this executable.
+ for testname in self.getGTestTests(execpath, litConfig, localConfig):
+ testPath = path_in_suite + (basename, testname)
+ yield lit.Test.Test(testSuite, testPath, localConfig)
+
+ def getTestsInDirectory(self, testSuite, path_in_suite,
+ litConfig, localConfig):
+ source_path = testSuite.getSourcePath(path_in_suite)
+ for filename in os.listdir(source_path):
+ filepath = os.path.join(source_path, filename)
+ if os.path.isdir(filepath):
+ # Iterate over executables in a directory.
+ if not os.path.normcase(filename) in self.test_sub_dir:
+ continue
+ dirpath_in_suite = path_in_suite + (filename, )
+ for subfilename in os.listdir(filepath):
+ execpath = os.path.join(filepath, subfilename)
+ for test in self.getTestsInExecutable(
+ testSuite, dirpath_in_suite, execpath,
+ litConfig, localConfig):
+ yield test
+ elif ('.' in self.test_sub_dir):
+ for test in self.getTestsInExecutable(
+ testSuite, path_in_suite, filepath,
+ litConfig, localConfig):
+ yield test
+
+ def execute(self, test, litConfig):
+ testPath,testName = os.path.split(test.getSourcePath())
+ while not os.path.exists(testPath):
+ # Handle GTest parametrized and typed tests, whose name includes
+ # some '/'s.
+ testPath, namePrefix = os.path.split(testPath)
+ testName = os.path.join(namePrefix, testName)
+
+ cmd = [testPath, '--gtest_filter=' + testName]
+ if litConfig.useValgrind:
+ cmd = litConfig.valgrindArgs + cmd
+
+ if litConfig.noExecute:
+ return lit.Test.PASS, ''
+
+ out, err, exitCode = lit.util.executeCommand(
+ cmd, env=test.config.environment)
+
+ if not exitCode:
+ return lit.Test.PASS,''
+
+ return lit.Test.FAIL, out + err
diff --git a/utils/lit/lit/formats/shtest.py b/utils/lit/lit/formats/shtest.py
new file mode 100644
index 0000000..30a6a33
--- /dev/null
+++ b/utils/lit/lit/formats/shtest.py
@@ -0,0 +1,12 @@
+from __future__ import absolute_import
+
+import lit.TestRunner
+from .base import FileBasedTest
+
+class ShTest(FileBasedTest):
+ def __init__(self, execute_external = False):
+ self.execute_external = execute_external
+
+ def execute(self, test, litConfig):
+ return lit.TestRunner.executeShTest(test, litConfig,
+ self.execute_external)
diff --git a/utils/lit/lit/main.py b/utils/lit/lit/main.py
index acf6101..6f672a0 100755
--- a/utils/lit/lit/main.py
+++ b/utils/lit/lit/main.py
@@ -7,37 +7,23 @@ See lit.pod for more information.
"""
from __future__ import absolute_import
-import math, os, platform, random, re, sys, time, threading, traceback
+import math, os, platform, random, re, sys, time
import lit.ProgressBar
import lit.LitConfig
import lit.Test
-import lit.Util
-
+import lit.run
+import lit.util
import lit.discovery
-class TestingProgressDisplay:
+class TestingProgressDisplay(object):
def __init__(self, opts, numTests, progressBar=None):
self.opts = opts
self.numTests = numTests
self.current = None
- self.lock = threading.Lock()
self.progressBar = progressBar
self.completed = 0
- def update(self, test):
- # Avoid locking overhead in quiet mode
- if self.opts.quiet and not test.result.isFailure:
- self.completed += 1
- return
-
- # Output lock.
- self.lock.acquire()
- try:
- self.handleUpdate(test)
- finally:
- self.lock.release()
-
def finish(self):
if self.progressBar:
self.progressBar.clear()
@@ -46,123 +32,86 @@ class TestingProgressDisplay:
elif self.opts.succinct:
sys.stdout.write('\n')
- def handleUpdate(self, test):
+ def update(self, test):
self.completed += 1
if self.progressBar:
self.progressBar.update(float(self.completed)/self.numTests,
test.getFullName())
- if self.opts.succinct and not test.result.isFailure:
+ if not test.result.code.isFailure and \
+ (self.opts.quiet or self.opts.succinct):
return
if self.progressBar:
self.progressBar.clear()
- print('%s: %s (%d of %d)' % (test.result.name, test.getFullName(),
+ # Show the test result line.
+ test_name = test.getFullName()
+ print('%s: %s (%d of %d)' % (test.result.code.name, test_name,
self.completed, self.numTests))
- if test.result.isFailure and self.opts.showOutput:
+ # Show the test failure output, if requested.
+ if test.result.code.isFailure and self.opts.showOutput:
print("%s TEST '%s' FAILED %s" % ('*'*20, test.getFullName(),
'*'*20))
- print(test.output)
+ print(test.result.output)
print("*" * 20)
+ # Report test metrics, if present.
+ if test.result.metrics:
+ print("%s TEST '%s' RESULTS %s" % ('*'*10, test.getFullName(),
+ '*'*10))
+ items = sorted(test.result.metrics.items())
+ for metric_name, value in items:
+ print('%s: %s ' % (metric_name, value.format()))
+ print("*" * 10)
+
+ # Ensure the output is flushed.
sys.stdout.flush()
-class TestProvider:
- def __init__(self, tests, maxTime):
- self.maxTime = maxTime
- self.iter = iter(tests)
- self.lock = threading.Lock()
- self.startTime = time.time()
- self.canceled = False
-
- def cancel(self):
- self.lock.acquire()
- self.canceled = True
- self.lock.release()
-
- def get(self):
- # Check if we have run out of time.
- if self.maxTime is not None:
- if time.time() - self.startTime > self.maxTime:
- return None
-
- # Otherwise take the next test.
- self.lock.acquire()
- if self.canceled:
- self.lock.release()
- return None
- for item in self.iter:
- break
- else:
- item = None
- self.lock.release()
- return item
-
-class Tester(threading.Thread):
- def __init__(self, litConfig, provider, display):
- threading.Thread.__init__(self)
- self.litConfig = litConfig
- self.provider = provider
- self.display = display
-
- def run(self):
- while 1:
- item = self.provider.get()
- if item is None:
- break
- self.runTest(item)
-
- def runTest(self, test):
- result = None
- startTime = time.time()
- try:
- result, output = test.config.test_format.execute(test,
- self.litConfig)
- except KeyboardInterrupt:
- # This is a sad hack. Unfortunately subprocess goes
- # bonkers with ctrl-c and we start forking merrily.
- print('\nCtrl-C detected, goodbye.')
- os.kill(0,9)
- except:
- if self.litConfig.debug:
- raise
- result = lit.Test.UNRESOLVED
- output = 'Exception during script execution:\n'
- output += traceback.format_exc()
- output += '\n'
- elapsed = time.time() - startTime
-
- test.setResult(result, output, elapsed)
- self.display.update(test)
-
-def runTests(numThreads, litConfig, provider, display):
- # If only using one testing thread, don't use threads at all; this lets us
- # profile, among other things.
- if numThreads == 1:
- t = Tester(litConfig, provider, display)
- t.run()
- return
-
- # Otherwise spin up the testing threads and wait for them to finish.
- testers = [Tester(litConfig, provider, display)
- for i in range(numThreads)]
- for t in testers:
- t.start()
+def write_test_results(run, lit_config, testing_time, output_path):
try:
- for t in testers:
- t.join()
- except KeyboardInterrupt:
- sys.exit(2)
+ import json
+ except ImportError:
+ lit_config.fatal('test output unsupported with Python 2.5')
+
+ # Construct the data we will write.
+ data = {}
+ # Encode the current lit version as a schema version.
+ data['__version__'] = lit.__versioninfo__
+ data['elapsed'] = testing_time
+ # FIXME: Record some information on the lit configuration used?
+ # FIXME: Record information from the individual test suites?
+
+ # Encode the tests.
+ data['tests'] = tests_data = []
+ for test in run.tests:
+ test_data = {
+ 'name' : test.getFullName(),
+ 'code' : test.result.code.name,
+ 'output' : test.result.output,
+ 'elapsed' : test.result.elapsed }
+
+ # Add test metrics, if present.
+ if test.result.metrics:
+ test_data['metrics'] = metrics_data = {}
+ for key, value in test.result.metrics.items():
+ metrics_data[key] = value.todata()
+
+ tests_data.append(test_data)
+
+ # Write the output.
+ f = open(output_path, 'w')
+ try:
+ json.dump(data, f, indent=2, sort_keys=True)
+ f.write('\n')
+ finally:
+ f.close()
def main(builtinParameters = {}):
- # Bump the GIL check interval, its more important to get any one thread to a
- # blocking operation (hopefully exec) than to try and unblock other threads.
- #
- # FIXME: This is a hack.
- import sys
- sys.setcheckinterval(1000)
+ # Use processes by default on Unix platforms.
+ isWindows = platform.system() == 'Windows'
+ useProcessesIsDefault = not isWindows
global options
from optparse import OptionParser, OptionGroup
@@ -191,6 +140,9 @@ def main(builtinParameters = {}):
group.add_option("-v", "--verbose", dest="showOutput",
help="Show all test output",
action="store_true", default=False)
+ group.add_option("-o", "--output", dest="output_path",
+ help="Write test results to the provided path",
+ action="store", type=str, metavar="PATH")
group.add_option("", "--no-progress-bar", dest="useProgressBar",
help="Do not use curses based progress bar",
action="store_false", default=True)
@@ -243,9 +195,12 @@ def main(builtinParameters = {}):
group.add_option("", "--show-tests", dest="showTests",
help="Show all discovered tests",
action="store_true", default=False)
- group.add_option("", "--repeat", dest="repeatTests", metavar="N",
- help="Repeat tests N times (for timing)",
- action="store", default=None, type=int)
+ group.add_option("", "--use-processes", dest="useProcesses",
+ help="Run tests in parallel with processes (not threads)",
+ action="store_true", default=useProcessesIsDefault)
+ group.add_option("", "--use-threads", dest="useProcesses",
+ help="Run tests in parallel with threads (not processes)",
+ action="store_false", default=useProcessesIsDefault)
parser.add_option_group(group)
(opts, args) = parser.parse_args()
@@ -259,7 +214,7 @@ def main(builtinParameters = {}):
# I haven't seen this bug occur with 2.5.2 and later, so only enable multiple
# threads by default there.
if sys.hexversion >= 0x2050200:
- opts.numThreads = lit.Util.detectCPUs()
+ opts.numThreads = lit.util.detectCPUs()
else:
opts.numThreads = 1
@@ -284,20 +239,22 @@ def main(builtinParameters = {}):
valgrindArgs = opts.valgrindArgs,
noExecute = opts.noExecute,
debug = opts.debug,
- isWindows = (platform.system()=='Windows'),
+ isWindows = isWindows,
params = userParams,
config_prefix = opts.configPrefix)
- tests = lit.discovery.find_tests_for_inputs(litConfig, inputs)
+ # Perform test discovery.
+ run = lit.run.Run(litConfig,
+ lit.discovery.find_tests_for_inputs(litConfig, inputs))
if opts.showSuites or opts.showTests:
# Aggregate the tests by suite.
suitesAndTests = {}
- for t in tests:
+ for t in run.tests:
if t.suite not in suitesAndTests:
suitesAndTests[t.suite] = []
suitesAndTests[t.suite].append(t)
- suitesAndTests = suitesAndTests.items()
+ suitesAndTests = list(suitesAndTests.items())
suitesAndTests.sort(key = lambda item: item[0].name)
# Show the suites, if requested.
@@ -315,9 +272,12 @@ def main(builtinParameters = {}):
ts_tests.sort(key = lambda test: test.path_in_suite)
for test in ts_tests:
print(' %s' % (test.getFullName(),))
-
+
+ # Exit.
+ sys.exit(0)
+
# Select and order the tests.
- numTotalTests = len(tests)
+ numTotalTests = len(run.tests)
# First, select based on the filter expression if given.
if opts.filter:
@@ -326,33 +286,28 @@ def main(builtinParameters = {}):
except:
parser.error("invalid regular expression for --filter: %r" % (
opts.filter))
- tests = [t for t in tests
- if rex.search(t.getFullName())]
+ run.tests = [t for t in run.tests
+ if rex.search(t.getFullName())]
# Then select the order.
if opts.shuffle:
- random.shuffle(tests)
+ random.shuffle(run.tests)
else:
- tests.sort(key = lambda t: t.getFullName())
+ run.tests.sort(key = lambda t: t.getFullName())
# Finally limit the number of tests, if desired.
if opts.maxTests is not None:
- tests = tests[:opts.maxTests]
+ run.tests = run.tests[:opts.maxTests]
# Don't create more threads than tests.
- opts.numThreads = min(len(tests), opts.numThreads)
+ opts.numThreads = min(len(run.tests), opts.numThreads)
extra = ''
- if len(tests) != numTotalTests:
+ if len(run.tests) != numTotalTests:
extra = ' of %d' % numTotalTests
- header = '-- Testing: %d%s tests, %d threads --'%(len(tests),extra,
+ header = '-- Testing: %d%s tests, %d threads --'%(len(run.tests), extra,
opts.numThreads)
- if opts.repeatTests:
- tests = [t.copyWithIndex(i)
- for t in tests
- for i in range(opts.repeatTests)]
-
progressBar = None
if not opts.quiet:
if opts.succinct and opts.useProgressBar:
@@ -366,63 +321,50 @@ def main(builtinParameters = {}):
print(header)
startTime = time.time()
- display = TestingProgressDisplay(opts, len(tests), progressBar)
- provider = TestProvider(tests, opts.maxTime)
-
+ display = TestingProgressDisplay(opts, len(run.tests), progressBar)
try:
- import win32api
- except ImportError:
- pass
- else:
- def console_ctrl_handler(type):
- provider.cancel()
- return True
- win32api.SetConsoleCtrlHandler(console_ctrl_handler, True)
-
- runTests(opts.numThreads, litConfig, provider, display)
+ run.execute_tests(display, opts.numThreads, opts.maxTime,
+ opts.useProcesses)
+ except KeyboardInterrupt:
+ sys.exit(2)
display.finish()
+ testing_time = time.time() - startTime
if not opts.quiet:
- print('Testing Time: %.2fs'%(time.time() - startTime))
+ print('Testing Time: %.2fs' % (testing_time,))
- # Update results for any tests which weren't run.
- for t in tests:
- if t.result is None:
- t.setResult(lit.Test.UNRESOLVED, '', 0.0)
+ # Write out the test data, if requested.
+ if opts.output_path is not None:
+ write_test_results(run, litConfig, testing_time, opts.output_path)
# List test results organized by kind.
hasFailures = False
byCode = {}
- for t in tests:
- if t.result not in byCode:
- byCode[t.result] = []
- byCode[t.result].append(t)
- if t.result.isFailure:
+ for test in run.tests:
+ if test.result.code not in byCode:
+ byCode[test.result.code] = []
+ byCode[test.result.code].append(test)
+ if test.result.code.isFailure:
hasFailures = True
- # FIXME: Show unresolved and (optionally) unsupported tests.
+ # Print each test in any of the failing groups.
for title,code in (('Unexpected Passing Tests', lit.Test.XPASS),
- ('Failing Tests', lit.Test.FAIL)):
+ ('Failing Tests', lit.Test.FAIL),
+ ('Unresolved Tests', lit.Test.UNRESOLVED)):
elts = byCode.get(code)
if not elts:
continue
print('*'*20)
print('%s (%d):' % (title, len(elts)))
- for t in elts:
- print(' %s' % t.getFullName())
+ for test in elts:
+ print(' %s' % test.getFullName())
sys.stdout.write('\n')
- if opts.timeTests:
- # Collate, in case we repeated tests.
- times = {}
- for t in tests:
- key = t.getFullName()
- times[key] = times.get(key, 0.) + t.elapsed
-
- byTime = list(times.items())
- byTime.sort(key = lambda item: item[1])
- if byTime:
- lit.Util.printHistogram(byTime, title='Tests')
+ if opts.timeTests and run.tests:
+ # Order by time.
+ test_times = [(test.getFullName(), test.result.elapsed)
+ for test in run.tests]
+ lit.util.printHistogram(test_times, title='Tests')
for name,code in (('Expected Passes ', lit.Test.PASS),
('Expected Failures ', lit.Test.XFAIL),
diff --git a/utils/lit/lit/run.py b/utils/lit/lit/run.py
new file mode 100644
index 0000000..27c414d
--- /dev/null
+++ b/utils/lit/lit/run.py
@@ -0,0 +1,277 @@
+import os
+import threading
+import time
+import traceback
+try:
+ import Queue as queue
+except ImportError:
+ import queue
+
+try:
+ import win32api
+except ImportError:
+ win32api = None
+
+try:
+ import multiprocessing
+except ImportError:
+ multiprocessing = None
+
+import lit.Test
+
+###
+# Test Execution Implementation
+
+class LockedValue(object):
+ def __init__(self, value):
+ self.lock = threading.Lock()
+ self._value = value
+
+ def _get_value(self):
+ self.lock.acquire()
+ try:
+ return self._value
+ finally:
+ self.lock.release()
+
+ def _set_value(self, value):
+ self.lock.acquire()
+ try:
+ self._value = value
+ finally:
+ self.lock.release()
+
+ value = property(_get_value, _set_value)
+
+class TestProvider(object):
+ def __init__(self, tests, num_jobs, queue_impl, canceled_flag):
+ self.canceled_flag = canceled_flag
+
+ # Create a shared queue to provide the test indices.
+ self.queue = queue_impl()
+ for i in range(len(tests)):
+ self.queue.put(i)
+ for i in range(num_jobs):
+ self.queue.put(None)
+
+ def cancel(self):
+ self.canceled_flag.value = 1
+
+ def get(self):
+ # Check if we are canceled.
+ if self.canceled_flag.value:
+ return None
+
+ # Otherwise take the next test.
+ return self.queue.get()
+
+class Tester(object):
+ def __init__(self, run_instance, provider, consumer):
+ self.run_instance = run_instance
+ self.provider = provider
+ self.consumer = consumer
+
+ def run(self):
+ while True:
+ item = self.provider.get()
+ if item is None:
+ break
+ self.run_test(item)
+ self.consumer.task_finished()
+
+ def run_test(self, test_index):
+ test = self.run_instance.tests[test_index]
+ try:
+ self.run_instance.execute_test(test)
+ except KeyboardInterrupt:
+ # This is a sad hack. Unfortunately subprocess goes
+ # bonkers with ctrl-c and we start forking merrily.
+ print('\nCtrl-C detected, goodbye.')
+ os.kill(0,9)
+ self.consumer.update(test_index, test)
+
+class ThreadResultsConsumer(object):
+ def __init__(self, display):
+ self.display = display
+ self.lock = threading.Lock()
+
+ def update(self, test_index, test):
+ self.lock.acquire()
+ try:
+ self.display.update(test)
+ finally:
+ self.lock.release()
+
+ def task_finished(self):
+ pass
+
+ def handle_results(self):
+ pass
+
+class MultiprocessResultsConsumer(object):
+ def __init__(self, run, display, num_jobs):
+ self.run = run
+ self.display = display
+ self.num_jobs = num_jobs
+ self.queue = multiprocessing.Queue()
+
+ def update(self, test_index, test):
+ # This method is called in the child processes, and communicates the
+ # results to the actual display implementation via an output queue.
+ self.queue.put((test_index, test.result))
+
+ def task_finished(self):
+ # This method is called in the child processes, and communicates that
+ # individual tasks are complete.
+ self.queue.put(None)
+
+ def handle_results(self):
+ # This method is called in the parent, and consumes the results from the
+ # output queue and dispatches to the actual display. The method will
+ # complete after each of num_jobs tasks has signalled completion.
+ completed = 0
+ while completed != self.num_jobs:
+ # Wait for a result item.
+ item = self.queue.get()
+ if item is None:
+ completed += 1
+ continue
+
+ # Update the test result in the parent process.
+ index,result = item
+ test = self.run.tests[index]
+ test.result = result
+
+ self.display.update(test)
+
+def run_one_tester(run, provider, display):
+ tester = Tester(run, provider, display)
+ tester.run()
+
+###
+
+class Run(object):
+ """
+ This class represents a concrete, configured testing run.
+ """
+
+ def __init__(self, lit_config, tests):
+ self.lit_config = lit_config
+ self.tests = tests
+
+ def execute_test(self, test):
+ result = None
+ start_time = time.time()
+ try:
+ result = test.config.test_format.execute(test, self.lit_config)
+
+ # Support deprecated result from execute() which returned the result
+ # code and additional output as a tuple.
+ if isinstance(result, tuple):
+ code, output = result
+ result = lit.Test.Result(code, output)
+ elif not isinstance(result, lit.Test.Result):
+ raise ValueError("unexpected result from test execution")
+ except KeyboardInterrupt:
+ raise
+ except:
+ if self.lit_config.debug:
+ raise
+ output = 'Exception during script execution:\n'
+ output += traceback.format_exc()
+ output += '\n'
+ result = lit.Test.Result(lit.Test.UNRESOLVED, output)
+ result.elapsed = time.time() - start_time
+
+ test.setResult(result)
+
+ def execute_tests(self, display, jobs, max_time=None,
+ use_processes=False):
+ """
+ execute_tests(display, jobs, [max_time])
+
+ Execute each of the tests in the run, using up to jobs number of
+ parallel tasks, and inform the display of each individual result. The
+ provided tests should be a subset of the tests available in this run
+ object.
+
+ If max_time is non-None, it should be a time in seconds after which to
+ stop executing tests.
+
+ The display object will have its update method called with each test as
+ it is completed. The calls are guaranteed to be locked with respect to
+ one another, but are *not* guaranteed to be called on the same thread as
+ this method was invoked on.
+
+ Upon completion, each test in the run will have its result
+ computed. Tests which were not actually executed (for any reason) will
+ be given an UNRESOLVED result.
+ """
+
+ # Choose the appropriate parallel execution implementation.
+ consumer = None
+ if jobs != 1 and use_processes and multiprocessing:
+ try:
+ task_impl = multiprocessing.Process
+ queue_impl = multiprocessing.Queue
+ canceled_flag = multiprocessing.Value('i', 0)
+ consumer = MultiprocessResultsConsumer(self, display, jobs)
+ except:
+ # multiprocessing fails to initialize with certain OpenBSD and
+ # FreeBSD Python versions: http://bugs.python.org/issue3770
+ # Unfortunately the error raised also varies by platform.
+ self.lit_config.note('failed to initialize multiprocessing')
+ consumer = None
+ if not consumer:
+ task_impl = threading.Thread
+ queue_impl = queue.Queue
+ canceled_flag = LockedValue(0)
+ consumer = ThreadResultsConsumer(display)
+
+ # Create the test provider.
+ provider = TestProvider(self.tests, jobs, queue_impl, canceled_flag)
+
+ # Install a console-control signal handler on Windows.
+ if win32api is not None:
+ def console_ctrl_handler(type):
+ provider.cancel()
+ return True
+ win32api.SetConsoleCtrlHandler(console_ctrl_handler, True)
+
+ # Install a timeout handler, if requested.
+ if max_time is not None:
+ def timeout_handler():
+ provider.cancel()
+ timeout_timer = threading.Timer(max_time, timeout_handler)
+ timeout_timer.start()
+
+ # If not using multiple tasks, just run the tests directly.
+ if jobs == 1:
+ run_one_tester(self, provider, consumer)
+ else:
+ # Otherwise, execute the tests in parallel
+ self._execute_tests_in_parallel(task_impl, provider, consumer, jobs)
+
+ # Cancel the timeout handler.
+ if max_time is not None:
+ timeout_timer.cancel()
+
+ # Update results for any tests which weren't run.
+ for test in self.tests:
+ if test.result is None:
+ test.setResult(lit.Test.Result(lit.Test.UNRESOLVED, '', 0.0))
+
+ def _execute_tests_in_parallel(self, task_impl, provider, consumer, jobs):
+ # Start all of the tasks.
+ tasks = [task_impl(target=run_one_tester,
+ args=(self, provider, consumer))
+ for i in range(jobs)]
+ for t in tasks:
+ t.start()
+
+ # Allow the consumer to handle results, if necessary.
+ consumer.handle_results()
+
+ # Wait for all the tasks to complete.
+ for t in tasks:
+ t.join()
diff --git a/utils/lit/lit/Util.py b/utils/lit/lit/util.py
index 6f09eed..2b1010c 100644
--- a/utils/lit/lit/Util.py
+++ b/utils/lit/lit/util.py
@@ -1,4 +1,11 @@
-import os, sys
+import errno
+import itertools
+import math
+import os
+import platform
+import signal
+import subprocess
+import sys
def detectCPUs():
"""
@@ -6,7 +13,7 @@ def detectCPUs():
"""
# Linux, Unix and MacOS:
if hasattr(os, "sysconf"):
- if os.sysconf_names.has_key("SC_NPROCESSORS_ONLN"):
+ if "SC_NPROCESSORS_ONLN" in os.sysconf_names:
# Linux & Unix:
ncpus = os.sysconf("SC_NPROCESSORS_ONLN")
if isinstance(ncpus, int) and ncpus > 0:
@@ -14,7 +21,7 @@ def detectCPUs():
else: # OSX:
return int(capture(['sysctl', '-n', 'hw.ncpu']))
# Windows:
- if os.environ.has_key("NUMBER_OF_PROCESSORS"):
+ if "NUMBER_OF_PROCESSORS" in os.environ:
ncpus = int(os.environ["NUMBER_OF_PROCESSORS"])
if ncpus > 0:
return ncpus
@@ -23,8 +30,6 @@ def detectCPUs():
def mkdir_p(path):
"""mkdir_p(path) - Make the "path" directory, if it does not exist; this
will also make directories for any missing parent directories."""
- import errno
-
if not path or os.path.exists(path):
return
@@ -41,7 +46,6 @@ def mkdir_p(path):
raise
def capture(args, env=None):
- import subprocess
"""capture(command) - Run the given command (or argv list) in a shell and
return the standard output."""
p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
@@ -93,8 +97,6 @@ def whichTools(tools, paths):
return None
def printHistogram(items, title = 'Items'):
- import itertools, math
-
items.sort(key = lambda item: item[1])
maxValue = max([v for _,v in items])
@@ -138,3 +140,30 @@ def printHistogram(items, title = 'Items'):
pDigits, pfDigits, i*barH, pDigits, pfDigits, (i+1)*barH,
'*'*w, ' '*(barW-w), cDigits, len(row), cDigits, len(items)))
+# Close extra file handles on UNIX (on Windows this cannot be done while
+# also redirecting input).
+kUseCloseFDs = not (platform.system() == 'Windows')
+def executeCommand(command, cwd=None, env=None):
+ p = subprocess.Popen(command, cwd=cwd,
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ env=env, close_fds=kUseCloseFDs)
+ out,err = p.communicate()
+ exitCode = p.wait()
+
+ # Detect Ctrl-C in subprocess.
+ if exitCode == -signal.SIGINT:
+ raise KeyboardInterrupt
+
+ # Ensure the resulting output is always of string type.
+ try:
+ out = str(out.decode('ascii'))
+ except:
+ out = str(out)
+ try:
+ err = str(err.decode('ascii'))
+ except:
+ err = str(err)
+
+ return out, err, exitCode
diff --git a/utils/lit/setup.py b/utils/lit/setup.py
index a94e6ea..10de6bb 100644
--- a/utils/lit/setup.py
+++ b/utils/lit/setup.py
@@ -1,7 +1,14 @@
import lit
+import os
-# FIXME: Support distutils?
from setuptools import setup, find_packages
+
+# setuptools expects to be invoked from within the directory of setup.py, but it
+# is nice to allow:
+# python path/to/setup.py install
+# to work (for scripts, etc.)
+os.chdir(os.path.dirname(os.path.abspath(__file__)))
+
setup(
name = "lit",
version = lit.__version__,
diff --git a/utils/lit/tests/Inputs/discovery/lit.cfg b/utils/lit/tests/Inputs/discovery/lit.cfg
index 4049ab1..c48ca0b 100644
--- a/utils/lit/tests/Inputs/discovery/lit.cfg
+++ b/utils/lit/tests/Inputs/discovery/lit.cfg
@@ -1,3 +1,4 @@
+import lit.formats
config.name = 'top-level-suite'
config.suffixes = ['.txt']
config.test_format = lit.formats.ShTest()
@@ -8,3 +9,6 @@ config.test_format = lit.formats.ShTest()
#
#config.test_source_root = None
#config.test_exec_root = None
+
+# Check that arbitrary config values are copied (tested by subdir/lit.local.cfg).
+config.an_extra_variable = False
diff --git a/utils/lit/tests/Inputs/discovery/subdir/lit.local.cfg b/utils/lit/tests/Inputs/discovery/subdir/lit.local.cfg
index 5ae6b3c..631cb60 100644
--- a/utils/lit/tests/Inputs/discovery/subdir/lit.local.cfg
+++ b/utils/lit/tests/Inputs/discovery/subdir/lit.local.cfg
@@ -1 +1,4 @@
config.suffixes = ['.py']
+
+# Check that the arbitrary config values in our parent was inherited.
+assert hasattr(config, 'an_extra_variable')
diff --git a/utils/lit/tests/Inputs/discovery/subsuite/lit.cfg b/utils/lit/tests/Inputs/discovery/subsuite/lit.cfg
index 0c2979d..b49329a 100644
--- a/utils/lit/tests/Inputs/discovery/subsuite/lit.cfg
+++ b/utils/lit/tests/Inputs/discovery/subsuite/lit.cfg
@@ -1,3 +1,4 @@
+import lit.formats
config.name = 'sub-suite'
config.suffixes = ['.txt']
config.test_format = lit.formats.ShTest()
diff --git a/utils/lit/tests/Inputs/exec-discovery-in-tree/lit.cfg b/utils/lit/tests/Inputs/exec-discovery-in-tree/lit.cfg
index 342b2fd..ae25b4f 100644
--- a/utils/lit/tests/Inputs/exec-discovery-in-tree/lit.cfg
+++ b/utils/lit/tests/Inputs/exec-discovery-in-tree/lit.cfg
@@ -1,6 +1,8 @@
+import lit.formats
+
# Verify that the site configuration was loaded.
if config.test_source_root is None or config.test_exec_root is None:
- lit.fatal("No site specific configuration")
+ lit_config.fatal("No site specific configuration")
config.name = 'exec-discovery-in-tree-suite'
config.suffixes = ['.txt']
diff --git a/utils/lit/tests/Inputs/exec-discovery-in-tree/obj/lit.site.cfg b/utils/lit/tests/Inputs/exec-discovery-in-tree/obj/lit.site.cfg
index de9a3d0..4061c89 100644
--- a/utils/lit/tests/Inputs/exec-discovery-in-tree/obj/lit.site.cfg
+++ b/utils/lit/tests/Inputs/exec-discovery-in-tree/obj/lit.site.cfg
@@ -1,4 +1,4 @@
import os
config.test_exec_root = os.path.dirname(__file__)
config.test_source_root = os.path.dirname(config.test_exec_root)
-lit.load_config(config, os.path.join(config.test_source_root, "lit.cfg")) \ No newline at end of file
+lit_config.load_config(config, os.path.join(config.test_source_root, "lit.cfg")) \ No newline at end of file
diff --git a/utils/lit/tests/Inputs/exec-discovery/lit.site.cfg b/utils/lit/tests/Inputs/exec-discovery/lit.site.cfg
index 796569a..ac273c7 100644
--- a/utils/lit/tests/Inputs/exec-discovery/lit.site.cfg
+++ b/utils/lit/tests/Inputs/exec-discovery/lit.site.cfg
@@ -2,4 +2,4 @@
import os
config.test_exec_root = os.path.dirname(__file__)
config.test_source_root = os.path.join(os.path.dirname(config.test_exec_root), "discovery")
-lit.load_config(config, os.path.join(config.test_source_root, "lit.cfg"))
+lit_config.load_config(config, os.path.join(config.test_source_root, "lit.cfg"))
diff --git a/utils/lit/tests/Inputs/googletest-format/DummySubDir/OneTest b/utils/lit/tests/Inputs/googletest-format/DummySubDir/OneTest
new file mode 100755
index 0000000..9dff137
--- /dev/null
+++ b/utils/lit/tests/Inputs/googletest-format/DummySubDir/OneTest
@@ -0,0 +1,34 @@
+#!/usr/bin/env python
+
+import sys
+
+if len(sys.argv) != 2:
+ raise ValueError("unexpected number of args")
+
+if sys.argv[1] == "--gtest_list_tests":
+ print("""\
+FirstTest.
+ subTestA
+ subTestB
+ParameterizedTest/0.
+ subTest
+ParameterizedTest/1.
+ subTest""")
+ sys.exit(0)
+elif not sys.argv[1].startswith("--gtest_filter="):
+ raise ValueError("unexpected argument: %r" % (sys.argv[1]))
+
+test_name = sys.argv[1].split('=',1)[1]
+if test_name == 'FirstTest.subTestA':
+ print('I am subTest A, I PASS')
+ sys.exit(0)
+elif test_name == 'FirstTest.subTestB':
+ print('I am subTest B, I FAIL')
+ print('And I have two lines of output')
+ sys.exit(1)
+elif test_name in ('ParameterizedTest/0.subTest',
+ 'ParameterizedTest/1.subTest'):
+ print('I am a parameterized test, I also PASS')
+ sys.exit(0)
+else:
+ raise SystemExit("error: invalid test name: %r" % (test_name,))
diff --git a/utils/lit/tests/Inputs/googletest-format/lit.cfg b/utils/lit/tests/Inputs/googletest-format/lit.cfg
new file mode 100644
index 0000000..f2f6cda
--- /dev/null
+++ b/utils/lit/tests/Inputs/googletest-format/lit.cfg
@@ -0,0 +1,3 @@
+import lit.formats
+config.name = 'googletest-format'
+config.test_format = lit.formats.GoogleTest('DummySubDir', 'Test')
diff --git a/utils/lit/tests/Inputs/progress-bar/lit.cfg b/utils/lit/tests/Inputs/progress-bar/lit.cfg
index 4878b65..7f31129 100644
--- a/utils/lit/tests/Inputs/progress-bar/lit.cfg
+++ b/utils/lit/tests/Inputs/progress-bar/lit.cfg
@@ -1,3 +1,4 @@
+import lit.formats
config.name = 'shtest-shell'
config.suffixes = ['.txt']
config.test_format = lit.formats.ShTest()
diff --git a/utils/lit/tests/Inputs/shtest-format/argv0.txt b/utils/lit/tests/Inputs/shtest-format/argv0.txt
new file mode 100644
index 0000000..2ff2890
--- /dev/null
+++ b/utils/lit/tests/Inputs/shtest-format/argv0.txt
@@ -0,0 +1,6 @@
+# Check that we route argv[0] as it was written, instead of the resolved
+# path. This is important for some tools, in particular '[' which at least on OS
+# X only recognizes that it is in '['-mode when its argv[0] is exactly
+# '['. Otherwise it will refuse to accept the trailing closing bracket.
+#
+# RUN: [ "A" = "A" ]
diff --git a/utils/lit/tests/Inputs/shtest-format/external_shell/fail.txt b/utils/lit/tests/Inputs/shtest-format/external_shell/fail.txt
index 1e74be5..069e376 100644
--- a/utils/lit/tests/Inputs/shtest-format/external_shell/fail.txt
+++ b/utils/lit/tests/Inputs/shtest-format/external_shell/fail.txt
@@ -1,3 +1,5 @@
# Run a command that fails with error on stdout.
#
+# RUN: echo "line 1: failed test output on stdout"
+# RUN: echo "line 2: failed test output on stdout"
# RUN: cat "does-not-exist"
diff --git a/utils/lit/tests/Inputs/shtest-format/external_shell/fail_with_bad_encoding.txt b/utils/lit/tests/Inputs/shtest-format/external_shell/fail_with_bad_encoding.txt
new file mode 100644
index 0000000..f6157e6
--- /dev/null
+++ b/utils/lit/tests/Inputs/shtest-format/external_shell/fail_with_bad_encoding.txt
@@ -0,0 +1,5 @@
+# Run a command that fails with error on stdout.
+#
+# RUN: %S/write-bad-encoding.sh
+# RUN: false
+
diff --git a/utils/lit/tests/Inputs/shtest-format/external_shell/lit.local.cfg b/utils/lit/tests/Inputs/shtest-format/external_shell/lit.local.cfg
index d14d147..5e87c72 100644
--- a/utils/lit/tests/Inputs/shtest-format/external_shell/lit.local.cfg
+++ b/utils/lit/tests/Inputs/shtest-format/external_shell/lit.local.cfg
@@ -1 +1,2 @@
+import lit.formats
config.test_format = lit.formats.ShTest(execute_external=True)
diff --git a/utils/lit/tests/Inputs/shtest-format/external_shell/write-bad-encoding.sh b/utils/lit/tests/Inputs/shtest-format/external_shell/write-bad-encoding.sh
new file mode 100755
index 0000000..6b622cb
--- /dev/null
+++ b/utils/lit/tests/Inputs/shtest-format/external_shell/write-bad-encoding.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+echo "a line with bad encoding: Â."
diff --git a/utils/lit/tests/Inputs/shtest-format/fail.txt b/utils/lit/tests/Inputs/shtest-format/fail.txt
index 49932c3..8c305eb 100644
--- a/utils/lit/tests/Inputs/shtest-format/fail.txt
+++ b/utils/lit/tests/Inputs/shtest-format/fail.txt
@@ -1 +1,2 @@
+# RUN: printf "line 1: failed test output on stdout\nline 2: failed test output on stdout"
# RUN: false
diff --git a/utils/lit/tests/Inputs/shtest-format/lit.cfg b/utils/lit/tests/Inputs/shtest-format/lit.cfg
index 78dd1bf..9b47985 100644
--- a/utils/lit/tests/Inputs/shtest-format/lit.cfg
+++ b/utils/lit/tests/Inputs/shtest-format/lit.cfg
@@ -1,3 +1,4 @@
+import lit.formats
config.name = 'shtest-format'
config.suffixes = ['.txt']
config.test_format = lit.formats.ShTest()
diff --git a/utils/lit/tests/Inputs/shtest-shell/lit.cfg b/utils/lit/tests/Inputs/shtest-shell/lit.cfg
index 4878b65..7f31129 100644
--- a/utils/lit/tests/Inputs/shtest-shell/lit.cfg
+++ b/utils/lit/tests/Inputs/shtest-shell/lit.cfg
@@ -1,3 +1,4 @@
+import lit.formats
config.name = 'shtest-shell'
config.suffixes = ['.txt']
config.test_format = lit.formats.ShTest()
diff --git a/utils/lit/tests/Inputs/test-data/lit.cfg b/utils/lit/tests/Inputs/test-data/lit.cfg
new file mode 100644
index 0000000..f5aba7b
--- /dev/null
+++ b/utils/lit/tests/Inputs/test-data/lit.cfg
@@ -0,0 +1,44 @@
+import os
+try:
+ import ConfigParser
+except ImportError:
+ import configparser as ConfigParser
+
+import lit.formats
+import lit.Test
+
+class DummyFormat(lit.formats.FileBasedTest):
+ def execute(self, test, lit_config):
+ # In this dummy format, expect that each test file is actually just a
+ # .ini format dump of the results to report.
+
+ source_path = test.getSourcePath()
+
+ cfg = ConfigParser.ConfigParser()
+ cfg.read(source_path)
+
+ # Create the basic test result.
+ result_code = cfg.get('global', 'result_code')
+ result_output = cfg.get('global', 'result_output')
+ result = lit.Test.Result(getattr(lit.Test, result_code),
+ result_output)
+
+ # Load additional metrics.
+ for key,value_str in cfg.items('results'):
+ value = eval(value_str)
+ if isinstance(value, int):
+ metric = lit.Test.IntMetricValue(value)
+ elif isinstance(value, float):
+ metric = lit.Test.RealMetricValue(value)
+ else:
+ raise RuntimeError("unsupported result type")
+ result.addMetric(key, metric)
+
+ return result
+
+config.name = 'test-data'
+config.suffixes = ['.ini']
+config.test_format = DummyFormat()
+config.test_source_root = None
+config.test_exec_root = None
+config.target_triple = None
diff --git a/utils/lit/tests/Inputs/test-data/metrics.ini b/utils/lit/tests/Inputs/test-data/metrics.ini
new file mode 100644
index 0000000..01b09c5
--- /dev/null
+++ b/utils/lit/tests/Inputs/test-data/metrics.ini
@@ -0,0 +1,7 @@
+[global]
+result_code = PASS
+result_output = Test passed.
+
+[results]
+value0 = 1
+value1 = 2.3456 \ No newline at end of file
diff --git a/utils/lit/tests/Inputs/unittest-adaptor/lit.cfg b/utils/lit/tests/Inputs/unittest-adaptor/lit.cfg
index 52de709..9e08a86 100644
--- a/utils/lit/tests/Inputs/unittest-adaptor/lit.cfg
+++ b/utils/lit/tests/Inputs/unittest-adaptor/lit.cfg
@@ -1,3 +1,4 @@
+import lit.formats
config.name = 'unittest-adaptor'
config.suffixes = ['.txt']
config.test_format = lit.formats.ShTest()
diff --git a/utils/lit/tests/discovery.py b/utils/lit/tests/discovery.py
index be98c4b..2801089 100644
--- a/utils/lit/tests/discovery.py
+++ b/utils/lit/tests/discovery.py
@@ -1,7 +1,7 @@
# Check the basic discovery process, including a sub-suite.
#
# RUN: %{lit} %{inputs}/discovery \
-# RUN: -j 1 --debug --show-tests --show-suites --max-tests 0 \
+# RUN: -j 1 --debug --show-tests --show-suites \
# RUN: -v > %t.out 2> %t.err
# RUN: FileCheck --check-prefix=CHECK-BASIC-OUT < %t.out %s
# RUN: FileCheck --check-prefix=CHECK-BASIC-ERR < %t.err %s
@@ -24,7 +24,6 @@
# CHECK-BASIC-OUT: top-level-suite :: subdir/test-three
# CHECK-BASIC-OUT: top-level-suite :: test-one
# CHECK-BASIC-OUT: top-level-suite :: test-two
-# CHECK-BASIC-OUT: -- Testing: 0
# Check discovery when exact test names are given.
@@ -32,19 +31,18 @@
# RUN: %{lit} \
# RUN: %{inputs}/discovery/subdir/test-three.py \
# RUN: %{inputs}/discovery/subsuite/test-one.txt \
-# RUN: -j 1 --show-tests --show-suites --max-tests 0 -v > %t.out
+# RUN: -j 1 --show-tests --show-suites -v > %t.out
# RUN: FileCheck --check-prefix=CHECK-EXACT-TEST < %t.out %s
#
# CHECK-EXACT-TEST: -- Available Tests --
# CHECK-EXACT-TEST: sub-suite :: test-one
# CHECK-EXACT-TEST: top-level-suite :: subdir/test-three
-# CHECK-EXACT-TEST: -- Testing: 0
# Check discovery when using an exec path.
#
# RUN: %{lit} %{inputs}/exec-discovery \
-# RUN: -j 1 --debug --show-tests --show-suites --max-tests 0 \
+# RUN: -j 1 --debug --show-tests --show-suites \
# RUN: -v > %t.out 2> %t.err
# RUN: FileCheck --check-prefix=CHECK-ASEXEC-OUT < %t.out %s
# RUN: FileCheck --check-prefix=CHECK-ASEXEC-ERR < %t.err %s
@@ -70,7 +68,6 @@
# CHECK-ASEXEC-OUT: top-level-suite :: subdir/test-three
# CHECK-ASEXEC-OUT: top-level-suite :: test-one
# CHECK-ASEXEC-OUT: top-level-suite :: test-two
-# CHECK-ASEXEC-OUT: -- Testing: 0
# Check discovery when exact test names are given.
#
@@ -78,12 +75,11 @@
#
# RUN: %{lit} \
# RUN: %{inputs}/exec-discovery/subdir/test-three.py \
-# RUN: -j 1 --show-tests --show-suites --max-tests 0 -v > %t.out
+# RUN: -j 1 --show-tests --show-suites -v > %t.out
# RUN: FileCheck --check-prefix=CHECK-ASEXEC-EXACT-TEST < %t.out %s
#
# CHECK-ASEXEC-EXACT-TEST: -- Available Tests --
# CHECK-ASEXEC-EXACT-TEST: top-level-suite :: subdir/test-three
-# CHECK-ASEXEC-EXACT-TEST: -- Testing: 0
# Check that we don't recurse infinitely when loading an site specific test
@@ -91,7 +87,7 @@
#
# RUN: %{lit} \
# RUN: %{inputs}/exec-discovery-in-tree/obj/ \
-# RUN: -j 1 --show-tests --show-suites --max-tests 0 -v > %t.out
+# RUN: -j 1 --show-tests --show-suites -v > %t.out
# RUN: FileCheck --check-prefix=CHECK-ASEXEC-INTREE < %t.out %s
#
# CHECK-ASEXEC-INTREE: exec-discovery-in-tree-suite - 1 tests
@@ -99,4 +95,3 @@
# CHECK-ASEXEC-INTREE-NEXT: Exec Root : {{.*/exec-discovery-in-tree/obj$}}
# CHECK-ASEXEC-INTREE-NEXT: -- Available Tests --
# CHECK-ASEXEC-INTREE-NEXT: exec-discovery-in-tree-suite :: test-one
-# CHECK-ASEXEC-INTREE: -- Testing: 0
diff --git a/utils/lit/tests/googletest-format.py b/utils/lit/tests/googletest-format.py
new file mode 100644
index 0000000..a62fd1b
--- /dev/null
+++ b/utils/lit/tests/googletest-format.py
@@ -0,0 +1,20 @@
+# Check the various features of the GoogleTest format.
+#
+# RUN: not %{lit} -j 1 -v %{inputs}/googletest-format > %t.out
+# RUN: FileCheck < %t.out %s
+#
+# END.
+
+# CHECK: -- Testing:
+# CHECK: PASS: googletest-format :: DummySubDir/OneTest/FirstTest.subTestA
+# CHECK: FAIL: googletest-format :: DummySubDir/OneTest/FirstTest.subTestB
+# CHECK-NEXT: *** TEST 'googletest-format :: DummySubDir/OneTest/FirstTest.subTestB' FAILED ***
+# CHECK-NEXT: I am subTest B, I FAIL
+# CHECK-NEXT: And I have two lines of output
+# CHECK: ***
+# CHECK: PASS: googletest-format :: DummySubDir/OneTest/ParameterizedTest/0.subTest
+# CHECK: PASS: googletest-format :: DummySubDir/OneTest/ParameterizedTest/1.subTest
+# CHECK: Failing Tests (1)
+# CHECK: Expected Passes : 3
+# CHECK: Unexpected Failures: 1
+
diff --git a/utils/lit/tests/lit.cfg b/utils/lit/tests/lit.cfg
index 32760ce..2111b72 100644
--- a/utils/lit/tests/lit.cfg
+++ b/utils/lit/tests/lit.cfg
@@ -1,6 +1,9 @@
# -*- Python -*-
import os
+import sys
+
+import lit.formats
# Configuration file for the 'lit' test runner.
@@ -20,17 +23,23 @@ config.excludes = ['Inputs']
config.test_source_root = os.path.dirname(__file__)
config.test_exec_root = config.test_source_root
-config.target_triple = None
+config.target_triple = '(unused)'
src_root = os.path.join(config.test_source_root, '..')
config.environment['PYTHONPATH'] = src_root
config.substitutions.append(('%{src_root}', src_root))
config.substitutions.append(('%{inputs}', os.path.join(
src_root, 'tests', 'Inputs')))
-config.substitutions.append(('%{lit}', os.path.join(src_root, 'lit.py')))
+config.substitutions.append(('%{lit}', "%%{python} %s" % (
+ os.path.join(src_root, 'lit.py'),)))
+config.substitutions.append(('%{python}', sys.executable))
# Enable coverage.py reporting, assuming the coverage module has been installed
# and sitecustomize.py in the virtualenv has been modified appropriately.
-if lit.params.get('check-coverage', None):
+if lit_config.params.get('check-coverage', None):
config.environment['COVERAGE_PROCESS_START'] = os.path.join(
os.path.dirname(__file__), ".coveragerc")
+
+# Add a feature to detect the Python version.
+config.available_features.add("python%d.%d" % (sys.version_info[0],
+ sys.version_info[1]))
diff --git a/utils/lit/tests/shell-parsing.py b/utils/lit/tests/shell-parsing.py
index f644132..a07e988 100644
--- a/utils/lit/tests/shell-parsing.py
+++ b/utils/lit/tests/shell-parsing.py
@@ -1,3 +1,3 @@
# Just run the ShUtil unit tests.
#
-# RUN: python -m lit.ShUtil
+# RUN: %{python} -m lit.ShUtil
diff --git a/utils/lit/tests/shtest-encoding.py b/utils/lit/tests/shtest-encoding.py
new file mode 100644
index 0000000..dfc987f
--- /dev/null
+++ b/utils/lit/tests/shtest-encoding.py
@@ -0,0 +1,3 @@
+# RUN: true
+
+# Here is a string that cannot be decoded in line mode: Â.
diff --git a/utils/lit/tests/shtest-format.py b/utils/lit/tests/shtest-format.py
index 4b36873..751f0d7 100644
--- a/utils/lit/tests/shtest-format.py
+++ b/utils/lit/tests/shtest-format.py
@@ -7,15 +7,43 @@
# CHECK: -- Testing:
+# CHECK: PASS: shtest-format :: argv0.txt
# CHECK: FAIL: shtest-format :: external_shell/fail.txt
-# CHECK: *** TEST 'shtest-format :: external_shell/fail.txt' FAILED ***
+# CHECK-NEXT: *** TEST 'shtest-format :: external_shell/fail.txt' FAILED ***
+# CHECK: Command Output (stdout):
+# CHECK-NEXT: --
+# CHECK-NEXT: line 1: failed test output on stdout
+# CHECK-NEXT: line 2: failed test output on stdout
# CHECK: Command Output (stderr):
-# CHECK: cat: does-not-exist: No such file or directory
+# CHECK-NEXT: --
+# CHECK-NEXT: cat: does-not-exist: No such file or directory
+# CHECK: --
+
+# CHECK: FAIL: shtest-format :: external_shell/fail_with_bad_encoding.txt
+# CHECK-NEXT: *** TEST 'shtest-format :: external_shell/fail_with_bad_encoding.txt' FAILED ***
+# CHECK: Command Output (stdout):
+# CHECK-NEXT: --
+# CHECK-NEXT: a line with bad encoding:
# CHECK: --
# CHECK: PASS: shtest-format :: external_shell/pass.txt
# CHECK: FAIL: shtest-format :: fail.txt
+# CHECK-NEXT: *** TEST 'shtest-format :: fail.txt' FAILED ***
+# CHECK-NEXT: Script:
+# CHECK-NEXT: --
+# CHECK-NEXT: printf "line 1
+# CHECK-NEXT: false
+# CHECK-NEXT: --
+# CHECK-NEXT: Exit Code: 1
+#
+# CHECK: Command Output (stdout):
+# CHECK-NEXT: --
+# CHECK-NEXT: Command 0: "printf"
+# CHECK-NEXT: Command 0 Result: 0
+# CHECK-NEXT: Command 0 Output:
+# CHECK-NEXT: line 1: failed test output on stdout
+# CHECK-NEXT: line 2: failed test output on stdout
# CHECK: UNRESOLVED: shtest-format :: no-test-line.txt
# CHECK: PASS: shtest-format :: pass.txt
@@ -26,18 +54,24 @@
# CHECK: XFAIL: shtest-format :: xfail-target.txt
# CHECK: XFAIL: shtest-format :: xfail.txt
# CHECK: XPASS: shtest-format :: xpass.txt
+# CHECK-NEXT: *** TEST 'shtest-format :: xpass.txt' FAILED ***
+# CHECK-NEXT: Script
+# CHECK-NEXT: --
+# CHECK-NEXT: true
+# CHECK-NEXT: --
# CHECK: Testing Time
# CHECK: Unexpected Passing Tests (1)
# CHECK: shtest-format :: xpass.txt
-# CHECK: Failing Tests (2)
+# CHECK: Failing Tests (3)
# CHECK: shtest-format :: external_shell/fail.txt
+# CHECK: shtest-format :: external_shell/fail_with_bad_encoding.txt
# CHECK: shtest-format :: fail.txt
-# CHECK: Expected Passes : 3
+# CHECK: Expected Passes : 4
# CHECK: Expected Failures : 3
# CHECK: Unsupported Tests : 2
# CHECK: Unresolved Tests : 1
# CHECK: Unexpected Passes : 1
-# CHECK: Unexpected Failures: 2
+# CHECK: Unexpected Failures: 3
diff --git a/utils/lit/tests/test-data.py b/utils/lit/tests/test-data.py
new file mode 100644
index 0000000..54909d7
--- /dev/null
+++ b/utils/lit/tests/test-data.py
@@ -0,0 +1,12 @@
+# Test features related to formats which support reporting additional test data.
+
+# RUN: %{lit} -j 1 -v %{inputs}/test-data > %t.out
+# RUN: FileCheck < %t.out %s
+
+# CHECK: -- Testing:
+
+# CHECK: PASS: test-data :: metrics.ini
+# CHECK-NEXT: *** TEST 'test-data :: metrics.ini' RESULTS ***
+# CHECK-NEXT: value0: 1
+# CHECK-NEXT: value1: 2.3456
+# CHECK-NEXT: ***
diff --git a/utils/lit/tests/test-output.py b/utils/lit/tests/test-output.py
new file mode 100644
index 0000000..adfbcd8
--- /dev/null
+++ b/utils/lit/tests/test-output.py
@@ -0,0 +1,21 @@
+# XFAIL: python2.5
+
+# RUN: %{lit} -j 1 -v %{inputs}/test-data --output %t.results.out > %t.out
+# RUN: FileCheck < %t.results.out %s
+
+# CHECK: {
+# CHECK: "__version__"
+# CHECK: "elapsed"
+# CHECK-NEXT: "tests": [
+# CHECK-NEXT: {
+# CHECK-NEXT: "code": "PASS",
+# CHECK-NEXT: "elapsed": {{[0-9.]+}},
+# CHECK-NEXT: "metrics": {
+# CHECK-NEXT: "value0": 1,
+# CHECK-NEXT: "value1": 2.3456
+# CHECK-NEXT: }
+# CHECK-NEXT: "name": "test-data :: metrics.ini",
+# CHECK-NEXT: "output": "Test passed."
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+# CHECK-NEXT: }
diff --git a/utils/lit/tests/unittest-adaptor.py b/utils/lit/tests/unittest-adaptor.py
index 243dd41..7435dda 100644
--- a/utils/lit/tests/unittest-adaptor.py
+++ b/utils/lit/tests/unittest-adaptor.py
@@ -1,6 +1,6 @@
# Check the lit adaption to run under unittest.
#
-# RUN: python %s %{inputs}/unittest-adaptor 2> %t.err
+# RUN: %{python} %s %{inputs}/unittest-adaptor 2> %t.err
# RUN: FileCheck < %t.err %s
#
# CHECK: unittest-adaptor :: test-one.txt ... ok
diff --git a/utils/llvm-build/llvmbuild/__init__.py b/utils/llvm-build/llvmbuild/__init__.py
index 7760218..eb20d09 100644
--- a/utils/llvm-build/llvmbuild/__init__.py
+++ b/utils/llvm-build/llvmbuild/__init__.py
@@ -1 +1 @@
-from main import main
+from llvmbuild.main import main
diff --git a/utils/llvm-build/llvmbuild/componentinfo.py b/utils/llvm-build/llvmbuild/componentinfo.py
index e684ac2..eda3a48 100644
--- a/utils/llvm-build/llvmbuild/componentinfo.py
+++ b/utils/llvm-build/llvmbuild/componentinfo.py
@@ -2,11 +2,14 @@
Descriptor objects for entities that are part of the LLVM project.
"""
-import ConfigParser
-import StringIO
+from __future__ import absolute_import
+try:
+ import configparser
+except:
+ import ConfigParser as configparser
import sys
-from util import *
+from llvmbuild.util import *
class ParseError(Exception):
pass
@@ -29,7 +32,7 @@ class ComponentInfo(object):
def __init__(self, subpath, name, dependencies, parent):
if not subpath.startswith('/'):
- raise ValueError,"invalid subpath: %r" % subpath
+ raise ValueError("invalid subpath: %r" % subpath)
self.subpath = subpath
self.name = name
self.dependencies = list(dependencies)
@@ -100,11 +103,11 @@ class GroupComponentInfo(ComponentInfo):
ComponentInfo.__init__(self, subpath, name, [], parent)
def get_llvmbuild_fragment(self):
- result = StringIO.StringIO()
- print >>result, 'type = %s' % self.type_name
- print >>result, 'name = %s' % self.name
- print >>result, 'parent = %s' % self.parent
- return result.getvalue()
+ return """\
+type = %s
+name = %s
+parent = %s
+""" % (self.type_name, self.name, self.parent)
class LibraryComponentInfo(ComponentInfo):
type_name = 'Library'
@@ -152,21 +155,22 @@ class LibraryComponentInfo(ComponentInfo):
yield ('library group', r)
def get_llvmbuild_fragment(self):
- result = StringIO.StringIO()
- print >>result, 'type = %s' % self.type_name
- print >>result, 'name = %s' % self.name
- print >>result, 'parent = %s' % self.parent
+ result = """\
+type = %s
+name = %s
+parent = %s
+""" % (self.type_name, self.name, self.parent)
if self.library_name is not None:
- print >>result, 'library_name = %s' % self.library_name
+ result += 'library_name = %s\n' % self.library_name
if self.required_libraries:
- print >>result, 'required_libraries = %s' % ' '.join(
+ result += 'required_libraries = %s\n' % ' '.join(
self.required_libraries)
if self.add_to_library_groups:
- print >>result, 'add_to_library_groups = %s' % ' '.join(
+ result += 'add_to_library_groups = %s\n' % ' '.join(
self.add_to_library_groups)
if not self.installed:
- print >>result, 'installed = 0'
- return result.getvalue()
+ result += 'installed = 0\n'
+ return result
def get_library_name(self):
return self.library_name or self.name
@@ -237,17 +241,18 @@ class LibraryGroupComponentInfo(ComponentInfo):
yield ('library group', r)
def get_llvmbuild_fragment(self):
- result = StringIO.StringIO()
- print >>result, 'type = %s' % self.type_name
- print >>result, 'name = %s' % self.name
- print >>result, 'parent = %s' % self.parent
+ result = """\
+type = %s
+name = %s
+parent = %s
+""" % (self.type_name, self.name, self.parent)
if self.required_libraries and not self._is_special_group:
- print >>result, 'required_libraries = %s' % ' '.join(
+ result += 'required_libraries = %s\n' % ' '.join(
self.required_libraries)
if self.add_to_library_groups:
- print >>result, 'add_to_library_groups = %s' % ' '.join(
+ result += 'add_to_library_groups = %s\n' % ' '.join(
self.add_to_library_groups)
- return result.getvalue()
+ return result
def get_llvmconfig_component_name(self):
return self.name.lower()
@@ -309,21 +314,22 @@ class TargetGroupComponentInfo(ComponentInfo):
yield ('library group', r)
def get_llvmbuild_fragment(self):
- result = StringIO.StringIO()
- print >>result, 'type = %s' % self.type_name
- print >>result, 'name = %s' % self.name
- print >>result, 'parent = %s' % self.parent
+ result = """\
+type = %s
+name = %s
+parent = %s
+""" % (self.type_name, self.name, self.parent)
if self.required_libraries:
- print >>result, 'required_libraries = %s' % ' '.join(
+ result += 'required_libraries = %s\n' % ' '.join(
self.required_libraries)
if self.add_to_library_groups:
- print >>result, 'add_to_library_groups = %s' % ' '.join(
+ result += 'add_to_library_groups = %s\n' % ' '.join(
self.add_to_library_groups)
for bool_key in ('has_asmparser', 'has_asmprinter', 'has_disassembler',
'has_jit'):
if getattr(self, bool_key):
- print >>result, '%s = 1' % (bool_key,)
- return result.getvalue()
+ result += '%s = 1\n' % (bool_key,)
+ return result
def get_llvmconfig_component_name(self):
return self.name.lower()
@@ -352,13 +358,13 @@ class ToolComponentInfo(ComponentInfo):
yield ('required library', r)
def get_llvmbuild_fragment(self):
- result = StringIO.StringIO()
- print >>result, 'type = %s' % self.type_name
- print >>result, 'name = %s' % self.name
- print >>result, 'parent = %s' % self.parent
- print >>result, 'required_libraries = %s' % ' '.join(
- self.required_libraries)
- return result.getvalue()
+ return """\
+type = %s
+name = %s
+parent = %s
+required_libraries = %s
+""" % (self.type_name, self.name, self.parent,
+ ' '.join(self.required_libraries))
class BuildToolComponentInfo(ToolComponentInfo):
type_name = 'BuildTool'
@@ -418,7 +424,7 @@ _component_type_map = dict(
TargetGroupComponentInfo, OptionalLibraryComponentInfo))
def load_from_path(path, subpath):
# Load the LLVMBuild.txt file as an .ini format file.
- parser = ConfigParser.RawConfigParser()
+ parser = configparser.RawConfigParser()
parser.read(path)
# Extract the common section.
@@ -459,8 +465,9 @@ def _read_components_from_parser(parser, path, subpath):
section, path, "unable to instantiate: %r" % type_name)
import traceback
traceback.print_exc()
- raise SystemExit, 1
- except ParseError,e:
+ raise SystemExit(1)
+ except ParseError:
+ e = sys.exc_info()[1]
fatal("unable to load component %r in %r: %s" % (
section, path, e.message))
diff --git a/utils/llvm-build/llvmbuild/main.py b/utils/llvm-build/llvmbuild/main.py
index 87e8819..eacefdf 100644
--- a/utils/llvm-build/llvmbuild/main.py
+++ b/utils/llvm-build/llvmbuild/main.py
@@ -1,11 +1,11 @@
-import StringIO
+from __future__ import absolute_import
import os
import sys
-import componentinfo
-import configutil
+import llvmbuild.componentinfo as componentinfo
+import llvmbuild.configutil as configutil
-from util import *
+from llvmbuild.util import *
###
@@ -186,7 +186,7 @@ class LLVMProjectInfo(object):
set(self.component_infos),
key = lambda c: c.name)
while components_to_visit:
- visit_component_info(iter(components_to_visit).next(), [], set())
+ visit_component_info(components_to_visit[0], [], set())
# Canonicalize children lists.
for c in self.ordered_component_infos:
@@ -194,7 +194,7 @@ class LLVMProjectInfo(object):
def print_tree(self):
def visit(node, depth = 0):
- print '%s%-40s (%s)' % (' '*depth, node.name, node.type_name)
+ print('%s%-40s (%s)' % (' '*depth, node.name, node.type_name))
for c in node.children:
visit(c, depth + 1)
visit(self.component_info_map['$ROOT'])
@@ -283,7 +283,7 @@ subdirectories = %s
header_name = '.' + os.path.join(subpath, 'LLVMBuild.txt')
header_pad = '-' * (80 - len(header_fmt % (header_name, '')))
header_string = header_fmt % (header_name, header_pad)
- print >>f, """\
+ f.write("""\
%s
;
; The LLVM Compiler Infrastructure
@@ -300,17 +300,18 @@ subdirectories = %s
; http://llvm.org/docs/LLVMBuild.html
;
;===------------------------------------------------------------------------===;
-""" % header_string
+
+""" % header_string)
# Write out each fragment.each component fragment.
for name,fragment in fragments:
comment = comments_map.get(name)
if comment is not None:
f.write(comment)
- print >>f, "[%s]" % name
+ f.write("[%s]\n" % name)
f.write(fragment)
if fragment is not fragments[-1][1]:
- print >>f
+ f.write('\n')
f.close()
@@ -363,7 +364,7 @@ subdirectories = %s
is_installed)
# Convert to a list of entries and sort by name.
- entries = entries.values()
+ entries = list(entries.values())
# Create an 'all' pseudo component. We keep the dependency list small by
# only listing entries that have no other dependents.
@@ -382,7 +383,7 @@ subdirectories = %s
# Write out the library table.
make_install_dir(os.path.dirname(output_path))
f = open(output_path, 'w')
- print >>f, """\
+ f.write("""\
//===- llvm-build generated file --------------------------------*- C++ -*-===//
//
// Component Library Depenedency Table
@@ -390,32 +391,33 @@ subdirectories = %s
// Automatically generated file, do not edit!
//
//===----------------------------------------------------------------------===//
-"""
- print >>f, 'struct AvailableComponent {'
- print >>f, ' /// The name of the component.'
- print >>f, ' const char *Name;'
- print >>f, ''
- print >>f, ' /// The name of the library for this component (or NULL).'
- print >>f, ' const char *Library;'
- print >>f, ''
- print >>f, ' /// Whether the component is installed.'
- print >>f, ' bool IsInstalled;'
- print >>f, ''
- print >>f, '\
- /// The list of libraries required when linking this component.'
- print >>f, ' const char *RequiredLibraries[%d];' % (
- max_required_libraries)
- print >>f, '} AvailableComponents[%d] = {' % len(entries)
+
+""")
+ f.write('struct AvailableComponent {\n')
+ f.write(' /// The name of the component.\n')
+ f.write(' const char *Name;\n')
+ f.write('\n')
+ f.write(' /// The name of the library for this component (or NULL).\n')
+ f.write(' const char *Library;\n')
+ f.write('\n')
+ f.write(' /// Whether the component is installed.\n')
+ f.write(' bool IsInstalled;\n')
+ f.write('\n')
+ f.write('\
+ /// The list of libraries required when linking this component.\n')
+ f.write(' const char *RequiredLibraries[%d];\n' % (
+ max_required_libraries))
+ f.write('} AvailableComponents[%d] = {\n' % len(entries))
for name,library_name,required_names,is_installed in entries:
if library_name is None:
library_name_as_cstr = '0'
else:
library_name_as_cstr = '"lib%s.a"' % library_name
- print >>f, ' { "%s", %s, %d, { %s } },' % (
+ f.write(' { "%s", %s, %d, { %s } },\n' % (
name, library_name_as_cstr, is_installed,
', '.join('"%s"' % dep
- for dep in required_names))
- print >>f, '};'
+ for dep in required_names)))
+ f.write('};\n')
f.close()
def get_required_libraries_for_component(self, ci, traverse_groups = False):
@@ -512,7 +514,7 @@ subdirectories = %s
header_name = os.path.basename(output_path)
header_pad = '-' * (80 - len(header_fmt % (header_name, '')))
header_string = header_fmt % (header_name, header_pad)
- print >>f, """\
+ f.write("""\
%s
#
# The LLVM Compiler Infrastructure
@@ -528,10 +530,11 @@ subdirectories = %s
# This file is autogenerated by llvm-build, do not edit!
#
#===------------------------------------------------------------------------===#
-""" % header_string
+
+""" % header_string)
# Write the dependency information in the best way we can.
- print >>f, """
+ f.write("""
# LLVMBuild CMake fragment dependencies.
#
# CMake has no builtin way to declare that the configuration depends on
@@ -541,30 +544,32 @@ subdirectories = %s
# CMake.
#
# FIXME: File a CMake RFE to get a properly supported version of this
-# feature."""
+# feature.
+""")
for dep in dependencies:
- print >>f, """\
+ f.write("""\
configure_file(\"%s\"
- ${CMAKE_CURRENT_BINARY_DIR}/DummyConfigureOutput)""" % (
- cmake_quote_path(dep),)
+ ${CMAKE_CURRENT_BINARY_DIR}/DummyConfigureOutput)\n""" % (
+ cmake_quote_path(dep),))
# Write the properties we use to encode the required library dependency
# information in a form CMake can easily use directly.
- print >>f, """
+ f.write("""
# Explicit library dependency information.
#
# The following property assignments effectively create a map from component
-# names to required libraries, in a way that is easily accessed from CMake."""
+# names to required libraries, in a way that is easily accessed from CMake.
+""")
for ci in self.ordered_component_infos:
# We only write the information for libraries currently.
if ci.type_name != 'Library':
continue
- print >>f, """\
-set_property(GLOBAL PROPERTY LLVMBUILD_LIB_DEPS_%s %s)""" % (
+ f.write("""\
+set_property(GLOBAL PROPERTY LLVMBUILD_LIB_DEPS_%s %s)\n""" % (
ci.get_prefixed_library_name(), " ".join(sorted(
dep.get_prefixed_library_name()
- for dep in self.get_required_libraries_for_component(ci))))
+ for dep in self.get_required_libraries_for_component(ci)))))
f.close()
@@ -590,7 +595,7 @@ set_property(GLOBAL PROPERTY LLVMBUILD_LIB_DEPS_%s %s)""" % (
header_name = os.path.basename(output_path)
header_pad = '-' * (80 - len(header_fmt % (header_name, '')))
header_string = header_fmt % (header_name, header_pad)
- print >>f, """\
+ f.write("""\
%s
#
# The LLVM Compiler Infrastructure
@@ -606,30 +611,33 @@ set_property(GLOBAL PROPERTY LLVMBUILD_LIB_DEPS_%s %s)""" % (
# This file is autogenerated by llvm-build, do not edit!
#
#===------------------------------------------------------------------------===#
-""" % header_string
+
+""" % header_string)
# Write the dependencies for the fragment.
#
# FIXME: Technically, we need to properly quote for Make here.
- print >>f, """\
+ f.write("""\
# Clients must explicitly enable LLVMBUILD_INCLUDE_DEPENDENCIES to get
# these dependencies. This is a compromise to help improve the
-# performance of recursive Make systems."""
- print >>f, 'ifeq ($(LLVMBUILD_INCLUDE_DEPENDENCIES),1)'
- print >>f, "# The dependencies for this Makefile fragment itself."
- print >>f, "%s: \\" % (mk_quote_string_for_target(output_path),)
+# performance of recursive Make systems.
+""")
+ f.write('ifeq ($(LLVMBUILD_INCLUDE_DEPENDENCIES),1)\n')
+ f.write("# The dependencies for this Makefile fragment itself.\n")
+ f.write("%s: \\\n" % (mk_quote_string_for_target(output_path),))
for dep in dependencies:
- print >>f, "\t%s \\" % (dep,)
- print >>f
+ f.write("\t%s \\\n" % (dep,))
+ f.write('\n')
# Generate dummy rules for each of the dependencies, so that things
# continue to work correctly if any of those files are moved or removed.
- print >>f, """\
+ f.write("""\
# The dummy targets to allow proper regeneration even when files are moved or
-# removed."""
+# removed.
+""")
for dep in dependencies:
- print >>f, "%s:" % (mk_quote_string_for_target(dep),)
- print >>f, 'endif'
+ f.write("%s:\n" % (mk_quote_string_for_target(dep),))
+ f.write('endif\n')
f.close()
@@ -801,7 +809,7 @@ given by --build-root) at the same SUBPATH""",
dest="optional_components", metavar="NAMES",
help=("Enable the given space or semi-colon separated "
"list of optional components"),
- action="store", default=None)
+ action="store", default="")
parser.add_option_group(group)
(opts, args) = parser.parse_args()
diff --git a/utils/llvm-build/llvmbuild/util.py b/utils/llvm-build/llvmbuild/util.py
index e581af2..ca021c4 100644
--- a/utils/llvm-build/llvmbuild/util.py
+++ b/utils/llvm-build/llvmbuild/util.py
@@ -3,7 +3,7 @@ import sys
def _write_message(kind, message):
program = os.path.basename(sys.argv[0])
- print >>sys.stderr, '%s: %s: %s' % (program, kind, message)
+ sys.stderr.write('%s: %s: %s\n' % (program, kind, message))
note = lambda message: _write_message('note', message)
warning = lambda message: _write_message('warning', message)
diff --git a/utils/llvm-lit/CMakeLists.txt b/utils/llvm-lit/CMakeLists.txt
index 602cc88..b535eae 100644
--- a/utils/llvm-lit/CMakeLists.txt
+++ b/utils/llvm-lit/CMakeLists.txt
@@ -2,11 +2,3 @@ configure_file(
llvm-lit.in
${LLVM_TOOLS_BINARY_DIR}/llvm-lit
)
-
-install(FILES
- ${LLVM_TOOLS_BINARY_DIR}/llvm-lit
- DESTINATION bin
- PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE
- GROUP_READ GROUP_EXECUTE
- WORLD_READ WORLD_EXECUTE
- )
diff --git a/utils/not/CMakeLists.txt b/utils/not/CMakeLists.txt
index f4c0229..5ff14d6 100644
--- a/utils/not/CMakeLists.txt
+++ b/utils/not/CMakeLists.txt
@@ -4,7 +4,7 @@ add_llvm_utility(not
target_link_libraries(not LLVMSupport)
if( MINGW )
- target_link_libraries(not imagehlp psapi)
+ target_link_libraries(not imagehlp psapi shell32)
endif( MINGW )
if( LLVM_ENABLE_THREADS AND HAVE_LIBPTHREAD )
target_link_libraries(not pthread)
diff --git a/utils/profile.pl b/utils/profile.pl
deleted file mode 100755
index 782e5dc..0000000
--- a/utils/profile.pl
+++ /dev/null
@@ -1,74 +0,0 @@
-#!/usr/bin/perl -w
-#
-# Program: profile.pl
-#
-# Synopsis: Insert instrumentation code into a program, run it with the JIT,
-# then print out a profile report.
-#
-# Syntax: profile.pl [OPTIONS] bitcodefile <arguments>
-#
-# OPTIONS may include one or more of the following:
-# -block - Enable basicblock profiling
-# -edge - Enable edge profiling
-# -function - Enable function profiling
-# -o <filename> - Emit profiling information to the specified file, instead
-# of llvmprof.out
-#
-# Any unrecognized options are passed into the invocation of llvm-prof
-#
-
-my $ProfilePass = "-insert-edge-profiling";
-
-my $LLVMProfOpts = "";
-my $ProgramOpts = "";
-my $ProfileFile = "";
-
-# Parse arguments...
-while (scalar(@ARGV) and ($_ = $ARGV[0], /^[-+]/)) {
- shift;
- last if /^--$/; # Stop processing arguments on --
-
- # List command line options here...
- if (/^-?-block$/) { $ProfilePass = "-insert-block-profiling"; next; }
- if (/^-?-edge$/) { $ProfilePass = "-insert-edge-profiling"; next; }
- if (/^-?-function$/) { $ProfilePass = "-insert-function-profiling"; next; }
- if (/^-?-o$/) { # Read -o filename...
- die "-o option requires a filename argument!" if (!scalar(@ARGV));
- $ProgramOpts .= " -llvmprof-output $ARGV[0]";
- $ProfileFile = $ARGV[0];
- shift;
- next;
- }
- if (/^-?-help$/) {
- print "OVERVIEW: profile.pl - Instrumentation and profile printer.\n\n";
- print "USAGE: profile.pl [options] program.bc <program args>\n\n";
- print "OPTIONS:\n";
- print " -block - Enable basicblock profiling\n";
- print " -edge - Enable edge profiling\n";
- print " -function - Enable function profiling\n";
- print " -o <file> - Specify an output file other than llvm-prof.out.\n";
- print " -help - Print this usage information\n";
- print "\nAll other options are passed into llvm-prof.\n";
- exit 1;
- }
-
- # Otherwise, pass the option on to llvm-prof
- $LLVMProfOpts .= " " . $_;
-}
-
-die "Must specify LLVM bitcode file as first argument!" if (@ARGV == 0);
-
-my $BytecodeFile = $ARGV[0];
-
-shift @ARGV;
-
-my $libdir = `llvm-config --libdir`;
-chomp $libdir;
-
-my $LibProfPath = $libdir . "/libprofile_rt.so";
-
-system "opt -q -f $ProfilePass $BytecodeFile -o $BytecodeFile.inst";
-system "lli -fake-argv0 '$BytecodeFile' -load $LibProfPath " .
- "$BytecodeFile.inst $ProgramOpts " . (join ' ', @ARGV);
-system "rm $BytecodeFile.inst";
-system "llvm-prof $LLVMProfOpts $BytecodeFile $ProfileFile";
diff --git a/utils/release/tag.sh b/utils/release/tag.sh
index 5e3f69a..6c5039d 100755
--- a/utils/release/tag.sh
+++ b/utils/release/tag.sh
@@ -17,7 +17,7 @@ set -e
release=""
rc=""
rebranch="no"
-projects="llvm cfe dragonegg test-suite compiler-rt libcxx clang-tools-extra polly lldb"
+projects="llvm cfe dragonegg test-suite compiler-rt libcxx clang-tools-extra polly lldb lld"
base_url="https://llvm.org/svn/llvm-project"
diff --git a/utils/release/test-release.sh b/utils/release/test-release.sh
index 6c17b46..91dac4c 100755
--- a/utils/release/test-release.sh
+++ b/utils/release/test-release.sh
@@ -26,6 +26,8 @@ Base_url="http://llvm.org/svn/llvm-project"
Release=""
Release_no_dot=""
RC=""
+Triple=""
+use_gzip="no"
do_checkout="yes"
do_ada="no"
do_clang="yes"
@@ -44,6 +46,7 @@ function usage() {
echo " -release X.Y The release number to test."
echo " -rc NUM The pre-release candidate number."
echo " -final The final release candidate."
+ echo " -triple TRIPLE The target triple for this machine."
echo " -j NUM Number of compile jobs to run. [default: 3]"
echo " -build-dir DIR Directory to perform testing in. [default: pwd]"
echo " -no-checkout Don't checkout the sources from SVN."
@@ -56,6 +59,7 @@ function usage() {
echo " -test-debug Test the debug build. [default: no]"
echo " -test-asserts Test with asserts on. [default: no]"
echo " -no-compare-files Don't test that phase 2 and 3 files are identical."
+ echo " -use-gzip Use gzip instead of xz."
}
while [ $# -gt 0 ]; do
@@ -72,6 +76,10 @@ while [ $# -gt 0 ]; do
-final | --final )
RC=final
;;
+ -triple | --triple )
+ shift
+ Triple="$1"
+ ;;
-j* )
NumJobs="`echo $1 | sed -e 's,-j\([0-9]*\),\1,g'`"
if [ -z "$NumJobs" ]; then
@@ -113,6 +121,9 @@ while [ $# -gt 0 ]; do
-no-compare-files | --no-compare-files )
do_compare="no"
;;
+ -use-gzip | --use-gzip )
+ use_gzip="yes"
+ ;;
-help | --help | -h | --h | -\? )
usage
exit 0
@@ -135,6 +146,10 @@ if [ -z "$RC" ]; then
echo "error: no release candidate number specified"
exit 1
fi
+if [ -z "$Triple" ]; then
+ echo "error: no target triple specified"
+ exit 1
+fi
# Figure out how many make processes to run.
if [ -z "$NumJobs" ]; then
@@ -159,6 +174,13 @@ cd $BuildDir
LogDir=$BuildDir/logs
mkdir -p $LogDir
+# Final package name.
+Package=clang+llvm-$Release
+if [ $RC != "final" ]; then
+ Package=$Package-$RC
+fi
+Package=$Package-$Triple
+
# Find compilers.
if [ "$do_dragonegg" = "yes" ]; then
gcc_compiler="$GCC"
@@ -180,6 +202,20 @@ if [ "$do_dragonegg" = "yes" ]; then
fi
fi
+# Make sure that a required program is available
+function check_program_exists() {
+ local program="$1"
+ if ! type -P $program > /dev/null 2>&1 ; then
+ echo "program '$1' not found !"
+ exit 1
+ fi
+}
+
+if [ `uname -s` != "Darwin" ]; then
+ check_program_exists 'chrpath'
+ check_program_exists 'file'
+ check_program_exists 'objdump'
+fi
# Make sure that the URLs are valid.
function check_valid_urls() {
@@ -328,6 +364,38 @@ function test_llvmCore() {
cd $BuildDir
}
+# Clean RPATH. Libtool adds the build directory to the search path, which is
+# not necessary --- and even harmful --- for the binary packages we release.
+function clean_RPATH() {
+ if [ `uname -s` = "Darwin" ]; then
+ return
+ fi
+ local InstallPath="$1"
+ for Candidate in `find $InstallPath/{bin,lib} -type f`; do
+ if file $Candidate | grep ELF | egrep 'executable|shared object' > /dev/null 2>&1 ; then
+ rpath=`objdump -x $Candidate | grep 'RPATH' | sed -e's/^ *RPATH *//'`
+ if [ -n "$rpath" ]; then
+ newrpath=`echo $rpath | sed -e's/.*\(\$ORIGIN[^:]*\).*/\1/'`
+ chrpath -r $newrpath $Candidate 2>&1 > /dev/null 2>&1
+ fi
+ fi
+ done
+}
+
+# Create a package of the release binaries.
+function package_release() {
+ cwd=`pwd`
+ cd $BuildDir/Phase3/Release
+ mv llvmCore-$Release-$RC.install $Package
+ if [ "$use_gzip" = "yes" ]; then
+ tar cfz $BuildDir/$Package.tar.gz $Package
+ else
+ tar cfJ $BuildDir/$Package.tar.xz $Package
+ fi
+ mv $Package llvmCore-$Release-$RC.install
+ cd $cwd
+}
+
set -e # Exit if any command fails
if [ "$do_checkout" = "yes" ]; then
@@ -415,6 +483,7 @@ for Flavor in $Flavors ; do
$llvmCore_phase1_objdir $llvmCore_phase1_installdir
build_llvmCore 1 $Flavor \
$llvmCore_phase1_objdir
+ clean_RPATH $llvmCore_phase1_installdir
# Test clang
if [ "$do_clang" = "yes" ]; then
@@ -427,6 +496,7 @@ for Flavor in $Flavors ; do
$llvmCore_phase2_objdir $llvmCore_phase2_installdir
build_llvmCore 2 $Flavor \
$llvmCore_phase2_objdir
+ clean_RPATH $llvmCore_phase2_installdir
########################################################################
# Phase 3: Build llvmCore with newly built clang from phase 2.
@@ -437,6 +507,7 @@ for Flavor in $Flavors ; do
$llvmCore_phase3_objdir $llvmCore_phase3_installdir
build_llvmCore 3 $Flavor \
$llvmCore_phase3_objdir
+ clean_RPATH $llvmCore_phase3_installdir
########################################################################
# Testing: Test phase 3
@@ -478,6 +549,7 @@ for Flavor in $Flavors ; do
build_llvmCore 2 $Flavor \
$llvmCore_de_phase2_objdir
build_dragonegg 2 $Flavor $llvmCore_de_phase2_installdir $dragonegg_phase2_objdir
+ clean_RPATH $llvmCore_de_phase2_installdir
########################################################################
# Phase 3: Build llvmCore with newly built dragonegg from phase 2.
@@ -489,6 +561,7 @@ for Flavor in $Flavors ; do
build_llvmCore 3 $Flavor \
$llvmCore_de_phase3_objdir
build_dragonegg 3 $Flavor $llvmCore_de_phase3_installdir $dragonegg_phase3_objdir
+ clean_RPATH $llvmCore_de_phase3_installdir
########################################################################
# Testing: Test phase 3
@@ -518,9 +591,16 @@ for Flavor in $Flavors ; do
done
) 2>&1 | tee $LogDir/testing.$Release-$RC.log
+package_release
+
set +e
# Woo hoo!
echo "### Testing Finished ###"
+if [ "$use_gzip" = "yes" ]; then
+ echo "### Package: $Package.tar.gz"
+else
+ echo "### Package: $Package.tar.xz"
+fi
echo "### Logs: $LogDir"
exit 0
diff --git a/utils/test_debuginfo.pl b/utils/test_debuginfo.pl
index 0832a33..a6b6137 100755
--- a/utils/test_debuginfo.pl
+++ b/utils/test_debuginfo.pl
@@ -11,8 +11,13 @@
# and run the script generated from source program comments. Finally,
# the debugger output is checked, using FileCheck, to validate
# debugging information.
+#
+# On Darwin the default is to use the llgdb.py wrapper script which
+# translates gdb commands into their lldb equivalents.
use File::Basename;
+use Config;
+use Cwd;
my $testcase_file = $ARGV[0];
my $executable_file = $ARGV[1];
@@ -23,6 +28,11 @@ my $output_dir = dirname $executable_file;
my $debugger_script_file = "$output_dir/$input_filename.debugger.script";
my $output_file = "$output_dir/$input_filename.gdb.output";
+my %cmd_map = ();
+# Assume lldb to be the debugger on Darwin.
+my $use_lldb = 0;
+$use_lldb = 1 if ($Config{osname} eq "darwin");
+
# Extract debugger commands from testcase. They are marked with DEBUGGER:
# at the beginning of a comment line.
open(INPUT, $testcase_file);
@@ -44,8 +54,15 @@ close(OUTPUT);
# setup debugger and debugger options to run a script.
my $my_debugger = $ENV{'DEBUGGER'};
if (!$my_debugger) {
- $my_debugger = "gdb";
+ if ($use_lldb) {
+ my $path = dirname(Cwd::abs_path($0));
+ $my_debugger = "/usr/bin/env python $path/../tools/clang/test/debuginfo-tests/llgdb.py";
+ } else {
+ $my_debugger = "gdb";
+ }
}
+
+# quiet / exit after cmdline / no init file / execute script
my $debugger_options = "-q -batch -n -x";
# run debugger and capture output.
diff --git a/utils/unittest/CMakeLists.txt b/utils/unittest/CMakeLists.txt
index 8bdfee1..fd1a048 100644
--- a/utils/unittest/CMakeLists.txt
+++ b/utils/unittest/CMakeLists.txt
@@ -14,6 +14,7 @@
# Where gtest's .h files can be found.
include_directories(
googletest/include
+ googletest
)
if(WIN32)
@@ -38,13 +39,7 @@ if(MSVC AND MSVC_VERSION EQUAL 1700)
endif ()
add_llvm_library(gtest
- googletest/gtest.cc
- googletest/gtest-death-test.cc
- googletest/gtest-filepath.cc
- googletest/gtest-port.cc
- googletest/gtest-printers.cc
- googletest/gtest-test-part.cc
- googletest/gtest-typed-test.cc
+ googletest/src/gtest-all.cc
)
add_llvm_library(gtest_main
diff --git a/utils/unittest/googletest/Makefile b/utils/unittest/googletest/Makefile
index bf73670..3d85e7d 100644
--- a/utils/unittest/googletest/Makefile
+++ b/utils/unittest/googletest/Makefile
@@ -19,6 +19,7 @@ REQUIRES_RTTI = 1
# unittests/Makefile.unittest and ../UnitTestMain/Makefile; ensure that any
# changes are made to both.
CPP.Flags += -I$(LLVM_SRC_ROOT)/utils/unittest/googletest/include
+CPP.Flags += -I$(LLVM_SRC_ROOT)/utils/unittest/googletest
CPP.Flags += $(NO_MISSING_FIELD_INITIALIZERS) $(NO_VARIADIC_MACROS)
CPP.Flags += -DGTEST_HAS_RTTI=0
# libstdc++'s TR1 <tuple> header depends on RTTI and uses C++'0x features not
@@ -36,6 +37,6 @@ endif
NO_INSTALL = 1
-SOURCES = $(filter-out gtest-all.cc, $(notdir $(wildcard $(PROJ_SRC_DIR)/*.cc)))
+SOURCES = src/gtest-all.cc
include $(LEVEL)/Makefile.common
diff --git a/utils/unittest/googletest/README.LLVM b/utils/unittest/googletest/README.LLVM
index 3565a32..1a6f0f5 100644
--- a/utils/unittest/googletest/README.LLVM
+++ b/utils/unittest/googletest/README.LLVM
@@ -10,23 +10,11 @@ Cleaned up as follows:
$ rm -f aclocal* CMakeLists.txt configure* Makefile* CHANGES CONTRIBUTORS README
$ rm -rf build-aux cmake codegear fused-src m4 make msvc samples scripts test xcode
$ rm -f `find . -name \*\.pump`
+$ rm -f src/gtest_main.cc
-# Move all the source files to the current directory
-$ mv src/* .
-$ rmdir src
-
-# Move extra headers into the already-existing internal headers dir
-$ mv *.h include/gtest/internal/
-
-# Update paths to the included files
-$ perl -pi -e 's|^#include "src/|#include "|' gtest-all.cc
-$ perl -pi -e 's|^#include "src/|#include "gtest/internal/|' *.cc
-
-$ rm -f gtest_main.cc
-
+# Put the license in the consistent place for LLVM.
$ mv COPYING LICENSE.TXT
-
Modified as follows:
* To GTestStreamToHelper in include/gtest/internal/gtest-internal.h,
added the ability to stream with raw_os_ostream.
diff --git a/utils/unittest/googletest/include/gtest/gtest-test-part.h b/utils/unittest/googletest/include/gtest/gtest-test-part.h
index 8aeea14..98e8b84 100644
--- a/utils/unittest/googletest/include/gtest/gtest-test-part.h
+++ b/utils/unittest/googletest/include/gtest/gtest-test-part.h
@@ -142,7 +142,7 @@ class GTEST_API_ TestPartResultArray {
// This interface knows how to report a test part result.
class TestPartResultReporterInterface {
public:
- virtual ~TestPartResultReporterInterface() {}
+ virtual ~TestPartResultReporterInterface();
virtual void ReportTestPartResult(const TestPartResult& result) = 0;
};
diff --git a/utils/unittest/googletest/include/gtest/gtest.h b/utils/unittest/googletest/include/gtest/gtest.h
index 1734c44..07ed92b 100644
--- a/utils/unittest/googletest/include/gtest/gtest.h
+++ b/utils/unittest/googletest/include/gtest/gtest.h
@@ -910,7 +910,7 @@ class GTEST_API_ TestCase {
class Environment {
public:
// The d'tor is virtual as we need to subclass Environment.
- virtual ~Environment() {}
+ virtual ~Environment();
// Override this to define how to set up the environment.
virtual void SetUp() {}
@@ -928,7 +928,7 @@ class Environment {
// the order the corresponding events are fired.
class TestEventListener {
public:
- virtual ~TestEventListener() {}
+ virtual ~TestEventListener();
// Fired before any test activity starts.
virtual void OnTestProgramStart(const UnitTest& unit_test) = 0;
@@ -980,6 +980,7 @@ class TestEventListener {
// comments about each method please see the definition of TestEventListener
// above.
class EmptyTestEventListener : public TestEventListener {
+ virtual void anchor();
public:
virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {}
virtual void OnTestIterationStart(const UnitTest& /*unit_test*/,
diff --git a/utils/unittest/googletest/include/gtest/internal/gtest-death-test-internal.h b/utils/unittest/googletest/include/gtest/internal/gtest-death-test-internal.h
index 7bac2bd..8d53c45 100644
--- a/utils/unittest/googletest/include/gtest/internal/gtest-death-test-internal.h
+++ b/utils/unittest/googletest/include/gtest/internal/gtest-death-test-internal.h
@@ -79,7 +79,7 @@ class GTEST_API_ DeathTest {
static bool Create(const char* statement, const RE* regex,
const char* file, int line, DeathTest** test);
DeathTest();
- virtual ~DeathTest() { }
+ virtual ~DeathTest();
// A helper class that aborts a death test when it's deleted.
class ReturnSentinel {
@@ -139,7 +139,7 @@ class GTEST_API_ DeathTest {
// Factory interface for death tests. May be mocked out for testing.
class DeathTestFactory {
public:
- virtual ~DeathTestFactory() { }
+ virtual ~DeathTestFactory();
virtual bool Create(const char* statement, const RE* regex,
const char* file, int line, DeathTest** test) = 0;
};
diff --git a/utils/unittest/googletest/include/gtest/internal/gtest-internal.h b/utils/unittest/googletest/include/gtest/internal/gtest-internal.h
index a94bf28..63f72ac 100644
--- a/utils/unittest/googletest/include/gtest/internal/gtest-internal.h
+++ b/utils/unittest/googletest/include/gtest/internal/gtest-internal.h
@@ -105,6 +105,7 @@
#if !GTEST_NO_LLVM_RAW_OSTREAM
namespace llvm {
class convertible_fwd_ostream : public std::ostream {
+ virtual void anchor();
raw_os_ostream ros_;
public:
@@ -536,7 +537,7 @@ GTEST_API_ TypeId GetTestTypeId();
// of a Test object.
class TestFactoryBase {
public:
- virtual ~TestFactoryBase() {}
+ virtual ~TestFactoryBase();
// Creates a test instance to run. The instance is both created and destroyed
// within TestInfoImpl::Run()
diff --git a/utils/unittest/googletest/include/gtest/internal/gtest-param-util.h b/utils/unittest/googletest/include/gtest/internal/gtest-param-util.h
index 0ef9718..3bb2ffb 100644
--- a/utils/unittest/googletest/include/gtest/internal/gtest-param-util.h
+++ b/utils/unittest/googletest/include/gtest/internal/gtest-param-util.h
@@ -414,7 +414,7 @@ class TestMetaFactory
// and calls RegisterTests() on each of them when asked.
class ParameterizedTestCaseInfoBase {
public:
- virtual ~ParameterizedTestCaseInfoBase() {}
+ virtual ~ParameterizedTestCaseInfoBase();
// Base part of test case name for display purposes.
virtual const string& GetTestCaseName() const = 0;
diff --git a/utils/unittest/googletest/include/gtest/internal/gtest-port.h b/utils/unittest/googletest/include/gtest/internal/gtest-port.h
index 58f6caf..32fd9c6 100644
--- a/utils/unittest/googletest/include/gtest/internal/gtest-port.h
+++ b/utils/unittest/googletest/include/gtest/internal/gtest-port.h
@@ -1116,7 +1116,7 @@ class Notification {
// problem.
class ThreadWithParamBase {
public:
- virtual ~ThreadWithParamBase() {}
+ virtual ~ThreadWithParamBase();
virtual void Run() = 0;
};
@@ -1290,7 +1290,7 @@ typedef GTestMutexLock MutexLock;
// ThreadLocalValueHolderBase.
class ThreadLocalValueHolderBase {
public:
- virtual ~ThreadLocalValueHolderBase() {}
+ virtual ~ThreadLocalValueHolderBase();
};
// Called by pthread to delete thread-local data stored by
diff --git a/utils/unittest/googletest/gtest-all.cc b/utils/unittest/googletest/src/gtest-all.cc
index 97753e5..0a9cee5 100644
--- a/utils/unittest/googletest/gtest-all.cc
+++ b/utils/unittest/googletest/src/gtest-all.cc
@@ -39,10 +39,10 @@
#include "gtest/gtest.h"
// The following lines pull in the real gtest *.cc files.
-#include "gtest.cc"
-#include "gtest-death-test.cc"
-#include "gtest-filepath.cc"
-#include "gtest-port.cc"
-#include "gtest-printers.cc"
-#include "gtest-test-part.cc"
-#include "gtest-typed-test.cc"
+#include "src/gtest.cc"
+#include "src/gtest-death-test.cc"
+#include "src/gtest-filepath.cc"
+#include "src/gtest-port.cc"
+#include "src/gtest-printers.cc"
+#include "src/gtest-test-part.cc"
+#include "src/gtest-typed-test.cc"
diff --git a/utils/unittest/googletest/gtest-death-test.cc b/utils/unittest/googletest/src/gtest-death-test.cc
index bf7e32c..314dba2 100644
--- a/utils/unittest/googletest/gtest-death-test.cc
+++ b/utils/unittest/googletest/src/gtest-death-test.cc
@@ -63,7 +63,7 @@
// prevent a user from accidentally including gtest-internal-inl.h in
// his code.
#define GTEST_IMPLEMENTATION_ 1
-#include "gtest/internal/gtest-internal-inl.h"
+#include "src/gtest-internal-inl.h"
#undef GTEST_IMPLEMENTATION_
namespace testing {
@@ -300,6 +300,9 @@ DeathTest::DeathTest() {
}
}
+// Pin the vtable to this file.
+DeathTest::~DeathTest() {}
+
// Creates and returns a death test by dispatching to the current
// death test factory.
bool DeathTest::Create(const char* statement, const RE* regex,
@@ -1091,6 +1094,9 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex,
return true;
}
+// Pin the vtable to this file.
+DeathTestFactory::~DeathTestFactory() {}
+
// Splits a given string on a given delimiter, populating a given
// vector with the fields. GTEST_HAS_DEATH_TEST implies that we have
// ::std::string, so we can use it here.
diff --git a/utils/unittest/googletest/gtest-filepath.cc b/utils/unittest/googletest/src/gtest-filepath.cc
index ad1bab8..ad1bab8 100644
--- a/utils/unittest/googletest/gtest-filepath.cc
+++ b/utils/unittest/googletest/src/gtest-filepath.cc
diff --git a/utils/unittest/googletest/include/gtest/internal/gtest-internal-inl.h b/utils/unittest/googletest/src/gtest-internal-inl.h
index 6554cfc..1bae630 100644
--- a/utils/unittest/googletest/include/gtest/internal/gtest-internal-inl.h
+++ b/utils/unittest/googletest/src/gtest-internal-inl.h
@@ -408,7 +408,7 @@ GTEST_API_ FilePath GetCurrentExecutableName();
class OsStackTraceGetterInterface {
public:
OsStackTraceGetterInterface() {}
- virtual ~OsStackTraceGetterInterface() {}
+ virtual ~OsStackTraceGetterInterface();
// Returns the current OS stack trace as a String. Parameters:
//
diff --git a/utils/unittest/googletest/gtest-port.cc b/utils/unittest/googletest/src/gtest-port.cc
index 3c32ff1..94fc57f 100644
--- a/utils/unittest/googletest/gtest-port.cc
+++ b/utils/unittest/googletest/src/gtest-port.cc
@@ -62,7 +62,7 @@
// prevent a user from accidentally including gtest-internal-inl.h in
// his code.
#define GTEST_IMPLEMENTATION_ 1
-#include "gtest/internal/gtest-internal-inl.h"
+#include "src/gtest-internal-inl.h"
#undef GTEST_IMPLEMENTATION_
namespace testing {
@@ -746,5 +746,19 @@ const char* StringFromGTestEnv(const char* flag, const char* default_value) {
return value == NULL ? default_value : value;
}
+// Pin the vtables to this file.
+#if GTEST_HAS_PTHREAD
+ThreadWithParamBase::~ThreadWithParamBase() {}
+ThreadLocalValueHolderBase::~ThreadLocalValueHolderBase() {}
+#endif
+TestFactoryBase::~TestFactoryBase() {}
+
} // namespace internal
} // namespace testing
+
+// Pin the vtable to this file.
+#if !GTEST_NO_LLVM_RAW_OSTREAM
+namespace llvm {
+void convertible_fwd_ostream::anchor() {}
+}
+#endif
diff --git a/utils/unittest/googletest/gtest-printers.cc b/utils/unittest/googletest/src/gtest-printers.cc
index 205a394..205a394 100644
--- a/utils/unittest/googletest/gtest-printers.cc
+++ b/utils/unittest/googletest/src/gtest-printers.cc
diff --git a/utils/unittest/googletest/gtest-test-part.cc b/utils/unittest/googletest/src/gtest-test-part.cc
index 1612780..5ddc67c 100644
--- a/utils/unittest/googletest/gtest-test-part.cc
+++ b/utils/unittest/googletest/src/gtest-test-part.cc
@@ -39,7 +39,7 @@
// prevent a user from accidentally including gtest-internal-inl.h in
// his code.
#define GTEST_IMPLEMENTATION_ 1
-#include "gtest/internal/gtest-internal-inl.h"
+#include "src/gtest-internal-inl.h"
#undef GTEST_IMPLEMENTATION_
namespace testing {
diff --git a/utils/unittest/googletest/gtest-typed-test.cc b/utils/unittest/googletest/src/gtest-typed-test.cc
index a5cc88f..a5cc88f 100644
--- a/utils/unittest/googletest/gtest-typed-test.cc
+++ b/utils/unittest/googletest/src/gtest-typed-test.cc
diff --git a/utils/unittest/googletest/gtest.cc b/utils/unittest/googletest/src/gtest.cc
index eb5c68c..bf850c6 100644
--- a/utils/unittest/googletest/gtest.cc
+++ b/utils/unittest/googletest/src/gtest.cc
@@ -129,7 +129,7 @@
// prevent a user from accidentally including gtest-internal-inl.h in
// his code.
#define GTEST_IMPLEMENTATION_ 1
-#include "gtest/internal/gtest-internal-inl.h"
+#include "src/gtest-internal-inl.h"
#undef GTEST_IMPLEMENTATION_
#if GTEST_OS_WINDOWS
@@ -4863,4 +4863,14 @@ void InitGoogleTest(int* argc, wchar_t** argv) {
internal::InitGoogleTestImpl(argc, argv);
}
+// Pin the vtables to this file.
+Environment::~Environment() {}
+TestPartResultReporterInterface::~TestPartResultReporterInterface() {}
+TestEventListener::~TestEventListener() {}
+void EmptyTestEventListener::anchor() {}
+namespace internal {
+OsStackTraceGetterInterface::~OsStackTraceGetterInterface() {}
+ParameterizedTestCaseInfoBase::~ParameterizedTestCaseInfoBase() {}
+}
+
} // namespace testing
diff --git a/utils/vim/llvm.vim b/utils/vim/llvm.vim
index 6c87cff..c2ec57c 100644
--- a/utils/vim/llvm.vim
+++ b/utils/vim/llvm.vim
@@ -22,17 +22,18 @@ syn match llvmType /\<i\d\+\>/
" Instructions.
" The true and false tokens can be used for comparison opcodes, but it's
" much more common for these tokens to be used for boolean constants.
-syn keyword llvmStatement add alloca and arcp ashr atomicrmw bitcast br call
-syn keyword llvmStatement cmpxchg eq exact extractelement extractvalue fadd fast
-syn keyword llvmStatement fcmp fdiv fence fmul fpext fptosi fptoui fptrunc free
-syn keyword llvmStatement frem fsub getelementptr icmp inbounds indirectbr
-syn keyword llvmStatement insertelement insertvalue inttoptr invoke landingpad
-syn keyword llvmStatement load lshr malloc max min mul nand ne ninf nnan nsw nsz
-syn keyword llvmStatement nuw oeq oge ogt ole olt one or ord phi ptrtoint resume
-syn keyword llvmStatement ret sdiv select sext sge sgt shl shufflevector sitofp
-syn keyword llvmStatement sle slt srem store sub switch trunc udiv ueq uge ugt
-syn keyword llvmStatement uitofp ule ult umax umin une uno unreachable unwind
-syn keyword llvmStatement urem va_arg xchg xor zext
+syn keyword llvmStatement add addrspacecast alloca and arcp ashr atomicrmw
+syn keyword llvmStatement bitcast br call cmpxchg eq exact extractelement
+syn keyword llvmStatement extractvalue fadd fast fcmp fdiv fence fmul fpext
+syn keyword llvmStatement fptosi fptoui fptrunc free frem fsub getelementptr
+syn keyword llvmStatement icmp inbounds indirectbr insertelement insertvalue
+syn keyword llvmStatement inttoptr invoke landingpad load lshr malloc max min
+syn keyword llvmStatement mul nand ne ninf nnan nsw nsz nuw oeq oge ogt ole
+syn keyword llvmStatement olt one or ord phi ptrtoint resume ret sdiv select
+syn keyword llvmStatement sext sge sgt shl shufflevector sitofp sle slt srem
+syn keyword llvmStatement store sub switch trunc udiv ueq uge ugt uitofp ule ult
+syn keyword llvmStatement umax umin une uno unreachable unwind urem va_arg
+syn keyword llvmStatement xchg xor zext
" Keywords.
syn keyword llvmKeyword acq_rel acquire sanitize_address addrspace alias align
@@ -43,12 +44,12 @@ syn keyword llvmKeyword constant datalayout declare default define deplibs
syn keyword llvmKeyword dllexport dllimport except extern_weak external fastcc
syn keyword llvmKeyword filter gc global hidden initialexec inlinehint inreg
syn keyword llvmKeyword intel_ocl_bicc inteldialect internal linker_private
-syn keyword llvmKeyword linker_private_weak linker_private_weak_def_auto
-syn keyword llvmKeyword linkonce linkonce_odr linkonce_odr_auto_hide
+syn keyword llvmKeyword linker_private_weak
+syn keyword llvmKeyword linkonce linkonce_odr
syn keyword llvmKeyword localdynamic localexec minsize module monotonic
syn keyword llvmKeyword msp430_intrcc naked nest noalias nocapture
syn keyword llvmKeyword noimplicitfloat noinline nonlazybind noredzone noreturn
-syn keyword llvmKeyword nounwind optsize personality private protected
+syn keyword llvmKeyword nounwind optnone optsize personality private protected
syn keyword llvmKeyword ptx_device ptx_kernel readnone readonly release
syn keyword llvmKeyword returns_twice sanitize_thread sanitize_memory
syn keyword llvmKeyword section seq_cst sideeffect signext singlethread
diff --git a/utils/yaml-bench/YAMLBench.cpp b/utils/yaml-bench/YAMLBench.cpp
index eef4a72..f335605 100644
--- a/utils/yaml-bench/YAMLBench.cpp
+++ b/utils/yaml-bench/YAMLBench.cpp
@@ -63,6 +63,20 @@ static raw_ostream &operator <<(raw_ostream &os, const indent &in) {
return os;
}
+/// \brief Pretty print a tag by replacing tag:yaml.org,2002: with !!.
+static std::string prettyTag(yaml::Node *N) {
+ std::string Tag = N->getVerbatimTag();
+ if (StringRef(Tag).startswith("tag:yaml.org,2002:")) {
+ std::string Ret = "!!";
+ Ret += StringRef(Tag).substr(18);
+ return llvm_move(Ret);
+ }
+ std::string Ret = "!<";
+ Ret += Tag;
+ Ret += ">";
+ return Ret;
+}
+
static void dumpNode( yaml::Node *n
, unsigned Indent = 0
, bool SuppressFirstIndent = false) {
@@ -76,9 +90,9 @@ static void dumpNode( yaml::Node *n
if (yaml::ScalarNode *sn = dyn_cast<yaml::ScalarNode>(n)) {
SmallString<32> Storage;
StringRef Val = sn->getValue(Storage);
- outs() << "!!str \"" << yaml::escape(Val) << "\"";
+ outs() << prettyTag(n) << " \"" << yaml::escape(Val) << "\"";
} else if (yaml::SequenceNode *sn = dyn_cast<yaml::SequenceNode>(n)) {
- outs() << "!!seq [\n";
+ outs() << prettyTag(n) << " [\n";
++Indent;
for (yaml::SequenceNode::iterator i = sn->begin(), e = sn->end();
i != e; ++i) {
@@ -88,7 +102,7 @@ static void dumpNode( yaml::Node *n
--Indent;
outs() << indent(Indent) << "]";
} else if (yaml::MappingNode *mn = dyn_cast<yaml::MappingNode>(n)) {
- outs() << "!!map {\n";
+ outs() << prettyTag(n) << " {\n";
++Indent;
for (yaml::MappingNode::iterator i = mn->begin(), e = mn->end();
i != e; ++i) {
@@ -104,7 +118,7 @@ static void dumpNode( yaml::Node *n
} else if (yaml::AliasNode *an = dyn_cast<yaml::AliasNode>(n)){
outs() << "*" << an->getName();
} else if (dyn_cast<yaml::NullNode>(n)) {
- outs() << "!!null null";
+ outs() << prettyTag(n) << " null";
}
}