summaryrefslogtreecommitdiffstats
path: root/utils
diff options
context:
space:
mode:
Diffstat (limited to 'utils')
-rw-r--r--utils/FileCheck/FileCheck.cpp286
-rw-r--r--utils/FileUpdate/FileUpdate.cpp4
-rwxr-xr-xutils/GenLibDeps.pl2
-rw-r--r--utils/KillTheDoctor/KillTheDoctor.cpp7
-rw-r--r--utils/PerfectShuffle/PerfectShuffle.cpp6
-rw-r--r--utils/TableGen/AsmMatcherEmitter.cpp36
-rw-r--r--utils/TableGen/AsmWriterEmitter.cpp19
-rw-r--r--utils/TableGen/CMakeLists.txt3
-rw-r--r--utils/TableGen/CTagsEmitter.cpp99
-rw-r--r--utils/TableGen/CodeEmitterGen.cpp2
-rw-r--r--utils/TableGen/CodeGenDAGPatterns.cpp219
-rw-r--r--utils/TableGen/CodeGenDAGPatterns.h14
-rw-r--r--utils/TableGen/CodeGenInstruction.cpp6
-rw-r--r--utils/TableGen/CodeGenInstruction.h4
-rw-r--r--utils/TableGen/CodeGenIntrinsics.h2
-rw-r--r--utils/TableGen/CodeGenMapTable.cpp9
-rw-r--r--utils/TableGen/CodeGenRegisters.cpp49
-rw-r--r--utils/TableGen/CodeGenRegisters.h27
-rw-r--r--utils/TableGen/CodeGenSchedule.cpp300
-rw-r--r--utils/TableGen/CodeGenSchedule.h86
-rw-r--r--utils/TableGen/CodeGenTarget.cpp14
-rw-r--r--utils/TableGen/CodeGenTarget.h10
-rw-r--r--utils/TableGen/DAGISelMatcher.cpp4
-rw-r--r--utils/TableGen/DAGISelMatcher.h4
-rw-r--r--utils/TableGen/DAGISelMatcherEmitter.cpp4
-rw-r--r--utils/TableGen/DAGISelMatcherGen.cpp57
-rw-r--r--utils/TableGen/DFAPacketizerEmitter.cpp11
-rw-r--r--utils/TableGen/DisassemblerEmitter.cpp5
-rw-r--r--utils/TableGen/EDEmitter.cpp1011
-rw-r--r--utils/TableGen/FixedLenDecoderEmitter.cpp9
-rw-r--r--utils/TableGen/InstrInfoEmitter.cpp6
-rw-r--r--utils/TableGen/IntrinsicEmitter.cpp71
-rw-r--r--utils/TableGen/OptParserEmitter.cpp266
-rw-r--r--utils/TableGen/PseudoLoweringEmitter.cpp1
-rw-r--r--utils/TableGen/RegisterInfoEmitter.cpp110
-rw-r--r--utils/TableGen/SequenceToOffsetTable.h4
-rw-r--r--utils/TableGen/SetTheory.cpp2
-rw-r--r--utils/TableGen/SetTheory.h2
-rw-r--r--utils/TableGen/StringToOffsetTable.h2
-rw-r--r--utils/TableGen/SubtargetEmitter.cpp206
-rw-r--r--utils/TableGen/TableGen.cpp19
-rw-r--r--utils/TableGen/TableGenBackends.h3
-rw-r--r--utils/TableGen/X86DisassemblerShared.h2
-rw-r--r--utils/TableGen/X86DisassemblerTables.cpp5
-rw-r--r--utils/TableGen/X86DisassemblerTables.h2
-rw-r--r--utils/TableGen/X86RecognizableInstr.cpp33
-rw-r--r--utils/TableGen/X86RecognizableInstr.h8
-rw-r--r--utils/TableGen/tdtags453
-rwxr-xr-xutils/UpdateCMakeLists.pl2
-rwxr-xr-xutils/buildit/build_llvm164
-rwxr-xr-xutils/clang-parse-diagnostics-file36
-rw-r--r--utils/emacs/llvm-mode.el9
-rwxr-xr-xutils/git/find-rev8
-rw-r--r--utils/kate/llvm.xml1
-rw-r--r--utils/lit/MANIFEST.in7
-rw-r--r--utils/lit/TODO17
-rw-r--r--utils/lit/lit/ExampleTests/Clang/lit.cfg2
-rw-r--r--utils/lit/lit/ExampleTests/LLVM.InTree/test/Bar/data.txt1
-rw-r--r--utils/lit/lit/ExampleTests/LLVM.InTree/test/Bar/dg.exp6
-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.cfg75
-rw-r--r--utils/lit/lit/ExampleTests/LLVM.InTree/test/lit.site.cfg3
-rw-r--r--utils/lit/lit/ExampleTests/LLVM.InTree/test/site.exp10
-rw-r--r--utils/lit/lit/ExampleTests/LLVM.OutOfTree/obj/test/lit.site.cfg3
-rw-r--r--utils/lit/lit/ExampleTests/LLVM.OutOfTree/obj/test/site.exp10
-rw-r--r--utils/lit/lit/ExampleTests/LLVM.OutOfTree/src/test/Foo/dg.exp6
-rw-r--r--utils/lit/lit/ExampleTests/LLVM.OutOfTree/src/test/lit.cfg75
-rw-r--r--utils/lit/lit/ExampleTests/ManyTests/lit.local.cfg23
-rw-r--r--utils/lit/lit/ExampleTests/TclTest/lit.local.cfg5
-rw-r--r--utils/lit/lit/ExampleTests/TclTest/stderr-pipe.ll1
-rw-r--r--utils/lit/lit/ExampleTests/TclTest/tcl-redir-1.ll7
-rw-r--r--utils/lit/lit/ExampleTests/lit.cfg4
-rw-r--r--utils/lit/lit/LitConfig.py14
-rw-r--r--utils/lit/lit/LitFormats.py3
-rw-r--r--utils/lit/lit/ShUtil.py22
-rw-r--r--utils/lit/lit/TclUtil.py322
-rw-r--r--utils/lit/lit/Test.py4
-rw-r--r--utils/lit/lit/TestFormats.py58
-rw-r--r--utils/lit/lit/TestRunner.py180
-rw-r--r--utils/lit/lit/__init__.py2
-rw-r--r--utils/lit/lit/discovery.py234
-rwxr-xr-xutils/lit/lit/main.py267
-rw-r--r--utils/lit/tests/.coveragerc11
-rw-r--r--utils/lit/tests/Inputs/discovery/lit.cfg5
-rw-r--r--utils/lit/tests/Inputs/discovery/subdir/lit.local.cfg1
-rw-r--r--utils/lit/tests/Inputs/discovery/subdir/test-three.py1
-rw-r--r--utils/lit/tests/Inputs/discovery/subsuite/lit.cfg5
-rw-r--r--utils/lit/tests/Inputs/discovery/subsuite/test-one.txt1
-rw-r--r--utils/lit/tests/Inputs/discovery/subsuite/test-two.txt1
-rw-r--r--utils/lit/tests/Inputs/discovery/test-one.txt1
-rw-r--r--utils/lit/tests/Inputs/discovery/test-two.txt1
-rw-r--r--utils/lit/tests/Inputs/shtest-format/external_shell/fail.txt3
-rw-r--r--utils/lit/tests/Inputs/shtest-format/external_shell/lit.local.cfg1
-rw-r--r--utils/lit/tests/Inputs/shtest-format/external_shell/pass.txt1
-rw-r--r--utils/lit/tests/Inputs/shtest-format/fail.txt1
-rw-r--r--utils/lit/tests/Inputs/shtest-format/lit.cfg7
-rw-r--r--utils/lit/tests/Inputs/shtest-format/no-test-line.txt1
-rw-r--r--utils/lit/tests/Inputs/shtest-format/pass.txt1
-rw-r--r--utils/lit/tests/Inputs/shtest-format/requires-missing.txt2
-rw-r--r--utils/lit/tests/Inputs/shtest-format/requires-present.txt2
-rw-r--r--utils/lit/tests/Inputs/shtest-format/unsupported_dir/lit.local.cfg1
-rw-r--r--utils/lit/tests/Inputs/shtest-format/unsupported_dir/some-test.txt1
-rw-r--r--utils/lit/tests/Inputs/shtest-format/xfail-feature.txt2
-rw-r--r--utils/lit/tests/Inputs/shtest-format/xfail-target.txt2
-rw-r--r--utils/lit/tests/Inputs/shtest-format/xfail.txt2
-rw-r--r--utils/lit/tests/Inputs/shtest-format/xpass.txt2
-rw-r--r--utils/lit/tests/Inputs/shtest-shell/error-0.txt3
-rw-r--r--utils/lit/tests/Inputs/shtest-shell/error-1.txt3
-rw-r--r--utils/lit/tests/Inputs/shtest-shell/error-2.txt3
-rw-r--r--utils/lit/tests/Inputs/shtest-shell/lit.cfg5
-rw-r--r--utils/lit/tests/Inputs/shtest-shell/redirects.txt41
-rw-r--r--utils/lit/tests/Inputs/shtest-shell/sequencing-0.txt28
-rw-r--r--utils/lit/tests/Inputs/shtest-shell/sequencing-1.txt2
-rwxr-xr-xutils/lit/tests/Inputs/shtest-shell/write-to-stderr.sh3
-rwxr-xr-xutils/lit/tests/Inputs/shtest-shell/write-to-stdout-and-stderr.sh4
-rw-r--r--utils/lit/tests/Inputs/unittest-adaptor/lit.cfg5
-rw-r--r--utils/lit/tests/Inputs/unittest-adaptor/test-one.txt1
-rw-r--r--utils/lit/tests/Inputs/unittest-adaptor/test-two.txt1
-rw-r--r--utils/lit/tests/discovery.py25
-rw-r--r--utils/lit/tests/lit.cfg36
-rw-r--r--utils/lit/tests/shell-parsing.py3
-rw-r--r--utils/lit/tests/shtest-format.py43
-rw-r--r--utils/lit/tests/shtest-shell.py33
-rw-r--r--utils/lit/tests/unittest-adaptor.py18
-rw-r--r--utils/lit/tests/usage.py6
-rw-r--r--utils/lit/utils/README.txt2
-rwxr-xr-xutils/lit/utils/check-coverage50
-rwxr-xr-xutils/lit/utils/check-sdist44
-rw-r--r--utils/llvm-build/llvmbuild/main.py8
-rwxr-xr-xutils/llvm-compilers-check112
-rw-r--r--utils/llvm-lit/llvm-lit.in3
-rw-r--r--utils/llvm.grm4
-rw-r--r--utils/llvm.natvis181
-rw-r--r--utils/obj2yaml/CMakeLists.txt7
-rw-r--r--utils/obj2yaml/Makefile20
-rw-r--r--utils/obj2yaml/coff2yaml.cpp362
-rw-r--r--utils/obj2yaml/obj2yaml.cpp89
-rw-r--r--utils/obj2yaml/obj2yaml.h35
-rwxr-xr-xutils/sort_includes.py87
-rw-r--r--utils/testgen/mc-bundling-x86-gen.py103
-rw-r--r--utils/textmate/README8
-rw-r--r--utils/textmate/TableGen.tmbundle/Syntaxes/TableGen.tmLanguage132
-rw-r--r--utils/textmate/TableGen.tmbundle/info.plist12
-rw-r--r--utils/unittest/UnitTestMain/TestMain.cpp2
-rw-r--r--utils/unittest/googletest/Makefile2
-rw-r--r--utils/unittest/googletest/README.LLVM3
-rw-r--r--utils/unittest/googletest/gtest-all.cc48
-rw-r--r--utils/unittest/googletest/gtest-filepath.cc2
-rw-r--r--utils/unittest/googletest/gtest-printers.cc4
-rw-r--r--utils/unittest/googletest/include/gtest/internal/gtest-internal.h9
-rw-r--r--utils/valgrind/x86_64-pc-linux-gnu.supp6
-rw-r--r--utils/vim/llvm.vim72
-rw-r--r--utils/vim/vimrc9
-rwxr-xr-xutils/wciia.py125
-rw-r--r--utils/yaml-bench/YAMLBench.cpp4
-rw-r--r--utils/yaml2obj/yaml2obj.cpp933
156 files changed, 4091 insertions, 3792 deletions
diff --git a/utils/FileCheck/FileCheck.cpp b/utils/FileCheck/FileCheck.cpp
index e791628..b0ef67a 100644
--- a/utils/FileCheck/FileCheck.cpp
+++ b/utils/FileCheck/FileCheck.cpp
@@ -17,17 +17,21 @@
//===----------------------------------------------------------------------===//
#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringMap.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Regex.h"
+#include "llvm/Support/Signals.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/Signals.h"
#include "llvm/Support/system_error.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/StringMap.h"
#include <algorithm>
+#include <map>
+#include <string>
+#include <vector>
using namespace llvm;
static cl::opt<std::string>
@@ -63,23 +67,29 @@ class Pattern {
/// RegEx - If non-empty, this is a regex pattern.
std::string RegExStr;
+ /// \brief Contains the number of line this pattern is in.
+ unsigned LineNumber;
+
/// VariableUses - Entries in this vector map to uses of a variable in the
/// pattern, e.g. "foo[[bar]]baz". In this case, the RegExStr will contain
/// "foobaz" and we'll get an entry in this vector that tells us to insert the
/// value of bar at offset 3.
std::vector<std::pair<StringRef, unsigned> > VariableUses;
- /// VariableDefs - Entries in this vector map to definitions of a variable in
- /// the pattern, e.g. "foo[[bar:.*]]baz". In this case, the RegExStr will
- /// contain "foo(.*)baz" and VariableDefs will contain the pair "bar",1. The
- /// index indicates what parenthesized value captures the variable value.
- std::vector<std::pair<StringRef, unsigned> > VariableDefs;
+ /// VariableDefs - Maps definitions of variables to their parenthesized
+ /// capture numbers.
+ /// E.g. for the pattern "foo[[bar:.*]]baz", VariableDefs will map "bar" to 1.
+ std::map<StringRef, unsigned> VariableDefs;
public:
Pattern(bool matchEOF = false) : MatchEOF(matchEOF) { }
- bool ParsePattern(StringRef PatternStr, SourceMgr &SM);
+ /// 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);
/// 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
@@ -97,17 +107,31 @@ public:
private:
static void AddFixedStringToRegEx(StringRef FixedStr, std::string &TheStr);
- bool AddRegExToRegEx(StringRef RegExStr, unsigned &CurParen, SourceMgr &SM);
+ bool AddRegExToRegEx(StringRef RS, unsigned &CurParen, SourceMgr &SM);
+ void AddBackrefToRegEx(unsigned BackrefNum);
/// ComputeMatchDistance - Compute an arbitrary estimate for the quality of
/// matching this pattern at the start of \arg Buffer; a distance of zero
/// should correspond to a perfect match.
unsigned ComputeMatchDistance(StringRef Buffer,
const StringMap<StringRef> &VariableTable) const;
+
+ /// \brief Evaluates expression and stores the result to \p Value.
+ /// \return true on success. false when the expression has invalid syntax.
+ bool EvaluateExpression(StringRef Expr, std::string &Value) const;
+
+ /// \brief Finds the closing sequence of a regex variable usage or
+ /// definition. Str has to point in the beginning of the definition
+ /// (right after the opening sequence).
+ /// \return offset of the closing sequence within Str, or npos if it was not
+ /// found.
+ size_t FindRegexVarEnd(StringRef Str);
};
-bool Pattern::ParsePattern(StringRef PatternStr, SourceMgr &SM) {
+bool Pattern::ParsePattern(StringRef PatternStr, SourceMgr &SM,
+ unsigned LineNumber) {
+ this->LineNumber = LineNumber;
PatternLoc = SMLoc::getFromPointer(PatternStr.data());
// Ignore trailing whitespace.
@@ -140,8 +164,7 @@ bool Pattern::ParsePattern(StringRef PatternStr, SourceMgr &SM) {
while (!PatternStr.empty()) {
// RegEx matches.
if (PatternStr.startswith("{{")) {
-
- // Otherwise, this is the start of a regex match. Scan for the }}.
+ // This is the start of a regex match. Scan for the }}.
size_t End = PatternStr.find("}}");
if (End == StringRef::npos) {
SM.PrintMessage(SMLoc::getFromPointer(PatternStr.data()),
@@ -171,8 +194,10 @@ bool Pattern::ParsePattern(StringRef PatternStr, SourceMgr &SM) {
// itself must be of the form "[a-zA-Z_][0-9a-zA-Z_]*", otherwise we reject
// it. This is to catch some common errors.
if (PatternStr.startswith("[[")) {
- // Verify that it is terminated properly.
- size_t End = PatternStr.find("]]");
+ // Find the closing bracket pair ending the match. End is going to be an
+ // offset relative to the beginning of the match string.
+ size_t End = FindRegexVarEnd(PatternStr.substr(2));
+
if (End == StringRef::npos) {
SM.PrintMessage(SMLoc::getFromPointer(PatternStr.data()),
SourceMgr::DK_Error,
@@ -180,8 +205,8 @@ bool Pattern::ParsePattern(StringRef PatternStr, SourceMgr &SM) {
return true;
}
- StringRef MatchStr = PatternStr.substr(2, End-2);
- PatternStr = PatternStr.substr(End+2);
+ StringRef MatchStr = PatternStr.substr(2, End);
+ PatternStr = PatternStr.substr(End+4);
// Get the regex name (e.g. "foo").
size_t NameEnd = MatchStr.find(':');
@@ -193,16 +218,31 @@ bool Pattern::ParsePattern(StringRef PatternStr, SourceMgr &SM) {
return true;
}
- // Verify that the name is well formed.
- for (unsigned i = 0, e = Name.size(); i != e; ++i)
- if (Name[i] != '_' && !isalnum(Name[i])) {
+ // Verify that the name/expression is well formed. FileCheck currently
+ // supports @LINE, @LINE+number, @LINE-number expressions. The check here
+ // is relaxed, more strict check is performed in \c EvaluateExpression.
+ bool IsExpression = false;
+ for (unsigned i = 0, e = Name.size(); i != e; ++i) {
+ if (i == 0 && Name[i] == '@') {
+ if (NameEnd != StringRef::npos) {
+ SM.PrintMessage(SMLoc::getFromPointer(Name.data()),
+ SourceMgr::DK_Error,
+ "invalid name in named regex definition");
+ return true;
+ }
+ IsExpression = true;
+ continue;
+ }
+ if (Name[i] != '_' && !isalnum(Name[i]) &&
+ (!IsExpression || (Name[i] != '+' && Name[i] != '-'))) {
SM.PrintMessage(SMLoc::getFromPointer(Name.data()+i),
SourceMgr::DK_Error, "invalid name in named regex");
return true;
}
+ }
// Name can't start with a digit.
- if (isdigit(Name[0])) {
+ if (isdigit(static_cast<unsigned char>(Name[0]))) {
SM.PrintMessage(SMLoc::getFromPointer(Name.data()), SourceMgr::DK_Error,
"invalid name in named regex");
return true;
@@ -210,12 +250,25 @@ bool Pattern::ParsePattern(StringRef PatternStr, SourceMgr &SM) {
// Handle [[foo]].
if (NameEnd == StringRef::npos) {
- VariableUses.push_back(std::make_pair(Name, RegExStr.size()));
+ // Handle variables that were defined earlier on the same line by
+ // emitting a backreference.
+ if (VariableDefs.find(Name) != VariableDefs.end()) {
+ unsigned VarParenNum = VariableDefs[Name];
+ if (VarParenNum < 1 || VarParenNum > 9) {
+ SM.PrintMessage(SMLoc::getFromPointer(Name.data()),
+ SourceMgr::DK_Error,
+ "Can't back-reference more than 9 variables");
+ return true;
+ }
+ AddBackrefToRegEx(VarParenNum);
+ } else {
+ VariableUses.push_back(std::make_pair(Name, RegExStr.size()));
+ }
continue;
}
// Handle [[foo:.*]].
- VariableDefs.push_back(std::make_pair(Name, CurParen));
+ VariableDefs[Name] = CurParen;
RegExStr += '(';
++CurParen;
@@ -231,7 +284,6 @@ bool Pattern::ParsePattern(StringRef PatternStr, SourceMgr &SM) {
FixedMatchEnd = std::min(FixedMatchEnd, PatternStr.find("[["));
AddFixedStringToRegEx(PatternStr.substr(0, FixedMatchEnd), RegExStr);
PatternStr = PatternStr.substr(FixedMatchEnd);
- continue;
}
return false;
@@ -264,21 +316,46 @@ void Pattern::AddFixedStringToRegEx(StringRef FixedStr, std::string &TheStr) {
}
}
-bool Pattern::AddRegExToRegEx(StringRef RegexStr, unsigned &CurParen,
+bool Pattern::AddRegExToRegEx(StringRef RS, unsigned &CurParen,
SourceMgr &SM) {
- Regex R(RegexStr);
+ Regex R(RS);
std::string Error;
if (!R.isValid(Error)) {
- SM.PrintMessage(SMLoc::getFromPointer(RegexStr.data()), SourceMgr::DK_Error,
+ SM.PrintMessage(SMLoc::getFromPointer(RS.data()), SourceMgr::DK_Error,
"invalid regex: " + Error);
return true;
}
- RegExStr += RegexStr.str();
+ RegExStr += RS.str();
CurParen += R.getNumMatches();
return false;
}
+void Pattern::AddBackrefToRegEx(unsigned BackrefNum) {
+ assert(BackrefNum >= 1 && BackrefNum <= 9 && "Invalid backref number");
+ std::string Backref = std::string("\\") +
+ std::string(1, '0' + BackrefNum);
+ RegExStr += Backref;
+}
+
+bool Pattern::EvaluateExpression(StringRef Expr, std::string &Value) const {
+ // The only supported expression is @LINE([\+-]\d+)?
+ if (!Expr.startswith("@LINE"))
+ return false;
+ Expr = Expr.substr(StringRef("@LINE").size());
+ int Offset = 0;
+ if (!Expr.empty()) {
+ if (Expr[0] == '+')
+ Expr = Expr.substr(1);
+ else if (Expr[0] != '-')
+ return false;
+ if (Expr.getAsInteger(10, Offset))
+ return false;
+ }
+ Value = llvm::itostr(LineNumber + Offset);
+ return true;
+}
+
/// 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
/// there is a match, the size of the matched string is returned in MatchLen.
@@ -307,15 +384,21 @@ size_t Pattern::Match(StringRef Buffer, size_t &MatchLen,
unsigned InsertOffset = 0;
for (unsigned i = 0, e = VariableUses.size(); i != e; ++i) {
- StringMap<StringRef>::iterator it =
- VariableTable.find(VariableUses[i].first);
- // If the variable is undefined, return an error.
- if (it == VariableTable.end())
- return StringRef::npos;
-
- // Look up the value and escape it so that we can plop it into the regex.
std::string Value;
- AddFixedStringToRegEx(it->second, Value);
+
+ if (VariableUses[i].first[0] == '@') {
+ if (!EvaluateExpression(VariableUses[i].first, Value))
+ return StringRef::npos;
+ } else {
+ StringMap<StringRef>::iterator it =
+ VariableTable.find(VariableUses[i].first);
+ // If the variable is undefined, return an error.
+ if (it == VariableTable.end())
+ return StringRef::npos;
+
+ // Look up the value and escape it so that we can plop it into the regex.
+ AddFixedStringToRegEx(it->second, Value);
+ }
// Plop it into the regex at the adjusted offset.
TmpStr.insert(TmpStr.begin()+VariableUses[i].second+InsertOffset,
@@ -337,10 +420,11 @@ size_t Pattern::Match(StringRef Buffer, size_t &MatchLen,
StringRef FullMatch = MatchInfo[0];
// If this defines any variables, remember their values.
- for (unsigned i = 0, e = VariableDefs.size(); i != e; ++i) {
- assert(VariableDefs[i].second < MatchInfo.size() &&
- "Internal paren error");
- VariableTable[VariableDefs[i].first] = MatchInfo[VariableDefs[i].second];
+ for (std::map<StringRef, unsigned>::const_iterator I = VariableDefs.begin(),
+ E = VariableDefs.end();
+ I != E; ++I) {
+ assert(I->second < MatchInfo.size() && "Internal paren error");
+ VariableTable[I->first] = MatchInfo[I->second];
}
MatchLen = FullMatch.size();
@@ -371,19 +455,31 @@ void Pattern::PrintFailureInfo(const SourceMgr &SM, StringRef Buffer,
// variable values.
if (!VariableUses.empty()) {
for (unsigned i = 0, e = VariableUses.size(); i != e; ++i) {
- StringRef Var = VariableUses[i].first;
- StringMap<StringRef>::const_iterator it = VariableTable.find(Var);
SmallString<256> Msg;
raw_svector_ostream OS(Msg);
-
- // Check for undefined variable references.
- if (it == VariableTable.end()) {
- OS << "uses undefined variable \"";
- OS.write_escaped(Var) << "\"";;
+ StringRef Var = VariableUses[i].first;
+ if (Var[0] == '@') {
+ std::string Value;
+ if (EvaluateExpression(Var, Value)) {
+ OS << "with expression \"";
+ OS.write_escaped(Var) << "\" equal to \"";
+ OS.write_escaped(Value) << "\"";
+ } else {
+ OS << "uses incorrect expression \"";
+ OS.write_escaped(Var) << "\"";
+ }
} else {
- OS << "with variable \"";
- OS.write_escaped(Var) << "\" equal to \"";
- OS.write_escaped(it->second) << "\"";
+ StringMap<StringRef>::const_iterator it = VariableTable.find(Var);
+
+ // Check for undefined variable references.
+ if (it == VariableTable.end()) {
+ OS << "uses undefined variable \"";
+ OS.write_escaped(Var) << "\"";
+ } else {
+ OS << "with variable \"";
+ OS.write_escaped(Var) << "\" equal to \"";
+ OS.write_escaped(it->second) << "\"";
+ }
}
SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note,
@@ -432,6 +528,40 @@ void Pattern::PrintFailureInfo(const SourceMgr &SM, StringRef Buffer,
}
}
+size_t Pattern::FindRegexVarEnd(StringRef Str) {
+ // Offset keeps track of the current offset within the input Str
+ size_t Offset = 0;
+ // [...] Nesting depth
+ size_t BracketDepth = 0;
+
+ while (!Str.empty()) {
+ if (Str.startswith("]]") && BracketDepth == 0)
+ return Offset;
+ if (Str[0] == '\\') {
+ // Backslash escapes the next char within regexes, so skip them both.
+ Str = Str.substr(2);
+ Offset += 2;
+ } else {
+ switch (Str[0]) {
+ default:
+ break;
+ case '[':
+ BracketDepth++;
+ break;
+ case ']':
+ assert(BracketDepth > 0 && "Invalid regex");
+ BracketDepth--;
+ break;
+ }
+ Str = Str.substr(1);
+ Offset++;
+ }
+ }
+
+ return StringRef::npos;
+}
+
+
//===----------------------------------------------------------------------===//
// Check Strings.
//===----------------------------------------------------------------------===//
@@ -457,9 +587,13 @@ struct CheckString {
: Pat(P), Loc(L), IsCheckNext(isCheckNext) {}
};
-/// CanonicalizeInputFile - Remove duplicate horizontal space from the specified
-/// memory buffer, free it, and return a new one.
-static MemoryBuffer *CanonicalizeInputFile(MemoryBuffer *MB) {
+/// Canonicalize whitespaces in the input file. Line endings are replaced
+/// with UNIX-style '\n'.
+///
+/// \param PreserveHorizontal Don't squash consecutive horizontal whitespace
+/// characters to a single space.
+static MemoryBuffer *CanonicalizeInputFile(MemoryBuffer *MB,
+ bool PreserveHorizontal) {
SmallString<128> NewFile;
NewFile.reserve(MB->getBufferSize());
@@ -470,8 +604,9 @@ static MemoryBuffer *CanonicalizeInputFile(MemoryBuffer *MB) {
continue;
}
- // If current char is not a horizontal whitespace, dump it to output as is.
- if (*Ptr != ' ' && *Ptr != '\t') {
+ // If current char is not a horizontal whitespace or if horizontal
+ // whitespace canonicalization is disabled, dump it to output as is.
+ if (PreserveHorizontal || (*Ptr != ' ' && *Ptr != '\t')) {
NewFile.push_back(*Ptr);
continue;
}
@@ -494,9 +629,9 @@ static MemoryBuffer *CanonicalizeInputFile(MemoryBuffer *MB) {
/// ReadCheckFile - Read the check file, which specifies the sequence of
/// expected strings. The strings are added to the CheckStrings vector.
+/// Returns true in case of an error, false otherwise.
static bool ReadCheckFile(SourceMgr &SM,
std::vector<CheckString> &CheckStrings) {
- // Open the check file, and tell SourceMgr about it.
OwningPtr<MemoryBuffer> File;
if (error_code ec =
MemoryBuffer::getFileOrSTDIN(CheckFilename.c_str(), File)) {
@@ -504,28 +639,33 @@ static bool ReadCheckFile(SourceMgr &SM,
<< ec.message() << '\n';
return true;
}
- MemoryBuffer *F = File.take();
// If we want to canonicalize whitespace, strip excess whitespace from the
- // buffer containing the CHECK lines.
- if (!NoCanonicalizeWhiteSpace)
- F = CanonicalizeInputFile(F);
+ // buffer containing the CHECK lines. Remove DOS style line endings.
+ MemoryBuffer *F =
+ CanonicalizeInputFile(File.take(), NoCanonicalizeWhiteSpace);
SM.AddNewSourceBuffer(F, SMLoc());
// Find all instances of CheckPrefix followed by : in the file.
StringRef Buffer = F->getBuffer();
-
std::vector<std::pair<SMLoc, Pattern> > NotMatches;
+ // LineNumber keeps track of the line on which CheckPrefix instances are
+ // found.
+ unsigned LineNumber = 1;
+
while (1) {
// See if Prefix occurs in the memory buffer.
- Buffer = Buffer.substr(Buffer.find(CheckPrefix));
-
+ size_t PrefixLoc = Buffer.find(CheckPrefix);
// If we didn't find a match, we're done.
- if (Buffer.empty())
+ if (PrefixLoc == StringRef::npos)
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
@@ -560,12 +700,11 @@ static bool ReadCheckFile(SourceMgr &SM,
// Parse the pattern.
Pattern P;
- if (P.ParsePattern(Buffer.substr(0, EOL), SM))
+ if (P.ParsePattern(Buffer.substr(0, EOL), SM, LineNumber))
return true;
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),
@@ -582,7 +721,6 @@ static bool ReadCheckFile(SourceMgr &SM,
continue;
}
-
// Okay, add the string we captured to the output vector and move on.
CheckStrings.push_back(CheckString(P,
PatternLoc,
@@ -663,18 +801,18 @@ int main(int argc, char **argv) {
MemoryBuffer::getFileOrSTDIN(InputFilename.c_str(), File)) {
errs() << "Could not open input file '" << InputFilename << "': "
<< ec.message() << '\n';
- return true;
+ return 2;
}
- MemoryBuffer *F = File.take();
- if (F->getBufferSize() == 0) {
+ if (File->getBufferSize() == 0) {
errs() << "FileCheck error: '" << InputFilename << "' is empty.\n";
- return 1;
+ return 2;
}
-
+
// Remove duplicate spaces in the input file if requested.
- if (!NoCanonicalizeWhiteSpace)
- F = CanonicalizeInputFile(F);
+ // Remove DOS style line endings.
+ MemoryBuffer *F =
+ CanonicalizeInputFile(File.take(), NoCanonicalizeWhiteSpace);
SM.AddNewSourceBuffer(F, SMLoc());
diff --git a/utils/FileUpdate/FileUpdate.cpp b/utils/FileUpdate/FileUpdate.cpp
index 3ea1e4f..9b48f94 100644
--- a/utils/FileUpdate/FileUpdate.cpp
+++ b/utils/FileUpdate/FileUpdate.cpp
@@ -13,12 +13,12 @@
//
//===----------------------------------------------------------------------===//
+#include "llvm/ADT/OwningPtr.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/ADT/OwningPtr.h"
#include "llvm/Support/PrettyStackTrace.h"
-#include "llvm/Support/ToolOutputFile.h"
#include "llvm/Support/Signals.h"
+#include "llvm/Support/ToolOutputFile.h"
#include "llvm/Support/system_error.h"
using namespace llvm;
diff --git a/utils/GenLibDeps.pl b/utils/GenLibDeps.pl
index 656250c..7748cab 100755
--- a/utils/GenLibDeps.pl
+++ b/utils/GenLibDeps.pl
@@ -98,7 +98,7 @@ if ($PEROBJ) {
$libpath =~ s/^BitWriter/Bitcode\/Writer/;
$libpath =~ s/^CppBackend/Target\/CppBackend/;
$libpath =~ s/^MSIL/Target\/MSIL/;
- $libpath =~ s/^Core/VMCore/;
+ $libpath =~ s/^Core/IR/;
$libpath =~ s/^Instrumentation/Transforms\/Instrumentation/;
$libpath =~ s/^Interpreter/ExecutionEngine\/Interpreter/;
$libpath =~ s/^JIT/ExecutionEngine\/JIT/;
diff --git a/utils/KillTheDoctor/KillTheDoctor.cpp b/utils/KillTheDoctor/KillTheDoctor.cpp
index 70713b2..feba2e5 100644
--- a/utils/KillTheDoctor/KillTheDoctor.cpp
+++ b/utils/KillTheDoctor/KillTheDoctor.cpp
@@ -39,19 +39,22 @@
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/PrettyStackTrace.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/type_traits.h"
#include "llvm/Support/Signals.h"
+#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/system_error.h"
+#include "llvm/Support/type_traits.h"
#include <algorithm>
#include <cerrno>
#include <cstdlib>
#include <map>
#include <string>
+
+// These includes must be last.
#include <Windows.h>
#include <WinError.h>
#include <Dbghelp.h>
#include <psapi.h>
+
using namespace llvm;
#undef max
diff --git a/utils/PerfectShuffle/PerfectShuffle.cpp b/utils/PerfectShuffle/PerfectShuffle.cpp
index 98f8f4c..d39414e 100644
--- a/utils/PerfectShuffle/PerfectShuffle.cpp
+++ b/utils/PerfectShuffle/PerfectShuffle.cpp
@@ -14,11 +14,11 @@
//
//===----------------------------------------------------------------------===//
-#include <iostream>
-#include <iomanip>
-#include <vector>
#include <cassert>
#include <cstdlib>
+#include <iomanip>
+#include <iostream>
+#include <vector>
struct Operator;
// Masks are 4-nibble hex numbers. Values 0-7 in any nibble means that it takes
diff --git a/utils/TableGen/AsmMatcherEmitter.cpp b/utils/TableGen/AsmMatcherEmitter.cpp
index ee83311..6faf819 100644
--- a/utils/TableGen/AsmMatcherEmitter.cpp
+++ b/utils/TableGen/AsmMatcherEmitter.cpp
@@ -100,9 +100,9 @@
#include "StringToOffsetTable.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/PointerUnion.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
@@ -958,8 +958,12 @@ static std::string getEnumNameForToken(StringRef Str) {
case ':': Res += "_COLON_"; break;
case '!': Res += "_EXCLAIM_"; break;
case '.': Res += "_DOT_"; break;
+ case '<': Res += "_LT_"; break;
+ case '>': Res += "_GT_"; break;
default:
- if (isalnum(*it))
+ if ((*it >= 'A' && *it <= 'Z') ||
+ (*it >= 'a' && *it <= 'z') ||
+ (*it >= '0' && *it <= '9'))
Res += *it;
else
Res += "_" + utostr((unsigned) *it) + "_";
@@ -1723,7 +1727,7 @@ static void emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName,
<< " default: llvm_unreachable(\"invalid conversion entry!\");\n"
<< " case CVT_Reg:\n"
<< " Operands[*(p + 1)]->setMCOperandNum(NumMCOperands);\n"
- << " Operands[*(p + 1)]->setConstraint(\"m\");\n"
+ << " Operands[*(p + 1)]->setConstraint(\"r\");\n"
<< " ++NumMCOperands;\n"
<< " break;\n"
<< " case CVT_Tied:\n"
@@ -1754,7 +1758,8 @@ static void emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName,
// Remember this converter for the kind enum.
unsigned KindID = OperandConversionKinds.size();
- OperandConversionKinds.insert("CVT_" + AsmMatchConverter);
+ OperandConversionKinds.insert("CVT_" +
+ getEnumNameForToken(AsmMatchConverter));
// Add the converter row for this instruction.
ConversionTable.push_back(std::vector<uint8_t>());
@@ -1762,7 +1767,8 @@ static void emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName,
ConversionTable.back().push_back(CVT_Done);
// Add the handler to the conversion driver function.
- CvtOS << " case CVT_" << AsmMatchConverter << ":\n"
+ CvtOS << " case CVT_"
+ << getEnumNameForToken(AsmMatchConverter) << ":\n"
<< " " << AsmMatchConverter << "(Inst, Operands);\n"
<< " break;\n";
@@ -1800,6 +1806,7 @@ static void emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName,
// the index of its entry in the vector).
std::string Name = "CVT_" + (Op.Class->isRegisterClass() ? "Reg" :
Op.Class->RenderMethod);
+ Name = getEnumNameForToken(Name);
bool IsNewConverter = false;
unsigned ID = getConverterOperandID(Name, OperandConversionKinds,
@@ -1823,9 +1830,13 @@ static void emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName,
// Add a handler for the operand number lookup.
OpOS << " case " << Name << ":\n"
- << " Operands[*(p + 1)]->setMCOperandNum(NumMCOperands);\n"
- << " Operands[*(p + 1)]->setConstraint(\"m\");\n"
- << " NumMCOperands += " << OpInfo.MINumOperands << ";\n"
+ << " Operands[*(p + 1)]->setMCOperandNum(NumMCOperands);\n";
+
+ if (Op.Class->isRegisterClass())
+ OpOS << " Operands[*(p + 1)]->setConstraint(\"r\");\n";
+ else
+ OpOS << " Operands[*(p + 1)]->setConstraint(\"m\");\n";
+ OpOS << " NumMCOperands += " << OpInfo.MINumOperands << ";\n"
<< " break;\n";
break;
}
@@ -2867,6 +2878,15 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << "(MatchClassKind)it->Classes[i]);\n";
OS << " if (Diag == Match_Success)\n";
OS << " continue;\n";
+ OS << " // If the generic handler indicates an invalid operand\n";
+ OS << " // failure, check for a special case.\n";
+ OS << " if (Diag == Match_InvalidOperand) {\n";
+ OS << " Diag = validateTargetOperandClass(Operands[i+1],\n";
+ OS.indent(43);
+ OS << "(MatchClassKind)it->Classes[i]);\n";
+ OS << " if (Diag == Match_Success)\n";
+ OS << " continue;\n";
+ OS << " }\n";
OS << " // If this operand is broken for all of the instances of this\n";
OS << " // mnemonic, keep track of it so we can report loc info.\n";
OS << " // If we already had a match that only failed due to a\n";
diff --git a/utils/TableGen/AsmWriterEmitter.cpp b/utils/TableGen/AsmWriterEmitter.cpp
index a4114d9..ac8d896 100644
--- a/utils/TableGen/AsmWriterEmitter.cpp
+++ b/utils/TableGen/AsmWriterEmitter.cpp
@@ -842,8 +842,11 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) {
if (!IAP->isOpMapped(ROName)) {
IAP->addOperand(ROName, i);
+ Record *R = CGA->ResultOperands[i].getRecord();
+ if (R->isSubClassOf("RegisterOperand"))
+ R = R->getValueAsDef("RegClass");
Cond = std::string("MRI.getRegClass(") + Target.getName() + "::" +
- CGA->ResultOperands[i].getRecord()->getName() + "RegClassID)"
+ R->getName() + "RegClassID)"
".contains(MI->getOperand(" + llvm::utostr(i) + ").getReg())";
IAP->addCond(Cond);
} else {
@@ -863,12 +866,18 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) {
break;
}
- case CodeGenInstAlias::ResultOperand::K_Imm:
- Cond = std::string("MI->getOperand(") +
- llvm::utostr(i) + ").getImm() == " +
- llvm::utostr(CGA->ResultOperands[i].getImm());
+ case CodeGenInstAlias::ResultOperand::K_Imm: {
+ std::string Op = "MI->getOperand(" + llvm::utostr(i) + ")";
+
+ // Just because the alias has an immediate result, doesn't mean the
+ // MCInst will. An MCExpr could be present, for example.
+ IAP->addCond(Op + ".isImm()");
+
+ Cond = Op + ".getImm() == "
+ + llvm::utostr(CGA->ResultOperands[i].getImm());
IAP->addCond(Cond);
break;
+ }
case CodeGenInstAlias::ResultOperand::K_Reg:
// If this is zero_reg, something's playing tricks we're not
// equipped to handle.
diff --git a/utils/TableGen/CMakeLists.txt b/utils/TableGen/CMakeLists.txt
index d0416c9..3ee1974 100644
--- a/utils/TableGen/CMakeLists.txt
+++ b/utils/TableGen/CMakeLists.txt
@@ -19,11 +19,11 @@ add_tablegen(llvm-tblgen LLVM
DAGISelMatcher.cpp
DFAPacketizerEmitter.cpp
DisassemblerEmitter.cpp
- EDEmitter.cpp
FastISelEmitter.cpp
FixedLenDecoderEmitter.cpp
InstrInfoEmitter.cpp
IntrinsicEmitter.cpp
+ OptParserEmitter.cpp
PseudoLoweringEmitter.cpp
RegisterInfoEmitter.cpp
SetTheory.cpp
@@ -33,4 +33,5 @@ add_tablegen(llvm-tblgen LLVM
X86DisassemblerTables.cpp
X86ModRMFilters.cpp
X86RecognizableInstr.cpp
+ CTagsEmitter.cpp
)
diff --git a/utils/TableGen/CTagsEmitter.cpp b/utils/TableGen/CTagsEmitter.cpp
new file mode 100644
index 0000000..8bf7778
--- /dev/null
+++ b/utils/TableGen/CTagsEmitter.cpp
@@ -0,0 +1,99 @@
+//===- CTagsEmitter.cpp - Generate ctags-compatible index ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This tablegen backend emits an index of definitions in ctags(1) format.
+// A helper script, utils/TableGen/tdtags, provides an easier-to-use
+// interface; run 'tdtags -H' for documentation.
+//
+//===----------------------------------------------------------------------===//
+
+#define DEBUG_TYPE "ctags-emitter"
+
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/TableGen/Error.h"
+#include "llvm/TableGen/Record.h"
+#include "llvm/TableGen/TableGenBackend.h"
+#include <algorithm>
+#include <string>
+#include <vector>
+using namespace llvm;
+
+namespace llvm { extern SourceMgr SrcMgr; }
+
+namespace {
+
+class Tag {
+private:
+ const std::string *Id;
+ SMLoc Loc;
+public:
+ Tag(const std::string &Name, const SMLoc Location)
+ : Id(&Name), Loc(Location) {}
+ int operator<(const Tag &B) const { return *Id < *B.Id; }
+ void emit(raw_ostream &OS) const {
+ int BufferID = SrcMgr.FindBufferContainingLoc(Loc);
+ MemoryBuffer *CurMB = SrcMgr.getBufferInfo(BufferID).Buffer;
+ const char *BufferName = CurMB->getBufferIdentifier();
+ std::pair<unsigned, unsigned> LineAndColumn = SrcMgr.getLineAndColumn(Loc);
+ OS << *Id << "\t" << BufferName << "\t" << LineAndColumn.first << "\n";
+ }
+};
+
+class CTagsEmitter {
+private:
+ RecordKeeper &Records;
+public:
+ CTagsEmitter(RecordKeeper &R) : Records(R) {}
+
+ void run(raw_ostream &OS);
+
+private:
+ static SMLoc locate(const Record *R);
+};
+
+} // End anonymous namespace.
+
+SMLoc CTagsEmitter::locate(const Record *R) {
+ ArrayRef<SMLoc> Locs = R->getLoc();
+ if (Locs.empty()) {
+ SMLoc NullLoc;
+ return NullLoc;
+ }
+ return Locs.front();
+}
+
+void CTagsEmitter::run(raw_ostream &OS) {
+ const std::map<std::string, Record *> &Classes = Records.getClasses();
+ const std::map<std::string, Record *> &Defs = Records.getDefs();
+ std::vector<Tag> Tags;
+ // Collect tags.
+ Tags.reserve(Classes.size() + Defs.size());
+ for (std::map<std::string, Record *>::const_iterator I = Classes.begin(),
+ E = Classes.end();
+ I != E; ++I)
+ Tags.push_back(Tag(I->first, locate(I->second)));
+ for (std::map<std::string, Record *>::const_iterator I = Defs.begin(),
+ E = Defs.end();
+ I != E; ++I)
+ Tags.push_back(Tag(I->first, locate(I->second)));
+ // Emit tags.
+ std::sort(Tags.begin(), Tags.end());
+ OS << "!_TAG_FILE_FORMAT\t1\t/original ctags format/\n";
+ OS << "!_TAG_FILE_SORTED\t1\t/0=unsorted, 1=sorted, 2=foldcase/\n";
+ for (std::vector<Tag>::const_iterator I = Tags.begin(), E = Tags.end();
+ I != E; ++I)
+ I->emit(OS);
+}
+
+namespace llvm {
+
+void EmitCTags(RecordKeeper &RK, raw_ostream &OS) { CTagsEmitter(RK).run(OS); }
+
+} // End llvm namespace.
diff --git a/utils/TableGen/CodeEmitterGen.cpp b/utils/TableGen/CodeEmitterGen.cpp
index 3e4f626..c94d384 100644
--- a/utils/TableGen/CodeEmitterGen.cpp
+++ b/utils/TableGen/CodeEmitterGen.cpp
@@ -14,10 +14,10 @@
//===----------------------------------------------------------------------===//
#include "CodeGenTarget.h"
-#include "llvm/TableGen/Record.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
+#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/TableGenBackend.h"
#include <map>
#include <string>
diff --git a/utils/TableGen/CodeGenDAGPatterns.cpp b/utils/TableGen/CodeGenDAGPatterns.cpp
index d5b581b..8e5bb77 100644
--- a/utils/TableGen/CodeGenDAGPatterns.cpp
+++ b/utils/TableGen/CodeGenDAGPatterns.cpp
@@ -13,13 +13,13 @@
//===----------------------------------------------------------------------===//
#include "CodeGenDAGPatterns.h"
-#include "llvm/TableGen/Error.h"
-#include "llvm/TableGen/Record.h"
-#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/TableGen/Error.h"
+#include "llvm/TableGen/Record.h"
#include <algorithm>
#include <cstdio>
#include <set>
@@ -57,7 +57,7 @@ EEVT::TypeSet::TypeSet(MVT::SimpleValueType VT, TreePattern &TP) {
}
-EEVT::TypeSet::TypeSet(const std::vector<MVT::SimpleValueType> &VTList) {
+EEVT::TypeSet::TypeSet(ArrayRef<MVT::SimpleValueType> VTList) {
assert(!VTList.empty() && "empty list?");
TypeVec.append(VTList.begin(), VTList.end());
@@ -76,7 +76,7 @@ bool EEVT::TypeSet::FillWithPossibleTypes(TreePattern &TP,
bool (*Pred)(MVT::SimpleValueType),
const char *PredicateName) {
assert(isCompletelyUnknown());
- const std::vector<MVT::SimpleValueType> &LegalTypes =
+ ArrayRef<MVT::SimpleValueType> LegalTypes =
TP.getDAGPatterns().getTargetInfo().getLegalValueTypes();
if (TP.hasError())
@@ -956,6 +956,40 @@ bool SDTypeConstraint::ApplyTypeConstraint(TreePatternNode *N,
llvm_unreachable("Invalid ConstraintType!");
}
+// Update the node type to match an instruction operand or result as specified
+// in the ins or outs lists on the instruction definition. Return true if the
+// type was actually changed.
+bool TreePatternNode::UpdateNodeTypeFromInst(unsigned ResNo,
+ Record *Operand,
+ TreePattern &TP) {
+ // The 'unknown' operand indicates that types should be inferred from the
+ // context.
+ if (Operand->isSubClassOf("unknown_class"))
+ return false;
+
+ // The Operand class specifies a type directly.
+ if (Operand->isSubClassOf("Operand"))
+ return UpdateNodeType(ResNo, getValueType(Operand->getValueAsDef("Type")),
+ TP);
+
+ // PointerLikeRegClass has a type that is determined at runtime.
+ if (Operand->isSubClassOf("PointerLikeRegClass"))
+ return UpdateNodeType(ResNo, MVT::iPTR, TP);
+
+ // Both RegisterClass and RegisterOperand operands derive their types from a
+ // register class def.
+ Record *RC = 0;
+ if (Operand->isSubClassOf("RegisterClass"))
+ RC = Operand;
+ else if (Operand->isSubClassOf("RegisterOperand"))
+ RC = Operand->getValueAsDef("RegClass");
+
+ assert(RC && "Unknown operand type");
+ CodeGenTarget &Tgt = TP.getDAGPatterns().getTargetInfo();
+ return UpdateNodeType(ResNo, Tgt.getRegisterClass(RC).getValueTypes(), TP);
+}
+
+
//===----------------------------------------------------------------------===//
// SDNodeInfo implementation
//
@@ -1287,8 +1321,18 @@ TreePatternNode *TreePatternNode::InlinePatternFragments(TreePattern &TP) {
/// type which should be applied to it. This will infer the type of register
/// references from the register file information, for example.
///
+/// When Unnamed is set, return the type of a DAG operand with no name, such as
+/// the F8RC register class argument in:
+///
+/// (COPY_TO_REGCLASS GPR:$src, F8RC)
+///
+/// When Unnamed is false, return the type of a named DAG operand such as the
+/// GPR:$src operand above.
+///
static EEVT::TypeSet getImplicitType(Record *R, unsigned ResNo,
- bool NotRegisters, TreePattern &TP) {
+ bool NotRegisters,
+ bool Unnamed,
+ TreePattern &TP) {
// Check to see if this is a register operand.
if (R->isSubClassOf("RegisterOperand")) {
assert(ResNo == 0 && "Regoperand ref only has one result!");
@@ -1302,6 +1346,13 @@ static EEVT::TypeSet getImplicitType(Record *R, unsigned ResNo,
// Check to see if this is a register or a register class.
if (R->isSubClassOf("RegisterClass")) {
assert(ResNo == 0 && "Regclass ref only has one result!");
+ // An unnamed register class represents itself as an i32 immediate, for
+ // example on a COPY_TO_REGCLASS instruction.
+ if (Unnamed)
+ return EEVT::TypeSet(MVT::i32, TP);
+
+ // In a named operand, the register class provides the possible set of
+ // types.
if (NotRegisters)
return EEVT::TypeSet(); // Unknown.
const CodeGenTarget &T = TP.getDAGPatterns().getTargetInfo();
@@ -1327,9 +1378,27 @@ static EEVT::TypeSet getImplicitType(Record *R, unsigned ResNo,
return EEVT::TypeSet();
}
- if (R->isSubClassOf("ValueType") || R->isSubClassOf("CondCode")) {
+ if (R->isSubClassOf("ValueType")) {
assert(ResNo == 0 && "This node only has one result!");
- // Using a VTSDNode or CondCodeSDNode.
+ // An unnamed VTSDNode represents itself as an MVT::Other immediate.
+ //
+ // (sext_inreg GPR:$src, i16)
+ // ~~~
+ if (Unnamed)
+ return EEVT::TypeSet(MVT::Other, TP);
+ // With a name, the ValueType simply provides the type of the named
+ // variable.
+ //
+ // (sext_inreg i32:$src, i16)
+ // ~~~~~~~~
+ if (NotRegisters)
+ return EEVT::TypeSet(); // Unknown.
+ return EEVT::TypeSet(getValueType(R), TP);
+ }
+
+ if (R->isSubClassOf("CondCode")) {
+ assert(ResNo == 0 && "This node only has one result!");
+ // Using a CondCodeSDNode.
return EEVT::TypeSet(MVT::Other, TP);
}
@@ -1435,7 +1504,8 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) {
bool MadeChange = false;
for (unsigned i = 0, e = Types.size(); i != e; ++i)
MadeChange |= UpdateNodeType(i, getImplicitType(DI->getDef(), i,
- NotRegisters, TP), TP);
+ NotRegisters,
+ !hasName(), TP), TP);
return MadeChange;
}
@@ -1498,25 +1568,6 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) {
return MadeChange;
}
- if (getOperator()->getName() == "COPY_TO_REGCLASS") {
- bool MadeChange = false;
- MadeChange |= getChild(0)->ApplyTypeConstraints(TP, NotRegisters);
- MadeChange |= getChild(1)->ApplyTypeConstraints(TP, NotRegisters);
-
- assert(getChild(0)->getNumTypes() == 1 &&
- getChild(1)->getNumTypes() == 1 && "Unhandled case");
-
- // child #1 of COPY_TO_REGCLASS should be a register class. We don't care
- // what type it gets, so if it didn't get a concrete type just give it the
- // first viable type from the reg class.
- if (!getChild(1)->hasTypeSet(0) &&
- !getChild(1)->getExtType(0).isCompletelyUnknown()) {
- MVT::SimpleValueType RCVT = getChild(1)->getExtType(0).getTypeList()[0];
- MadeChange |= getChild(1)->UpdateNodeType(0, RCVT, TP);
- }
- return MadeChange;
- }
-
if (const CodeGenIntrinsic *Int = getIntrinsicInfo(CDP)) {
bool MadeChange = false;
@@ -1575,26 +1626,8 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) {
// (outs) list of the instruction.
// FIXME: Cap at one result so far.
unsigned NumResultsToAdd = InstInfo.Operands.NumDefs ? 1 : 0;
- for (unsigned ResNo = 0; ResNo != NumResultsToAdd; ++ResNo) {
- Record *ResultNode = Inst.getResult(ResNo);
-
- if (ResultNode->isSubClassOf("PointerLikeRegClass")) {
- MadeChange |= UpdateNodeType(ResNo, MVT::iPTR, TP);
- } else if (ResultNode->isSubClassOf("RegisterOperand")) {
- Record *RegClass = ResultNode->getValueAsDef("RegClass");
- const CodeGenRegisterClass &RC =
- CDP.getTargetInfo().getRegisterClass(RegClass);
- MadeChange |= UpdateNodeType(ResNo, RC.getValueTypes(), TP);
- } else if (ResultNode->isSubClassOf("unknown_class")) {
- // Nothing to do.
- } else {
- assert(ResultNode->isSubClassOf("RegisterClass") &&
- "Operands should be register classes!");
- const CodeGenRegisterClass &RC =
- CDP.getTargetInfo().getRegisterClass(ResultNode);
- MadeChange |= UpdateNodeType(ResNo, RC.getValueTypes(), TP);
- }
- }
+ for (unsigned ResNo = 0; ResNo != NumResultsToAdd; ++ResNo)
+ MadeChange |= UpdateNodeTypeFromInst(ResNo, Inst.getResult(ResNo), TP);
// If the instruction has implicit defs, we apply the first one as a result.
// FIXME: This sucks, it should apply all implicit defs.
@@ -1636,30 +1669,44 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) {
return false;
}
- MVT::SimpleValueType VT;
TreePatternNode *Child = getChild(ChildNo++);
unsigned ChildResNo = 0; // Instructions always use res #0 of their op.
- if (OperandNode->isSubClassOf("RegisterClass")) {
- const CodeGenRegisterClass &RC =
- CDP.getTargetInfo().getRegisterClass(OperandNode);
- MadeChange |= Child->UpdateNodeType(ChildResNo, RC.getValueTypes(), TP);
- } else if (OperandNode->isSubClassOf("RegisterOperand")) {
- Record *RegClass = OperandNode->getValueAsDef("RegClass");
- const CodeGenRegisterClass &RC =
- CDP.getTargetInfo().getRegisterClass(RegClass);
- MadeChange |= Child->UpdateNodeType(ChildResNo, RC.getValueTypes(), TP);
- } else if (OperandNode->isSubClassOf("Operand")) {
- VT = getValueType(OperandNode->getValueAsDef("Type"));
- MadeChange |= Child->UpdateNodeType(ChildResNo, VT, TP);
- } else if (OperandNode->isSubClassOf("PointerLikeRegClass")) {
- MadeChange |= Child->UpdateNodeType(ChildResNo, MVT::iPTR, TP);
- } else if (OperandNode->isSubClassOf("unknown_class")) {
- // Nothing to do.
- } else
- llvm_unreachable("Unknown operand type!");
+ // If the operand has sub-operands, they may be provided by distinct
+ // child patterns, so attempt to match each sub-operand separately.
+ if (OperandNode->isSubClassOf("Operand")) {
+ DagInit *MIOpInfo = OperandNode->getValueAsDag("MIOperandInfo");
+ if (unsigned NumArgs = MIOpInfo->getNumArgs()) {
+ // But don't do that if the whole operand is being provided by
+ // a single ComplexPattern.
+ const ComplexPattern *AM = Child->getComplexPatternInfo(CDP);
+ if (!AM || AM->getNumOperands() < NumArgs) {
+ // Match first sub-operand against the child we already have.
+ Record *SubRec = cast<DefInit>(MIOpInfo->getArg(0))->getDef();
+ MadeChange |=
+ Child->UpdateNodeTypeFromInst(ChildResNo, SubRec, TP);
+
+ // And the remaining sub-operands against subsequent children.
+ for (unsigned Arg = 1; Arg < NumArgs; ++Arg) {
+ if (ChildNo >= getNumChildren()) {
+ TP.error("Instruction '" + getOperator()->getName() +
+ "' expects more operands than were provided.");
+ return false;
+ }
+ Child = getChild(ChildNo++);
+
+ SubRec = cast<DefInit>(MIOpInfo->getArg(Arg))->getDef();
+ MadeChange |=
+ Child->UpdateNodeTypeFromInst(ChildResNo, SubRec, TP);
+ }
+ continue;
+ }
+ }
+ }
- MadeChange |= Child->ApplyTypeConstraints(TP, NotRegisters);
+ // If we didn't match by pieces above, attempt to match the whole
+ // operand now.
+ MadeChange |= Child->UpdateNodeTypeFromInst(ChildResNo, OperandNode, TP);
}
if (ChildNo != getNumChildren()) {
@@ -1668,6 +1715,8 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) {
return false;
}
+ for (unsigned i = 0, e = getNumChildren(); i != e; ++i)
+ MadeChange |= getChild(i)->ApplyTypeConstraints(TP, NotRegisters);
return MadeChange;
}
@@ -1817,6 +1866,16 @@ TreePatternNode *TreePattern::ParseTreePattern(Init *TheInit, StringRef OpName){
return Res;
}
+ // ?:$name or just $name.
+ if (TheInit == UnsetInit::get()) {
+ if (OpName.empty())
+ error("'?' argument requires a name to match with operand list");
+ TreePatternNode *Res = new TreePatternNode(TheInit, 1);
+ Args.push_back(OpName);
+ Res->setName(OpName);
+ return Res;
+ }
+
if (IntInit *II = dyn_cast<IntInit>(TheInit)) {
if (!OpName.empty())
error("Constant int argument should not have a name!");
@@ -2383,6 +2442,7 @@ FindPatternInputsAndOutputs(TreePattern *I, TreePatternNode *Pat,
I->error("set destination should be a register!");
if (Val->getDef()->isSubClassOf("RegisterClass") ||
+ Val->getDef()->isSubClassOf("ValueType") ||
Val->getDef()->isSubClassOf("RegisterOperand") ||
Val->getDef()->isSubClassOf("PointerLikeRegClass")) {
if (Dest->getName().empty())
@@ -2599,6 +2659,25 @@ getInstructionsInTree(TreePatternNode *Tree, SmallVectorImpl<Record*> &Instrs) {
getInstructionsInTree(Tree->getChild(i), Instrs);
}
+/// Check the class of a pattern leaf node against the instruction operand it
+/// represents.
+static bool checkOperandClass(CGIOperandList::OperandInfo &OI,
+ Record *Leaf) {
+ if (OI.Rec == Leaf)
+ return true;
+
+ // Allow direct value types to be used in instruction set patterns.
+ // The type will be checked later.
+ if (Leaf->isSubClassOf("ValueType"))
+ return true;
+
+ // Patterns can also be ComplexPattern instances.
+ if (Leaf->isSubClassOf("ComplexPattern"))
+ return true;
+
+ return false;
+}
+
/// ParseInstructions - Parse all of the instructions, inlining and resolving
/// any fragments involved. This populates the Instructions list with fully
/// resolved instructions.
@@ -2708,7 +2787,7 @@ void CodeGenDAGPatterns::ParseInstructions() {
I->error("Operand $" + OpName + " should be a set destination: all "
"outputs must occur before inputs in operand list!");
- if (CGI.Operands[i].Rec != R)
+ if (!checkOperandClass(CGI.Operands[i], R))
I->error("Operand $" + OpName + " class mismatch!");
// Remember the return type.
@@ -2747,7 +2826,7 @@ void CodeGenDAGPatterns::ParseInstructions() {
if (InVal->isLeaf() && isa<DefInit>(InVal->getLeafValue())) {
Record *InRec = static_cast<DefInit*>(InVal->getLeafValue())->getDef();
- if (Op.Rec != InRec && !InRec->isSubClassOf("ComplexPattern"))
+ if (!checkOperandClass(Op, InRec))
I->error("Operand $" + OpName + "'s register class disagrees"
" between the operand and pattern");
}
diff --git a/utils/TableGen/CodeGenDAGPatterns.h b/utils/TableGen/CodeGenDAGPatterns.h
index 9be763f..7c2fa36 100644
--- a/utils/TableGen/CodeGenDAGPatterns.h
+++ b/utils/TableGen/CodeGenDAGPatterns.h
@@ -15,15 +15,15 @@
#ifndef CODEGEN_DAGPATTERNS_H
#define CODEGEN_DAGPATTERNS_H
-#include "CodeGenTarget.h"
#include "CodeGenIntrinsics.h"
+#include "CodeGenTarget.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/Support/ErrorHandling.h"
-#include <set>
#include <algorithm>
-#include <vector>
#include <map>
+#include <set>
+#include <vector>
namespace llvm {
class Record;
@@ -59,7 +59,7 @@ namespace EEVT {
public:
TypeSet() {}
TypeSet(MVT::SimpleValueType VT, TreePattern &TP);
- TypeSet(const std::vector<MVT::SimpleValueType> &VTList);
+ TypeSet(ArrayRef<MVT::SimpleValueType> VTList);
bool isCompletelyUnknown() const { return TypeVec.empty(); }
@@ -334,6 +334,7 @@ public:
}
~TreePatternNode();
+ bool hasName() const { return !Name.empty(); }
const std::string &getName() const { return Name; }
void setName(StringRef N) { Name.assign(N.begin(), N.end()); }
@@ -463,6 +464,11 @@ public: // Higher level manipulation routines.
return Types[ResNo].MergeInTypeInfo(EEVT::TypeSet(InTy, TP), TP);
}
+ // Update node type with types inferred from an instruction operand or result
+ // def from the ins/outs lists.
+ // Return true if the type changed.
+ bool UpdateNodeTypeFromInst(unsigned ResNo, Record *Operand, TreePattern &TP);
+
/// ContainsUnresolvedType - Return true if this tree contains any
/// unresolved types.
bool ContainsUnresolvedType() const {
diff --git a/utils/TableGen/CodeGenInstruction.cpp b/utils/TableGen/CodeGenInstruction.cpp
index 0a8684d..3673204 100644
--- a/utils/TableGen/CodeGenInstruction.cpp
+++ b/utils/TableGen/CodeGenInstruction.cpp
@@ -13,11 +13,11 @@
#include "CodeGenInstruction.h"
#include "CodeGenTarget.h"
-#include "llvm/TableGen/Error.h"
-#include "llvm/TableGen/Record.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringMap.h"
-#include "llvm/ADT/STLExtras.h"
+#include "llvm/TableGen/Error.h"
+#include "llvm/TableGen/Record.h"
#include <set>
using namespace llvm;
diff --git a/utils/TableGen/CodeGenInstruction.h b/utils/TableGen/CodeGenInstruction.h
index 55d4439..d1e1153 100644
--- a/utils/TableGen/CodeGenInstruction.h
+++ b/utils/TableGen/CodeGenInstruction.h
@@ -14,12 +14,12 @@
#ifndef CODEGEN_INSTRUCTION_H
#define CODEGEN_INSTRUCTION_H
-#include "llvm/CodeGen/ValueTypes.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/CodeGen/ValueTypes.h"
#include "llvm/Support/SourceMgr.h"
#include <string>
-#include <vector>
#include <utility>
+#include <vector>
namespace llvm {
class Record;
diff --git a/utils/TableGen/CodeGenIntrinsics.h b/utils/TableGen/CodeGenIntrinsics.h
index 6efe952..f0570f9 100644
--- a/utils/TableGen/CodeGenIntrinsics.h
+++ b/utils/TableGen/CodeGenIntrinsics.h
@@ -14,9 +14,9 @@
#ifndef CODEGEN_INTRINSIC_H
#define CODEGEN_INTRINSIC_H
+#include "llvm/CodeGen/ValueTypes.h"
#include <string>
#include <vector>
-#include "llvm/CodeGen/ValueTypes.h"
namespace llvm {
class Record;
diff --git a/utils/TableGen/CodeGenMapTable.cpp b/utils/TableGen/CodeGenMapTable.cpp
index 1653d67..ee32aa1 100644
--- a/utils/TableGen/CodeGenMapTable.cpp
+++ b/utils/TableGen/CodeGenMapTable.cpp
@@ -533,12 +533,11 @@ static void emitEnums(raw_ostream &OS, RecordKeeper &Records) {
II = ColFieldValueMap.begin(), IE = ColFieldValueMap.end();
II != IE; II++) {
std::vector<Init*> FieldValues = (*II).second;
- unsigned FieldSize = FieldValues.size();
// Delete duplicate entries from ColFieldValueMap
- for (unsigned i = 0; i < FieldSize - 1; i++) {
+ for (unsigned i = 0; i < FieldValues.size() - 1; i++) {
Init *CurVal = FieldValues[i];
- for (unsigned j = i+1; j < FieldSize; j++) {
+ for (unsigned j = i+1; j < FieldValues.size(); j++) {
if (CurVal == FieldValues[j]) {
FieldValues.erase(FieldValues.begin()+j);
}
@@ -547,9 +546,9 @@ static void emitEnums(raw_ostream &OS, RecordKeeper &Records) {
// Emit enumerated values for the column fields.
OS << "enum " << (*II).first << " {\n";
- for (unsigned i = 0; i < FieldSize; i++) {
+ for (unsigned i = 0, endFV = FieldValues.size(); i < endFV; i++) {
OS << "\t" << (*II).first << "_" << FieldValues[i]->getAsUnquotedString();
- if (i != FieldValues.size() - 1)
+ if (i != endFV - 1)
OS << ",\n";
else
OS << "\n};\n\n";
diff --git a/utils/TableGen/CodeGenRegisters.cpp b/utils/TableGen/CodeGenRegisters.cpp
index 580e319..993b8db 100644
--- a/utils/TableGen/CodeGenRegisters.cpp
+++ b/utils/TableGen/CodeGenRegisters.cpp
@@ -14,12 +14,12 @@
#include "CodeGenRegisters.h"
#include "CodeGenTarget.h"
-#include "llvm/TableGen/Error.h"
#include "llvm/ADT/IntEqClasses.h"
-#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/Twine.h"
+#include "llvm/TableGen/Error.h"
using namespace llvm;
@@ -636,8 +636,10 @@ struct TupleExpander : SetTheory::Expander {
Elts.insert(NewReg);
// Copy Proto super-classes.
- for (unsigned i = 0, e = Proto->getSuperClasses().size(); i != e; ++i)
- NewReg->addSuperClass(Proto->getSuperClasses()[i]);
+ ArrayRef<Record *> Supers = Proto->getSuperClasses();
+ ArrayRef<SMRange> Ranges = Proto->getSuperClassRanges();
+ for (unsigned i = 0, e = Supers.size(); i != e; ++i)
+ NewReg->addSuperClass(Supers[i], Ranges[i]);
// Copy Proto fields.
for (unsigned i = 0, e = Proto->getValues().size(); i != e; ++i) {
@@ -701,7 +703,9 @@ CodeGenRegisterClass::CodeGenRegisterClass(CodeGenRegBank &RegBank, Record *R)
// Rename anonymous register classes.
if (R->getName().size() > 9 && R->getName()[9] == '.') {
static unsigned AnonCounter = 0;
- R->setName("AnonRegClass_"+utostr(AnonCounter++));
+ R->setName("AnonRegClass_" + utostr(AnonCounter));
+ // MSVC2012 ICEs if AnonCounter++ is directly passed to utostr.
+ ++AnonCounter;
}
std::vector<Record*> TypeList = R->getValueAsListOfDefs("RegTypes");
@@ -1196,6 +1200,12 @@ void CodeGenRegBank::computeSubRegIndexLaneMasks() {
if (Idx->getComposites().empty()) {
Idx->LaneMask = 1u << Bit;
// Share bit 31 in the unlikely case there are more than 32 leafs.
+ //
+ // Sharing bits is harmless; it allows graceful degradation in targets
+ // with more than 32 vector lanes. They simply get a limited resolution
+ // view of lanes beyond the 32nd.
+ //
+ // See also the comment for getSubRegIndexLaneMask().
if (Bit < 31) ++Bit;
} else {
Idx->LaneMask = 0;
@@ -1589,6 +1599,35 @@ void CodeGenRegBank::computeRegUnitSets() {
}
assert(!RegClassUnitSets[RCIdx].empty() && "missing unit set for regclass");
}
+
+ // For each register unit, ensure that we have the list of UnitSets that
+ // contain the unit. Normally, this matches an existing list of UnitSets for a
+ // register class. If not, we create a new entry in RegClassUnitSets as a
+ // "fake" register class.
+ for (unsigned UnitIdx = 0, UnitEnd = NumNativeRegUnits;
+ UnitIdx < UnitEnd; ++UnitIdx) {
+ std::vector<unsigned> RUSets;
+ for (unsigned i = 0, e = RegUnitSets.size(); i != e; ++i) {
+ RegUnitSet &RUSet = RegUnitSets[i];
+ if (std::find(RUSet.Units.begin(), RUSet.Units.end(), UnitIdx)
+ == RUSet.Units.end())
+ continue;
+ RUSets.push_back(i);
+ }
+ unsigned RCUnitSetsIdx = 0;
+ for (unsigned e = RegClassUnitSets.size();
+ RCUnitSetsIdx != e; ++RCUnitSetsIdx) {
+ if (RegClassUnitSets[RCUnitSetsIdx] == RUSets) {
+ break;
+ }
+ }
+ RegUnits[UnitIdx].RegClassUnitSetsIdx = RCUnitSetsIdx;
+ if (RCUnitSetsIdx == RegClassUnitSets.size()) {
+ // Create a new list of UnitSets as a "fake" register class.
+ RegClassUnitSets.resize(RCUnitSetsIdx + 1);
+ RegClassUnitSets[RCUnitSetsIdx].swap(RUSets);
+ }
+ }
}
void CodeGenRegBank::computeDerivedInfo() {
diff --git a/utils/TableGen/CodeGenRegisters.h b/utils/TableGen/CodeGenRegisters.h
index e411074..4f2cc28 100644
--- a/utils/TableGen/CodeGenRegisters.h
+++ b/utils/TableGen/CodeGenRegisters.h
@@ -16,17 +16,17 @@
#define CODEGEN_REGISTERS_H
#include "SetTheory.h"
-#include "llvm/TableGen/Record.h"
-#include "llvm/CodeGen/ValueTypes.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SetVector.h"
+#include "llvm/CodeGen/ValueTypes.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/TableGen/Record.h"
#include <cstdlib>
#include <map>
-#include <string>
#include <set>
+#include <string>
#include <vector>
namespace llvm {
@@ -261,7 +261,7 @@ namespace llvm {
public:
unsigned EnumValue;
std::string Namespace;
- std::vector<MVT::SimpleValueType> VTs;
+ SmallVector<MVT::SimpleValueType, 4> VTs;
unsigned SpillSize;
unsigned SpillAlignment;
int CopyCost;
@@ -274,7 +274,7 @@ namespace llvm {
const std::string &getName() const { return Name; }
std::string getQualifiedName() const;
- const std::vector<MVT::SimpleValueType> &getValueTypes() const {return VTs;}
+ ArrayRef<MVT::SimpleValueType> getValueTypes() const {return VTs;}
unsigned getNumValueTypes() const { return VTs.size(); }
MVT::SimpleValueType getValueTypeNum(unsigned VTNum) const {
@@ -403,7 +403,11 @@ namespace llvm {
// these two registers and their super-registers.
const CodeGenRegister *Roots[2];
- RegUnit() : Weight(0) { Roots[0] = Roots[1] = 0; }
+ // Index into RegClassUnitSets where we can find the list of UnitSets that
+ // contain this unit.
+ unsigned RegClassUnitSetsIdx;
+
+ RegUnit() : Weight(0), RegClassUnitSetsIdx(0) { Roots[0] = Roots[1] = 0; }
ArrayRef<const CodeGenRegister*> getRoots() const {
assert(!(Roots[1] && !Roots[0]) && "Invalid roots array");
@@ -462,6 +466,10 @@ namespace llvm {
// Map RegisterClass index to the index of the RegUnitSet that contains the
// class's units and any inferred RegUnit supersets.
+ //
+ // NOTE: This could grow beyond the number of register classes when we map
+ // register units to lists of unit sets. If the list of unit sets does not
+ // already exist for a register class, we create a new entry in this vector.
std::vector<std::vector<unsigned> > RegClassUnitSets;
// Add RC to *2RC maps.
@@ -615,6 +623,13 @@ namespace llvm {
return RegUnitSets[Idx];
}
+ // The number of pressure set lists may be larget than the number of
+ // register classes if some register units appeared in a list of sets that
+ // did not correspond to an existing register class.
+ unsigned getNumRegClassPressureSetLists() const {
+ return RegClassUnitSets.size();
+ }
+
// Get a list of pressure set IDs for a register class. Liveness of a
// register in this class impacts each pressure set in this list by the
// weight of the register. An exact solution requires all registers in a
diff --git a/utils/TableGen/CodeGenSchedule.cpp b/utils/TableGen/CodeGenSchedule.cpp
index 63cc97a..c02f084 100644
--- a/utils/TableGen/CodeGenSchedule.cpp
+++ b/utils/TableGen/CodeGenSchedule.cpp
@@ -16,10 +16,10 @@
#include "CodeGenSchedule.h"
#include "CodeGenTarget.h"
-#include "llvm/TableGen/Error.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Regex.h"
-#include "llvm/ADT/STLExtras.h"
+#include "llvm/TableGen/Error.h"
using namespace llvm;
@@ -88,7 +88,7 @@ struct InstRegexOp : public SetTheory::Operator {
/// CodeGenModels ctor interprets machine model records and populates maps.
CodeGenSchedModels::CodeGenSchedModels(RecordKeeper &RK,
const CodeGenTarget &TGT):
- Records(RK), Target(TGT), NumItineraryClasses(0) {
+ Records(RK), Target(TGT) {
Sets.addFieldExpander("InstRW", "Instrs");
@@ -217,7 +217,7 @@ void CodeGenSchedModels::collectSchedRW() {
for (CodeGenTarget::inst_iterator I = Target.inst_begin(),
E = Target.inst_end(); I != E; ++I) {
Record *SchedDef = (*I)->TheDef;
- if (!SchedDef->isSubClassOf("Sched"))
+ if (SchedDef->isValueUnset("SchedRW"))
continue;
RecVec RWs = SchedDef->getValueAsListOfDefs("SchedRW");
for (RecIter RWI = RWs.begin(), RWE = RWs.end(); RWI != RWE; ++RWI) {
@@ -502,40 +502,25 @@ void CodeGenSchedModels::collectSchedClasses() {
// NoItinerary is always the first class at Idx=0
SchedClasses.resize(1);
- SchedClasses.back().Name = "NoItinerary";
+ SchedClasses.back().Index = 0;
+ SchedClasses.back().Name = "NoInstrModel";
+ SchedClasses.back().ItinClassDef = Records.getDef("NoItinerary");
SchedClasses.back().ProcIndices.push_back(0);
- SchedClassIdxMap[SchedClasses.back().Name] = 0;
- // Gather and sort all itinerary classes used by instruction descriptions.
- RecVec ItinClassList;
+ // Create a SchedClass for each unique combination of itinerary class and
+ // SchedRW list.
for (CodeGenTarget::inst_iterator I = Target.inst_begin(),
E = Target.inst_end(); I != E; ++I) {
Record *ItinDef = (*I)->TheDef->getValueAsDef("Itinerary");
- // Map a new SchedClass with no index.
- if (!SchedClassIdxMap.count(ItinDef->getName())) {
- SchedClassIdxMap[ItinDef->getName()] = 0;
- ItinClassList.push_back(ItinDef);
- }
- }
- // Assign each itinerary class unique number, skipping NoItinerary==0
- NumItineraryClasses = ItinClassList.size();
- std::sort(ItinClassList.begin(), ItinClassList.end(), LessRecord());
- for (unsigned i = 0, N = NumItineraryClasses; i < N; i++) {
- Record *ItinDef = ItinClassList[i];
- SchedClassIdxMap[ItinDef->getName()] = SchedClasses.size();
- SchedClasses.push_back(CodeGenSchedClass(ItinDef));
- }
- // Infer classes from SchedReadWrite resources listed for each
- // instruction definition that inherits from class Sched.
- for (CodeGenTarget::inst_iterator I = Target.inst_begin(),
- E = Target.inst_end(); I != E; ++I) {
- if (!(*I)->TheDef->isSubClassOf("Sched"))
- continue;
IdxVec Writes, Reads;
- findRWs((*I)->TheDef->getValueAsListOfDefs("SchedRW"), Writes, Reads);
+ if (!(*I)->TheDef->isValueUnset("SchedRW"))
+ findRWs((*I)->TheDef->getValueAsListOfDefs("SchedRW"), Writes, Reads);
+
// ProcIdx == 0 indicates the class applies to all processors.
IdxVec ProcIndices(1, 0);
- addSchedClass(Writes, Reads, ProcIndices);
+
+ unsigned SCIdx = addSchedClass(ItinDef, Writes, Reads, ProcIndices);
+ InstrClassMap[(*I)->TheDef] = SCIdx;
}
// Create classes for InstRW defs.
RecVec InstRWDefs = Records.getAllDerivedDefinitions("InstRW");
@@ -549,68 +534,70 @@ void CodeGenSchedModels::collectSchedClasses() {
DEBUG(EnableDump = true);
if (!EnableDump)
return;
+
for (CodeGenTarget::inst_iterator I = Target.inst_begin(),
E = Target.inst_end(); I != E; ++I) {
- Record *SchedDef = (*I)->TheDef;
+
std::string InstName = (*I)->TheDef->getName();
- if (SchedDef->isSubClassOf("Sched")) {
+ unsigned SCIdx = InstrClassMap.lookup((*I)->TheDef);
+ if (!SCIdx) {
+ dbgs() << "No machine model for " << (*I)->TheDef->getName() << '\n';
+ continue;
+ }
+ CodeGenSchedClass &SC = getSchedClass(SCIdx);
+ if (SC.ProcIndices[0] != 0)
+ PrintFatalError((*I)->TheDef->getLoc(), "Instruction's sched class "
+ "must not be subtarget specific.");
+
+ IdxVec ProcIndices;
+ if (SC.ItinClassDef->getName() != "NoItinerary") {
+ ProcIndices.push_back(0);
+ dbgs() << "Itinerary for " << InstName << ": "
+ << SC.ItinClassDef->getName() << '\n';
+ }
+ if (!SC.Writes.empty()) {
+ ProcIndices.push_back(0);
+ dbgs() << "SchedRW machine model for " << InstName;
+ for (IdxIter WI = SC.Writes.begin(), WE = SC.Writes.end(); WI != WE; ++WI)
+ dbgs() << " " << SchedWrites[*WI].Name;
+ for (IdxIter RI = SC.Reads.begin(), RE = SC.Reads.end(); RI != RE; ++RI)
+ dbgs() << " " << SchedReads[*RI].Name;
+ dbgs() << '\n';
+ }
+ const RecVec &RWDefs = SchedClasses[SCIdx].InstRWs;
+ for (RecIter RWI = RWDefs.begin(), RWE = RWDefs.end();
+ RWI != RWE; ++RWI) {
+ const CodeGenProcModel &ProcModel =
+ getProcModel((*RWI)->getValueAsDef("SchedModel"));
+ ProcIndices.push_back(ProcModel.Index);
+ dbgs() << "InstRW on " << ProcModel.ModelName << " for " << InstName;
IdxVec Writes;
IdxVec Reads;
- findRWs((*I)->TheDef->getValueAsListOfDefs("SchedRW"), Writes, Reads);
- dbgs() << "SchedRW machine model for " << InstName;
+ findRWs((*RWI)->getValueAsListOfDefs("OperandReadWrites"),
+ Writes, Reads);
for (IdxIter WI = Writes.begin(), WE = Writes.end(); WI != WE; ++WI)
dbgs() << " " << SchedWrites[*WI].Name;
for (IdxIter RI = Reads.begin(), RE = Reads.end(); RI != RE; ++RI)
dbgs() << " " << SchedReads[*RI].Name;
dbgs() << '\n';
}
- unsigned SCIdx = InstrClassMap.lookup((*I)->TheDef);
- if (SCIdx) {
- const RecVec &RWDefs = SchedClasses[SCIdx].InstRWs;
- for (RecIter RWI = RWDefs.begin(), RWE = RWDefs.end();
- RWI != RWE; ++RWI) {
- const CodeGenProcModel &ProcModel =
- getProcModel((*RWI)->getValueAsDef("SchedModel"));
- dbgs() << "InstRW on " << ProcModel.ModelName << " for " << InstName;
- IdxVec Writes;
- IdxVec Reads;
- findRWs((*RWI)->getValueAsListOfDefs("OperandReadWrites"),
- Writes, Reads);
- for (IdxIter WI = Writes.begin(), WE = Writes.end(); WI != WE; ++WI)
- dbgs() << " " << SchedWrites[*WI].Name;
- for (IdxIter RI = Reads.begin(), RE = Reads.end(); RI != RE; ++RI)
- dbgs() << " " << SchedReads[*RI].Name;
- dbgs() << '\n';
- }
- continue;
- }
- if (!SchedDef->isSubClassOf("Sched")
- && (SchedDef->getValueAsDef("Itinerary")->getName() == "NoItinerary")) {
- dbgs() << "No machine model for " << (*I)->TheDef->getName() << '\n';
+ for (std::vector<CodeGenProcModel>::iterator PI = ProcModels.begin(),
+ PE = ProcModels.end(); PI != PE; ++PI) {
+ if (!std::count(ProcIndices.begin(), ProcIndices.end(), PI->Index))
+ dbgs() << "No machine model for " << (*I)->TheDef->getName()
+ << " on processor " << PI->ModelName << '\n';
}
}
}
-unsigned CodeGenSchedModels::getSchedClassIdx(
- const RecVec &RWDefs) const {
-
- IdxVec Writes, Reads;
- findRWs(RWDefs, Writes, Reads);
- return findSchedClassIdx(Writes, Reads);
-}
-
/// Find an SchedClass that has been inferred from a per-operand list of
/// SchedWrites and SchedReads.
-unsigned CodeGenSchedModels::findSchedClassIdx(const IdxVec &Writes,
+unsigned CodeGenSchedModels::findSchedClassIdx(Record *ItinClassDef,
+ const IdxVec &Writes,
const IdxVec &Reads) const {
for (SchedClassIter I = schedClassBegin(), E = schedClassEnd(); I != E; ++I) {
- // Classes with InstRWs may have the same Writes/Reads as a class originally
- // produced by a SchedRW definition. We need to be able to recover the
- // original class index for processors that don't match any InstRWs.
- if (I->ItinClassDef || !I->InstRWs.empty())
- continue;
-
- if (I->Writes == Writes && I->Reads == Reads) {
+ if (I->ItinClassDef == ItinClassDef
+ && I->Writes == Writes && I->Reads == Reads) {
return I - schedClassBegin();
}
}
@@ -621,29 +608,17 @@ unsigned CodeGenSchedModels::findSchedClassIdx(const IdxVec &Writes,
unsigned CodeGenSchedModels::getSchedClassIdx(
const CodeGenInstruction &Inst) const {
- unsigned SCIdx = InstrClassMap.lookup(Inst.TheDef);
- if (SCIdx)
- return SCIdx;
-
- // If this opcode isn't mapped by the subtarget fallback to the instruction
- // definition's SchedRW or ItinDef values.
- if (Inst.TheDef->isSubClassOf("Sched")) {
- RecVec RWs = Inst.TheDef->getValueAsListOfDefs("SchedRW");
- return getSchedClassIdx(RWs);
- }
- Record *ItinDef = Inst.TheDef->getValueAsDef("Itinerary");
- assert(SchedClassIdxMap.count(ItinDef->getName()) && "missing ItinClass");
- unsigned Idx = SchedClassIdxMap.lookup(ItinDef->getName());
- assert(Idx <= NumItineraryClasses && "bad ItinClass index");
- return Idx;
+ return InstrClassMap.lookup(Inst.TheDef);
}
std::string CodeGenSchedModels::createSchedClassName(
- const IdxVec &OperWrites, const IdxVec &OperReads) {
+ Record *ItinClassDef, const IdxVec &OperWrites, const IdxVec &OperReads) {
std::string Name;
+ if (ItinClassDef && ItinClassDef->getName() != "NoItinerary")
+ Name = ItinClassDef->getName();
for (IdxIter WI = OperWrites.begin(), WE = OperWrites.end(); WI != WE; ++WI) {
- if (WI != OperWrites.begin())
+ if (!Name.empty())
Name += '_';
Name += SchedWrites[*WI].Name;
}
@@ -665,17 +640,18 @@ std::string CodeGenSchedModels::createSchedClassName(const RecVec &InstDefs) {
return Name;
}
-/// Add an inferred sched class from a per-operand list of SchedWrites and
-/// SchedReads. ProcIndices contains the set of IDs of processors that may
-/// utilize this class.
-unsigned CodeGenSchedModels::addSchedClass(const IdxVec &OperWrites,
+/// Add an inferred sched class from an itinerary class and per-operand list of
+/// SchedWrites and SchedReads. ProcIndices contains the set of IDs of
+/// processors that may utilize this class.
+unsigned CodeGenSchedModels::addSchedClass(Record *ItinClassDef,
+ const IdxVec &OperWrites,
const IdxVec &OperReads,
const IdxVec &ProcIndices)
{
assert(!ProcIndices.empty() && "expect at least one ProcIdx");
- unsigned Idx = findSchedClassIdx(OperWrites, OperReads);
- if (Idx) {
+ unsigned Idx = findSchedClassIdx(ItinClassDef, OperWrites, OperReads);
+ if (Idx || SchedClasses[0].isKeyEqual(ItinClassDef, OperWrites, OperReads)) {
IdxVec PI;
std::set_union(SchedClasses[Idx].ProcIndices.begin(),
SchedClasses[Idx].ProcIndices.end(),
@@ -687,7 +663,9 @@ unsigned CodeGenSchedModels::addSchedClass(const IdxVec &OperWrites,
Idx = SchedClasses.size();
SchedClasses.resize(Idx+1);
CodeGenSchedClass &SC = SchedClasses.back();
- SC.Name = createSchedClassName(OperWrites, OperReads);
+ SC.Index = Idx;
+ SC.Name = createSchedClassName(ItinClassDef, OperWrites, OperReads);
+ SC.ItinClassDef = ItinClassDef;
SC.Writes = OperWrites;
SC.Reads = OperReads;
SC.ProcIndices = ProcIndices;
@@ -709,19 +687,10 @@ void CodeGenSchedModels::createInstRWClass(Record *InstRWDef) {
PrintFatalError(InstRWDef->getLoc(), "No matching instruction opcodes");
for (RecIter I = InstDefs->begin(), E = InstDefs->end(); I != E; ++I) {
- unsigned SCIdx = 0;
InstClassMapTy::const_iterator Pos = InstrClassMap.find(*I);
- if (Pos != InstrClassMap.end())
- SCIdx = Pos->second;
- else {
- // This instruction has not been mapped yet. Get the original class. All
- // instructions in the same InstrRW class must be from the same original
- // class because that is the fall-back class for other processors.
- Record *ItinDef = (*I)->getValueAsDef("Itinerary");
- SCIdx = SchedClassIdxMap.lookup(ItinDef->getName());
- if (!SCIdx && (*I)->isSubClassOf("Sched"))
- SCIdx = getSchedClassIdx((*I)->getValueAsListOfDefs("SchedRW"));
- }
+ if (Pos == InstrClassMap.end())
+ PrintFatalError((*I)->getLoc(), "No sched class for instruction.");
+ unsigned SCIdx = Pos->second;
unsigned CIdx = 0, CEnd = ClassInstrs.size();
for (; CIdx != CEnd; ++CIdx) {
if (ClassInstrs[CIdx].first == SCIdx)
@@ -741,7 +710,7 @@ void CodeGenSchedModels::createInstRWClass(Record *InstRWDef) {
ArrayRef<Record*> InstDefs = ClassInstrs[CIdx].second;
// If the all instrs in the current class are accounted for, then leave
// them mapped to their old class.
- if (SchedClasses[OldSCIdx].InstRWs.size() == InstDefs.size()) {
+ if (OldSCIdx && SchedClasses[OldSCIdx].InstRWs.size() == InstDefs.size()) {
assert(SchedClasses[OldSCIdx].ProcIndices[0] == 0 &&
"expected a generic SchedClass");
continue;
@@ -749,6 +718,7 @@ void CodeGenSchedModels::createInstRWClass(Record *InstRWDef) {
unsigned SCIdx = SchedClasses.size();
SchedClasses.resize(SCIdx+1);
CodeGenSchedClass &SC = SchedClasses.back();
+ SC.Index = SCIdx;
SC.Name = createSchedClassName(InstDefs);
// Preserve ItinDef and Writes/Reads for processors without an InstRW entry.
SC.ItinClassDef = SchedClasses[OldSCIdx].ItinClassDef;
@@ -780,32 +750,48 @@ void CodeGenSchedModels::createInstRWClass(Record *InstRWDef) {
}
}
+// True if collectProcItins found anything.
+bool CodeGenSchedModels::hasItineraries() const {
+ for (CodeGenSchedModels::ProcIter PI = procModelBegin(), PE = procModelEnd();
+ PI != PE; ++PI) {
+ if (PI->hasItineraries())
+ return true;
+ }
+ return false;
+}
+
// Gather the processor itineraries.
void CodeGenSchedModels::collectProcItins() {
for (std::vector<CodeGenProcModel>::iterator PI = ProcModels.begin(),
PE = ProcModels.end(); PI != PE; ++PI) {
CodeGenProcModel &ProcModel = *PI;
- RecVec ItinRecords = ProcModel.ItinsDef->getValueAsListOfDefs("IID");
- // Skip empty itinerary.
- if (ItinRecords.empty())
+ if (!ProcModel.hasItineraries())
continue;
- ProcModel.ItinDefList.resize(NumItineraryClasses+1);
+ RecVec ItinRecords = ProcModel.ItinsDef->getValueAsListOfDefs("IID");
+ assert(!ItinRecords.empty() && "ProcModel.hasItineraries is incorrect");
+
+ // Populate ItinDefList with Itinerary records.
+ ProcModel.ItinDefList.resize(NumInstrSchedClasses);
// Insert each itinerary data record in the correct position within
// the processor model's ItinDefList.
for (unsigned i = 0, N = ItinRecords.size(); i < N; i++) {
Record *ItinData = ItinRecords[i];
Record *ItinDef = ItinData->getValueAsDef("TheClass");
- if (!SchedClassIdxMap.count(ItinDef->getName())) {
+ bool FoundClass = false;
+ for (SchedClassIter SCI = schedClassBegin(), SCE = schedClassEnd();
+ SCI != SCE; ++SCI) {
+ // Multiple SchedClasses may share an itinerary. Update all of them.
+ if (SCI->ItinClassDef == ItinDef) {
+ ProcModel.ItinDefList[SCI->Index] = ItinData;
+ FoundClass = true;
+ }
+ }
+ if (!FoundClass) {
DEBUG(dbgs() << ProcModel.ItinsDef->getName()
- << " has unused itinerary class " << ItinDef->getName() << '\n');
- continue;
+ << " missing class for itinerary " << ItinDef->getName() << '\n');
}
- assert(SchedClassIdxMap.count(ItinDef->getName()) && "missing ItinClass");
- unsigned Idx = SchedClassIdxMap.lookup(ItinDef->getName());
- assert(Idx <= NumItineraryClasses && "bad ItinClass index");
- ProcModel.ItinDefList[Idx] = ItinData;
}
// Check for missing itinerary entries.
assert(!ProcModel.ItinDefList[0] && "NoItinerary class can't have rec");
@@ -839,13 +825,17 @@ void CodeGenSchedModels::collectProcItinRW() {
/// Infer new classes from existing classes. In the process, this may create new
/// SchedWrites from sequences of existing SchedWrites.
void CodeGenSchedModels::inferSchedClasses() {
+ DEBUG(dbgs() << NumInstrSchedClasses << " instr sched classes.\n");
+
// Visit all existing classes and newly created classes.
for (unsigned Idx = 0; Idx != SchedClasses.size(); ++Idx) {
+ assert(SchedClasses[Idx].Index == Idx && "bad SCIdx");
+
if (SchedClasses[Idx].ItinClassDef)
inferFromItinClass(SchedClasses[Idx].ItinClassDef, Idx);
- else if (!SchedClasses[Idx].InstRWs.empty())
+ if (!SchedClasses[Idx].InstRWs.empty())
inferFromInstRWs(Idx);
- else {
+ if (!SchedClasses[Idx].Writes.empty()) {
inferFromRW(SchedClasses[Idx].Writes, SchedClasses[Idx].Reads,
Idx, SchedClasses[Idx].ProcIndices);
}
@@ -1042,11 +1032,13 @@ static bool hasVariant(ArrayRef<PredTransition> Transitions,
// Populate IntersectingVariants with any variants or aliased sequences of the
// given SchedRW whose processor indices and predicates are not mutually
-// exclusive with the given transition,
+// exclusive with the given transition.
void PredTransitions::getIntersectingVariants(
const CodeGenSchedRW &SchedRW, unsigned TransIdx,
std::vector<TransVariant> &IntersectingVariants) {
+ bool GenericRW = false;
+
std::vector<TransVariant> Variants;
if (SchedRW.HasVariants) {
unsigned VarProcIdx = 0;
@@ -1058,6 +1050,8 @@ void PredTransitions::getIntersectingVariants(
const RecVec VarDefs = SchedRW.TheDef->getValueAsListOfDefs("Variants");
for (RecIter RI = VarDefs.begin(), RE = VarDefs.end(); RI != RE; ++RI)
Variants.push_back(TransVariant(*RI, SchedRW.Index, VarProcIdx, 0));
+ if (VarProcIdx == 0)
+ GenericRW = true;
}
for (RecIter AI = SchedRW.Aliases.begin(), AE = SchedRW.Aliases.end();
AI != AE; ++AI) {
@@ -1081,6 +1075,8 @@ void PredTransitions::getIntersectingVariants(
Variants.push_back(
TransVariant(AliasRW.TheDef, SchedRW.Index, AliasProcIdx, 0));
}
+ if (AliasProcIdx == 0)
+ GenericRW = true;
}
for (unsigned VIdx = 0, VEnd = Variants.size(); VIdx != VEnd; ++VIdx) {
TransVariant &Variant = Variants[VIdx];
@@ -1118,6 +1114,10 @@ void PredTransitions::getIntersectingVariants(
TransVec.push_back(TransVec[TransIdx]);
}
}
+ if (GenericRW && IntersectingVariants.empty()) {
+ PrintFatalError(SchedRW.TheDef->getLoc(), "No variant of this type has "
+ "a matching predicate on any processor");
+ }
}
// Push the Reads/Writes selected by this variant onto the PredTransition
@@ -1215,10 +1215,6 @@ void PredTransitions::substituteVariantOperand(
// This will push a copies of TransVec[TransIdx] on the back of TransVec.
std::vector<TransVariant> IntersectingVariants;
getIntersectingVariants(SchedRW, TransIdx, IntersectingVariants);
- if (IntersectingVariants.empty())
- PrintFatalError(SchedRW.TheDef->getLoc(),
- "No variant of this type has "
- "a matching predicate on any processor");
// Now expand each variant on top of its copy of the transition.
for (std::vector<TransVariant>::const_iterator
IVI = IntersectingVariants.begin(),
@@ -1295,8 +1291,8 @@ static void inferFromTransitions(ArrayRef<PredTransition> LastTransitions,
IdxVec ProcIndices(I->ProcIndices.begin(), I->ProcIndices.end());
CodeGenSchedTransition SCTrans;
SCTrans.ToClassIdx =
- SchedModels.addSchedClass(OperWritesVariant, OperReadsVariant,
- ProcIndices);
+ SchedModels.addSchedClass(/*ItinClassDef=*/0, OperWritesVariant,
+ OperReadsVariant, ProcIndices);
SCTrans.ProcIndices = ProcIndices;
// The final PredTerm is unique set of predicates guarding the transition.
RecVec Preds;
@@ -1318,7 +1314,7 @@ void CodeGenSchedModels::inferFromRW(const IdxVec &OperWrites,
const IdxVec &OperReads,
unsigned FromClassIdx,
const IdxVec &ProcIndices) {
- DEBUG(dbgs() << "INFER RW: ");
+ DEBUG(dbgs() << "INFER RW proc("; dumpIdxVec(ProcIndices); dbgs() << ") ");
// Create a seed transition with an empty PredTerm and the expanded sequences
// of SchedWrites for the current SchedClass.
@@ -1380,8 +1376,22 @@ void CodeGenSchedModels::collectProcResources() {
SCI != SCE; ++SCI) {
if (SCI->ItinClassDef)
collectItinProcResources(SCI->ItinClassDef);
- else
+ else {
+ // This class may have a default ReadWrite list which can be overriden by
+ // InstRW definitions.
+ if (!SCI->InstRWs.empty()) {
+ for (RecIter RWI = SCI->InstRWs.begin(), RWE = SCI->InstRWs.end();
+ RWI != RWE; ++RWI) {
+ Record *RWModelDef = (*RWI)->getValueAsDef("SchedModel");
+ IdxVec ProcIndices(1, getProcModel(RWModelDef).Index);
+ IdxVec Writes, Reads;
+ findRWs((*RWI)->getValueAsListOfDefs("OperandReadWrites"),
+ Writes, Reads);
+ collectRWResources(Writes, Reads, ProcIndices);
+ }
+ }
collectRWResources(SCI->Writes, SCI->Reads, SCI->ProcIndices);
+ }
}
// Add resources separately defined by each subtarget.
RecVec WRDefs = Records.getAllDerivedDefinitions("WriteRes");
@@ -1528,6 +1538,20 @@ Record *CodeGenSchedModels::findProcResUnits(Record *ProcResKind,
ProcUnitDef = *RI;
}
}
+ RecVec ProcResGroups = Records.getAllDerivedDefinitions("ProcResGroup");
+ for (RecIter RI = ProcResGroups.begin(), RE = ProcResGroups.end();
+ RI != RE; ++RI) {
+
+ if (*RI == ProcResKind
+ && (*RI)->getValueAsDef("SchedModel") == PM.ModelDef) {
+ if (ProcUnitDef) {
+ PrintFatalError((*RI)->getLoc(),
+ "Multiple ProcessorResourceUnits associated with "
+ + ProcResKind->getName());
+ }
+ ProcUnitDef = *RI;
+ }
+ }
if (!ProcUnitDef) {
PrintFatalError(ProcResKind->getLoc(),
"No ProcessorResources associated with "
@@ -1549,6 +1573,9 @@ void CodeGenSchedModels::addProcResource(Record *ProcResKind,
return;
PM.ProcResourceDefs.push_back(ProcResUnits);
+ if (ProcResUnits->isSubClassOf("ProcResGroup"))
+ return;
+
if (!ProcResUnits->getValueInit("Super")->isComplete())
return;
@@ -1611,7 +1638,7 @@ void CodeGenSchedRW::dump() const {
}
void CodeGenSchedClass::dump(const CodeGenSchedModels* SchedModels) const {
- dbgs() << "SCHEDCLASS " << Name << '\n'
+ dbgs() << "SCHEDCLASS " << Index << ":" << Name << '\n'
<< " Writes: ";
for (unsigned i = 0, N = Writes.size(); i < N; ++i) {
SchedModels->getSchedWrite(Writes[i]).dump();
@@ -1629,6 +1656,13 @@ void CodeGenSchedClass::dump(const CodeGenSchedModels* SchedModels) const {
}
}
dbgs() << "\n ProcIdx: "; dumpIdxVec(ProcIndices); dbgs() << '\n';
+ if (!Transitions.empty()) {
+ dbgs() << "\n Transitions for Proc ";
+ for (std::vector<CodeGenSchedTransition>::const_iterator
+ TI = Transitions.begin(), TE = Transitions.end(); TI != TE; ++TI) {
+ dumpIdxVec(TI->ProcIndices);
+ }
+ }
}
void PredTransitions::dump() const {
diff --git a/utils/TableGen/CodeGenSchedule.h b/utils/TableGen/CodeGenSchedule.h
index eed0589..e5b9118 100644
--- a/utils/TableGen/CodeGenSchedule.h
+++ b/utils/TableGen/CodeGenSchedule.h
@@ -16,10 +16,10 @@
#define CODEGEN_SCHEDULE_H
#include "SetTheory.h"
-#include "llvm/TableGen/Record.h"
-#include "llvm/Support/ErrorHandling.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/TableGen/Record.h"
namespace llvm {
@@ -55,10 +55,11 @@ struct CodeGenSchedRW {
IdxVec Sequence;
RecVec Aliases;
- CodeGenSchedRW(): Index(0), TheDef(0), IsAlias(false), HasVariants(false),
- IsVariadic(false), IsSequence(false) {}
- CodeGenSchedRW(unsigned Idx, Record *Def): Index(Idx), TheDef(Def),
- IsAlias(false), IsVariadic(false) {
+ CodeGenSchedRW()
+ : Index(0), TheDef(0), IsRead(false), IsAlias(false),
+ HasVariants(false), IsVariadic(false), IsSequence(false) {}
+ CodeGenSchedRW(unsigned Idx, Record *Def)
+ : Index(Idx), TheDef(Def), IsAlias(false), IsVariadic(false) {
Name = Def->getName();
IsRead = Def->isSubClassOf("SchedRead");
HasVariants = Def->isSubClassOf("SchedVariant");
@@ -72,9 +73,9 @@ struct CodeGenSchedRW {
}
CodeGenSchedRW(unsigned Idx, bool Read, const IdxVec &Seq,
- const std::string &Name):
- Index(Idx), Name(Name), TheDef(0), IsRead(Read), IsAlias(false),
- HasVariants(false), IsVariadic(false), IsSequence(true), Sequence(Seq) {
+ const std::string &Name)
+ : Index(Idx), Name(Name), TheDef(0), IsRead(Read), IsAlias(false),
+ HasVariants(false), IsVariadic(false), IsSequence(true), Sequence(Seq) {
assert(Sequence.size() > 1 && "implied sequence needs >1 RWs");
}
@@ -124,6 +125,7 @@ struct CodeGenSchedTransition {
/// itinerary class. Each inherits the processor index from the ItinRW record
/// that mapped the itinerary class to the variant Writes or Reads.
struct CodeGenSchedClass {
+ unsigned Index;
std::string Name;
Record *ItinClassDef;
@@ -140,12 +142,16 @@ struct CodeGenSchedClass {
// off to join another inferred class.
RecVec InstRWs;
- CodeGenSchedClass(): ItinClassDef(0) {}
- CodeGenSchedClass(Record *rec): ItinClassDef(rec) {
- Name = rec->getName();
- ProcIndices.push_back(0);
+ CodeGenSchedClass(): Index(0), ItinClassDef(0) {}
+
+ bool isKeyEqual(Record *IC, const IdxVec &W, const IdxVec &R) {
+ return ItinClassDef == IC && Writes == W && Reads == R;
}
+ // Is this class generated from a variants if existing classes? Instructions
+ // are never mapped directly to inferred scheduling classes.
+ bool isInferred() const { return !ItinClassDef; }
+
#ifndef NDEBUG
void dump(const CodeGenSchedModels *SchedModels) const;
#endif
@@ -188,11 +194,16 @@ struct CodeGenProcModel {
// Per-operand machine model resources associated with this processor.
RecVec ProcResourceDefs;
+ RecVec ProcResGroupDefs;
CodeGenProcModel(unsigned Idx, const std::string &Name, Record *MDef,
Record *IDef) :
Index(Idx), ModelName(Name), ModelDef(MDef), ItinsDef(IDef) {}
+ bool hasItineraries() const {
+ return !ItinsDef->getValueAsListOfDefs("IID").empty();
+ }
+
bool hasInstrSchedModel() const {
return !WriteResDefs.empty() || !ItinRWDefs.empty();
}
@@ -226,24 +237,11 @@ class CodeGenSchedModels {
// List of unique SchedClasses.
std::vector<CodeGenSchedClass> SchedClasses;
- // Map SchedClass name to itinerary index.
- // These are either explicit itinerary classes or classes implied by
- // instruction definitions with SchedReadWrite lists.
- StringMap<unsigned> SchedClassIdxMap;
-
- // SchedClass indices 1 up to and including NumItineraryClasses identify
- // itinerary classes that are explicitly used for this target's instruction
- // definitions. NoItinerary always has index 0 regardless of whether it is
- // explicitly referenced.
- //
- // Any implied SchedClass has an index greater than NumItineraryClasses.
- unsigned NumItineraryClasses;
-
// Any inferred SchedClass has an index greater than NumInstrSchedClassses.
unsigned NumInstrSchedClasses;
- // Map Instruction to SchedClass index. Only for Instructions mentioned in
- // InstRW records.
+ // Map each instruction to its unique SchedClass index considering the
+ // combination of it's itinerary class, SchedRW list, and InstRW records.
typedef DenseMap<Record*, unsigned> InstClassMapTy;
InstClassMapTy InstrClassMap;
@@ -279,6 +277,9 @@ public:
ProcIter procModelBegin() const { return ProcModels.begin(); }
ProcIter procModelEnd() const { return ProcModels.end(); }
+ // Return true if any processors have itineraries.
+ bool hasItineraries() const;
+
// Get a SchedWrite from its index.
const CodeGenSchedRW &getSchedWrite(unsigned Idx) const {
assert(Idx < SchedWrites.size() && "bad SchedWrite index");
@@ -310,16 +311,6 @@ public:
// Return true if the given write record is referenced by a ReadAdvance.
bool hasReadOfWrite(Record *WriteDef) const;
- // Check if any instructions are assigned to an explicit itinerary class other
- // than NoItinerary.
- bool hasItineraryClasses() const { return NumItineraryClasses > 0; }
-
- // Return the number of itinerary classes in use by this target's instruction
- // descriptions, not including "NoItinerary".
- unsigned numItineraryClasses() const {
- return NumItineraryClasses;
- }
-
// Get a SchedClass from its index.
CodeGenSchedClass &getSchedClass(unsigned Idx) {
assert(Idx < SchedClasses.size() && "bad SchedClass index");
@@ -335,28 +326,26 @@ public:
// for NoItinerary.
unsigned getSchedClassIdx(const CodeGenInstruction &Inst) const;
- unsigned getSchedClassIdx(const RecVec &RWDefs) const;
-
- unsigned getSchedClassIdxForItin(const Record *ItinDef) {
- return SchedClassIdxMap[ItinDef->getName()];
- }
-
typedef std::vector<CodeGenSchedClass>::const_iterator SchedClassIter;
SchedClassIter schedClassBegin() const { return SchedClasses.begin(); }
SchedClassIter schedClassEnd() const { return SchedClasses.end(); }
+ unsigned numInstrSchedClasses() const { return NumInstrSchedClasses; }
+
void findRWs(const RecVec &RWDefs, IdxVec &Writes, IdxVec &Reads) const;
void findRWs(const RecVec &RWDefs, IdxVec &RWs, bool IsRead) const;
void expandRWSequence(unsigned RWIdx, IdxVec &RWSeq, bool IsRead) const;
void expandRWSeqForProc(unsigned RWIdx, IdxVec &RWSeq, bool IsRead,
const CodeGenProcModel &ProcModel) const;
- unsigned addSchedClass(const IdxVec &OperWrites, const IdxVec &OperReads,
- const IdxVec &ProcIndices);
+ unsigned addSchedClass(Record *ItinDef, const IdxVec &OperWrites,
+ const IdxVec &OperReads, const IdxVec &ProcIndices);
unsigned findOrInsertRW(ArrayRef<unsigned> Seq, bool IsRead);
- unsigned findSchedClassIdx(const IdxVec &Writes, const IdxVec &Reads) const;
+ unsigned findSchedClassIdx(Record *ItinClassDef,
+ const IdxVec &Writes,
+ const IdxVec &Reads) const;
Record *findProcResUnits(Record *ProcResKind,
const CodeGenProcModel &PM) const;
@@ -374,7 +363,8 @@ private:
void collectSchedClasses();
- std::string createSchedClassName(const IdxVec &OperWrites,
+ std::string createSchedClassName(Record *ItinClassDef,
+ const IdxVec &OperWrites,
const IdxVec &OperReads);
std::string createSchedClassName(const RecVec &InstDefs);
void createInstRWClass(Record *InstRWDef);
diff --git a/utils/TableGen/CodeGenTarget.cpp b/utils/TableGen/CodeGenTarget.cpp
index c9992eb..8b292b9 100644
--- a/utils/TableGen/CodeGenTarget.cpp
+++ b/utils/TableGen/CodeGenTarget.cpp
@@ -17,11 +17,11 @@
#include "CodeGenTarget.h"
#include "CodeGenIntrinsics.h"
#include "CodeGenSchedule.h"
-#include "llvm/TableGen/Error.h"
-#include "llvm/TableGen/Record.h"
-#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/CommandLine.h"
+#include "llvm/TableGen/Error.h"
+#include "llvm/TableGen/Record.h"
#include <algorithm>
using namespace llvm;
@@ -73,16 +73,20 @@ std::string llvm::getEnumName(MVT::SimpleValueType T) {
case MVT::v4i1: return "MVT::v4i1";
case MVT::v8i1: return "MVT::v8i1";
case MVT::v16i1: return "MVT::v16i1";
+ case MVT::v32i1: return "MVT::v32i1";
+ case MVT::v64i1: return "MVT::v64i1";
case MVT::v2i8: return "MVT::v2i8";
case MVT::v4i8: return "MVT::v4i8";
case MVT::v8i8: return "MVT::v8i8";
case MVT::v16i8: return "MVT::v16i8";
case MVT::v32i8: return "MVT::v32i8";
+ case MVT::v64i8: return "MVT::v64i8";
case MVT::v1i16: return "MVT::v1i16";
case MVT::v2i16: return "MVT::v2i16";
case MVT::v4i16: return "MVT::v4i16";
case MVT::v8i16: return "MVT::v8i16";
case MVT::v16i16: return "MVT::v16i16";
+ case MVT::v32i16: return "MVT::v32i16";
case MVT::v1i32: return "MVT::v1i32";
case MVT::v2i32: return "MVT::v2i32";
case MVT::v4i32: return "MVT::v4i32";
@@ -97,8 +101,10 @@ std::string llvm::getEnumName(MVT::SimpleValueType T) {
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::v2f64: return "MVT::v2f64";
case MVT::v4f64: return "MVT::v4f64";
+ case MVT::v8f64: return "MVT::v8f64";
case MVT::Metadata: return "MVT::Metadata";
case MVT::iPTR: return "MVT::iPTR";
case MVT::iPTRAny: return "MVT::iPTRAny";
@@ -223,7 +229,7 @@ getRegisterVTs(Record *R) const {
for (unsigned i = 0, e = RCs.size(); i != e; ++i) {
const CodeGenRegisterClass &RC = *RCs[i];
if (RC.contains(Reg)) {
- const std::vector<MVT::SimpleValueType> &InVTs = RC.getValueTypes();
+ ArrayRef<MVT::SimpleValueType> InVTs = RC.getValueTypes();
Result.insert(Result.end(), InVTs.begin(), InVTs.end());
}
}
diff --git a/utils/TableGen/CodeGenTarget.h b/utils/TableGen/CodeGenTarget.h
index ddeecee..6271443 100644
--- a/utils/TableGen/CodeGenTarget.h
+++ b/utils/TableGen/CodeGenTarget.h
@@ -17,10 +17,10 @@
#ifndef CODEGEN_TARGET_H
#define CODEGEN_TARGET_H
-#include "CodeGenRegisters.h"
#include "CodeGenInstruction.h"
-#include "llvm/TableGen/Record.h"
+#include "CodeGenRegisters.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/TableGen/Record.h"
#include <algorithm>
namespace llvm {
@@ -68,7 +68,7 @@ class CodeGenTarget {
mutable DenseMap<const Record*, CodeGenInstruction*> Instructions;
mutable CodeGenRegBank *RegBank;
mutable std::vector<Record*> RegAltNameIndices;
- mutable std::vector<MVT::SimpleValueType> LegalValueTypes;
+ mutable SmallVector<MVT::SimpleValueType, 8> LegalValueTypes;
void ReadRegAltNameIndices() const;
void ReadInstructions() const;
void ReadLegalValueTypes() const;
@@ -129,7 +129,7 @@ public:
/// specified physical register.
std::vector<MVT::SimpleValueType> getRegisterVTs(Record *R) const;
- const std::vector<MVT::SimpleValueType> &getLegalValueTypes() const {
+ ArrayRef<MVT::SimpleValueType> getLegalValueTypes() const {
if (LegalValueTypes.empty()) ReadLegalValueTypes();
return LegalValueTypes;
}
@@ -137,7 +137,7 @@ public:
/// isLegalValueType - Return true if the specified value type is natively
/// supported by the target (i.e. there are registers that directly hold it).
bool isLegalValueType(MVT::SimpleValueType VT) const {
- const std::vector<MVT::SimpleValueType> &LegalVTs = getLegalValueTypes();
+ ArrayRef<MVT::SimpleValueType> LegalVTs = getLegalValueTypes();
for (unsigned i = 0, e = LegalVTs.size(); i != e; ++i)
if (LegalVTs[i] == VT) return true;
return false;
diff --git a/utils/TableGen/DAGISelMatcher.cpp b/utils/TableGen/DAGISelMatcher.cpp
index bd77907..d173cf0 100644
--- a/utils/TableGen/DAGISelMatcher.cpp
+++ b/utils/TableGen/DAGISelMatcher.cpp
@@ -10,9 +10,9 @@
#include "DAGISelMatcher.h"
#include "CodeGenDAGPatterns.h"
#include "CodeGenTarget.h"
-#include "llvm/TableGen/Record.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/TableGen/Record.h"
using namespace llvm;
void Matcher::anchor() { }
diff --git a/utils/TableGen/DAGISelMatcher.h b/utils/TableGen/DAGISelMatcher.h
index 7c6ce3b..f978188 100644
--- a/utils/TableGen/DAGISelMatcher.h
+++ b/utils/TableGen/DAGISelMatcher.h
@@ -10,10 +10,10 @@
#ifndef TBLGEN_DAGISELMATCHER_H
#define TBLGEN_DAGISELMATCHER_H
-#include "llvm/CodeGen/ValueTypes.h"
#include "llvm/ADT/OwningPtr.h"
-#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/CodeGen/ValueTypes.h"
#include "llvm/Support/Casting.h"
namespace llvm {
diff --git a/utils/TableGen/DAGISelMatcherEmitter.cpp b/utils/TableGen/DAGISelMatcherEmitter.cpp
index 713f174..93f84ce 100644
--- a/utils/TableGen/DAGISelMatcherEmitter.cpp
+++ b/utils/TableGen/DAGISelMatcherEmitter.cpp
@@ -13,12 +13,12 @@
#include "DAGISelMatcher.h"
#include "CodeGenDAGPatterns.h"
-#include "llvm/TableGen/Record.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FormattedStream.h"
+#include "llvm/TableGen/Record.h"
using namespace llvm;
enum {
@@ -132,7 +132,7 @@ static uint64_t EmitVBRValue(uint64_t Val, raw_ostream &OS) {
return NumBytes+1;
}
-/// EmitMatcherOpcodes - Emit bytes for the specified matcher and return
+/// EmitMatcher - Emit bytes for the specified matcher and return
/// the number of bytes emitted.
unsigned MatcherTableEmitter::
EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
diff --git a/utils/TableGen/DAGISelMatcherGen.cpp b/utils/TableGen/DAGISelMatcherGen.cpp
index 573f558..ed41631 100644
--- a/utils/TableGen/DAGISelMatcherGen.cpp
+++ b/utils/TableGen/DAGISelMatcherGen.cpp
@@ -10,11 +10,11 @@
#include "DAGISelMatcher.h"
#include "CodeGenDAGPatterns.h"
#include "CodeGenRegisters.h"
-#include "llvm/TableGen/Error.h"
-#include "llvm/TableGen/Record.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
+#include "llvm/TableGen/Error.h"
+#include "llvm/TableGen/Record.h"
#include <utility>
using namespace llvm;
@@ -211,6 +211,12 @@ void MatcherGen::EmitLeafMatchCode(const TreePatternNode *N) {
return AddMatcher(new CheckIntegerMatcher(II->getValue()));
}
+ // An UnsetInit represents a named node without any constraints.
+ if (N->getLeafValue() == UnsetInit::get()) {
+ assert(N->hasName() && "Unnamed ? leaf");
+ return;
+ }
+
DefInit *DI = dyn_cast<DefInit>(N->getLeafValue());
if (DI == 0) {
errs() << "Unknown leaf kind: " << *N << "\n";
@@ -218,6 +224,17 @@ void MatcherGen::EmitLeafMatchCode(const TreePatternNode *N) {
}
Record *LeafRec = DI->getDef();
+
+ // A ValueType leaf node can represent a register when named, or itself when
+ // unnamed.
+ if (LeafRec->isSubClassOf("ValueType")) {
+ // A named ValueType leaf always matches: (add i32:$a, i32:$b).
+ if (N->hasName())
+ return;
+ // An unnamed ValueType as in (sext_inreg GPR:$foo, i8).
+ return AddMatcher(new CheckValueTypeMatcher(LeafRec->getName()));
+ }
+
if (// Handle register references. Nothing to do here, they always match.
LeafRec->isSubClassOf("RegisterClass") ||
LeafRec->isSubClassOf("RegisterOperand") ||
@@ -236,9 +253,6 @@ void MatcherGen::EmitLeafMatchCode(const TreePatternNode *N) {
return;
}
- if (LeafRec->isSubClassOf("ValueType"))
- return AddMatcher(new CheckValueTypeMatcher(LeafRec->getName()));
-
if (LeafRec->isSubClassOf("CondCode"))
return AddMatcher(new CheckCondCodeMatcher(LeafRec->getName()));
@@ -734,20 +748,33 @@ EmitResultInstructionAsOperand(const TreePatternNode *N,
continue;
}
- const TreePatternNode *Child = N->getChild(ChildNo);
-
// Otherwise this is a normal operand or a predicate operand without
// 'execute always'; emit it.
- unsigned BeforeAddingNumOps = InstOps.size();
- EmitResultOperand(Child, InstOps);
- assert(InstOps.size() > BeforeAddingNumOps && "Didn't add any operands");
- // If the operand is an instruction and it produced multiple results, just
- // take the first one.
- if (!Child->isLeaf() && Child->getOperator()->isSubClassOf("Instruction"))
- InstOps.resize(BeforeAddingNumOps+1);
+ // For operands with multiple sub-operands we may need to emit
+ // multiple child patterns to cover them all. However, ComplexPattern
+ // children may themselves emit multiple MI operands.
+ unsigned NumSubOps = 1;
+ if (OperandNode->isSubClassOf("Operand")) {
+ DagInit *MIOpInfo = OperandNode->getValueAsDag("MIOperandInfo");
+ if (unsigned NumArgs = MIOpInfo->getNumArgs())
+ NumSubOps = NumArgs;
+ }
+
+ unsigned FinalNumOps = InstOps.size() + NumSubOps;
+ while (InstOps.size() < FinalNumOps) {
+ const TreePatternNode *Child = N->getChild(ChildNo);
+ unsigned BeforeAddingNumOps = InstOps.size();
+ EmitResultOperand(Child, InstOps);
+ assert(InstOps.size() > BeforeAddingNumOps && "Didn't add any operands");
- ++ChildNo;
+ // If the operand is an instruction and it produced multiple results, just
+ // take the first one.
+ if (!Child->isLeaf() && Child->getOperator()->isSubClassOf("Instruction"))
+ InstOps.resize(BeforeAddingNumOps+1);
+
+ ++ChildNo;
+ }
}
// If this node has input glue or explicitly specified input physregs, we
diff --git a/utils/TableGen/DFAPacketizerEmitter.cpp b/utils/TableGen/DFAPacketizerEmitter.cpp
index 0ad25a5..2549c47 100644
--- a/utils/TableGen/DFAPacketizerEmitter.cpp
+++ b/utils/TableGen/DFAPacketizerEmitter.cpp
@@ -279,6 +279,7 @@ DFAPacketizerEmitter::DFAPacketizerEmitter(RecordKeeper &R):
//
//
void DFA::writeTableAndAPI(raw_ostream &OS, const std::string &TargetName) {
+ static const std::string SentinelEntry = "{-1, -1}";
DFA::StateSet::iterator SI = states.begin();
// This table provides a map to the beginning of the transitions for State s
// in DFAStateInputTable.
@@ -305,12 +306,17 @@ void DFA::writeTableAndAPI(raw_ostream &OS, const std::string &TargetName) {
// If there are no valid transitions from this stage, we need a sentinel
// transition.
if (ValidTransitions == StateEntry[i]) {
- OS << "{-1, -1},";
+ OS << SentinelEntry << ",";
++ValidTransitions;
}
OS << "\n";
}
+
+ // Print out a sentinel entry at the end of the StateInputTable. This is
+ // needed to iterate over StateInputTable in DFAPacketizer::ReadTable()
+ OS << SentinelEntry << "\n";
+
OS << "};\n\n";
OS << "const unsigned int " << TargetName << "DFAStateEntryTable[] = {\n";
@@ -319,6 +325,9 @@ void DFA::writeTableAndAPI(raw_ostream &OS, const std::string &TargetName) {
for (unsigned i = 0; i < states.size(); ++i)
OS << StateEntry[i] << ", ";
+ // Print out the index to the sentinel entry in StateInputTable
+ OS << ValidTransitions << ", ";
+
OS << "\n};\n";
OS << "} // namespace\n";
diff --git a/utils/TableGen/DisassemblerEmitter.cpp b/utils/TableGen/DisassemblerEmitter.cpp
index 2d11d24..5a2a41b 100644
--- a/utils/TableGen/DisassemblerEmitter.cpp
+++ b/utils/TableGen/DisassemblerEmitter.cpp
@@ -127,8 +127,9 @@ void EmitDisassembler(RecordKeeper &Records, raw_ostream &OS) {
// ARM and Thumb have a CHECK() macro to deal with DecodeStatuses.
if (Target.getName() == "ARM" ||
- Target.getName() == "Thumb") {
- EmitFixedLenDecoder(Records, OS, "ARM",
+ Target.getName() == "Thumb" ||
+ Target.getName() == "AArch64") {
+ EmitFixedLenDecoder(Records, OS, Target.getName() == "AArch64" ? "AArch64" : "ARM",
"if (!Check(S, ", ")) return MCDisassembler::Fail;",
"S", "MCDisassembler::Fail",
" MCDisassembler::DecodeStatus S = "
diff --git a/utils/TableGen/EDEmitter.cpp b/utils/TableGen/EDEmitter.cpp
deleted file mode 100644
index ea25450..0000000
--- a/utils/TableGen/EDEmitter.cpp
+++ /dev/null
@@ -1,1011 +0,0 @@
-//===- EDEmitter.cpp - Generate instruction descriptions for ED -*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This tablegen backend is responsible for emitting a description of each
-// instruction in a format that the enhanced disassembler can use to tokenize
-// and parse instructions.
-//
-//===----------------------------------------------------------------------===//
-
-#include "AsmWriterInst.h"
-#include "CodeGenTarget.h"
-#include "llvm/MC/EDInstInfo.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/Format.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/TableGen/Error.h"
-#include "llvm/TableGen/Record.h"
-#include "llvm/TableGen/TableGenBackend.h"
-#include <string>
-#include <vector>
-
-using namespace llvm;
-
-// TODO: There's a suspiciously large amount of "table" data in this
-// backend which should probably be in the TableGen file itself.
-
-///////////////////////////////////////////////////////////
-// Support classes for emitting nested C data structures //
-///////////////////////////////////////////////////////////
-
-// TODO: These classes are probably generally useful to other backends;
-// add them to TableGen's "helper" API's.
-
-namespace {
-class EnumEmitter {
-private:
- std::string Name;
- std::vector<std::string> Entries;
-public:
- EnumEmitter(const char *N) : Name(N) {
- }
- int addEntry(const char *e) {
- Entries.push_back(std::string(e));
- return Entries.size() - 1;
- }
- void emit(raw_ostream &o, unsigned int &i) {
- o.indent(i) << "enum " << Name.c_str() << " {" << "\n";
- i += 2;
-
- unsigned int index = 0;
- unsigned int numEntries = Entries.size();
- for (index = 0; index < numEntries; ++index) {
- o.indent(i) << Entries[index];
- if (index < (numEntries - 1))
- o << ",";
- o << "\n";
- }
-
- i -= 2;
- o.indent(i) << "};" << "\n";
- }
-
- void emitAsFlags(raw_ostream &o, unsigned int &i) {
- o.indent(i) << "enum " << Name.c_str() << " {" << "\n";
- i += 2;
-
- unsigned int index = 0;
- unsigned int numEntries = Entries.size();
- unsigned int flag = 1;
- for (index = 0; index < numEntries; ++index) {
- o.indent(i) << Entries[index] << " = " << format("0x%x", flag);
- if (index < (numEntries - 1))
- o << ",";
- o << "\n";
- flag <<= 1;
- }
-
- i -= 2;
- o.indent(i) << "};" << "\n";
- }
-};
-} // End anonymous namespace
-
-namespace {
-class ConstantEmitter {
-public:
- virtual ~ConstantEmitter() { }
- virtual void emit(raw_ostream &o, unsigned int &i) = 0;
-};
-} // End anonymous namespace
-
-namespace {
-class LiteralConstantEmitter : public ConstantEmitter {
-private:
- bool IsNumber;
- union {
- int Number;
- const char* String;
- };
-public:
- LiteralConstantEmitter(int number = 0) :
- IsNumber(true),
- Number(number) {
- }
- void set(const char *string) {
- IsNumber = false;
- Number = 0;
- String = string;
- }
- bool is(const char *string) {
- return !strcmp(String, string);
- }
- void emit(raw_ostream &o, unsigned int &i) {
- if (IsNumber)
- o << Number;
- else
- o << String;
- }
-};
-} // End anonymous namespace
-
-namespace {
-class CompoundConstantEmitter : public ConstantEmitter {
-private:
- unsigned int Padding;
- std::vector<ConstantEmitter *> Entries;
-public:
- CompoundConstantEmitter(unsigned int padding = 0) : Padding(padding) {
- }
- CompoundConstantEmitter &addEntry(ConstantEmitter *e) {
- Entries.push_back(e);
-
- return *this;
- }
- ~CompoundConstantEmitter() {
- while (Entries.size()) {
- ConstantEmitter *entry = Entries.back();
- Entries.pop_back();
- delete entry;
- }
- }
- void emit(raw_ostream &o, unsigned int &i) {
- o << "{" << "\n";
- i += 2;
-
- unsigned int index;
- unsigned int numEntries = Entries.size();
-
- unsigned int numToPrint;
-
- if (Padding) {
- if (numEntries > Padding) {
- fprintf(stderr, "%u entries but %u padding\n", numEntries, Padding);
- llvm_unreachable("More entries than padding");
- }
- numToPrint = Padding;
- } else {
- numToPrint = numEntries;
- }
-
- for (index = 0; index < numToPrint; ++index) {
- o.indent(i);
- if (index < numEntries)
- Entries[index]->emit(o, i);
- else
- o << "-1";
-
- if (index < (numToPrint - 1))
- o << ",";
- o << "\n";
- }
-
- i -= 2;
- o.indent(i) << "}";
- }
-};
-} // End anonymous namespace
-
-namespace {
-class FlagsConstantEmitter : public ConstantEmitter {
-private:
- std::vector<std::string> Flags;
-public:
- FlagsConstantEmitter() {
- }
- FlagsConstantEmitter &addEntry(const char *f) {
- Flags.push_back(std::string(f));
- return *this;
- }
- void emit(raw_ostream &o, unsigned int &i) {
- unsigned int index;
- unsigned int numFlags = Flags.size();
- if (numFlags == 0)
- o << "0";
-
- for (index = 0; index < numFlags; ++index) {
- o << Flags[index].c_str();
- if (index < (numFlags - 1))
- o << " | ";
- }
- }
-};
-} // End anonymous namespace
-
-/// populateOperandOrder - Accepts a CodeGenInstruction and generates its
-/// AsmWriterInst for the desired assembly syntax, giving an ordered list of
-/// operands in the order they appear in the printed instruction. Then, for
-/// each entry in that list, determines the index of the same operand in the
-/// CodeGenInstruction, and emits the resulting mapping into an array, filling
-/// in unused slots with -1.
-///
-/// @arg operandOrder - The array that will be populated with the operand
-/// mapping. Each entry will contain -1 (invalid index
-/// into the operands present in the AsmString) or a number
-/// representing an index in the operand descriptor array.
-/// @arg inst - The instruction to use when looking up the operands
-/// @arg syntax - The syntax to use, according to LLVM's enumeration
-static void populateOperandOrder(CompoundConstantEmitter *operandOrder,
- const CodeGenInstruction &inst,
- unsigned syntax) {
- unsigned int numArgs = 0;
-
- AsmWriterInst awInst(inst, syntax, -1, -1);
-
- std::vector<AsmWriterOperand>::iterator operandIterator;
-
- for (operandIterator = awInst.Operands.begin();
- operandIterator != awInst.Operands.end();
- ++operandIterator) {
- if (operandIterator->OperandType ==
- AsmWriterOperand::isMachineInstrOperand) {
- operandOrder->addEntry(
- new LiteralConstantEmitter(operandIterator->CGIOpNo));
- numArgs++;
- }
- }
-}
-
-/////////////////////////////////////////////////////
-// Support functions for handling X86 instructions //
-/////////////////////////////////////////////////////
-
-#define SET(flag) { type->set(flag); return 0; }
-
-#define REG(str) if (name == str) SET("kOperandTypeRegister");
-#define MEM(str) if (name == str) SET("kOperandTypeX86Memory");
-#define LEA(str) if (name == str) SET("kOperandTypeX86EffectiveAddress");
-#define IMM(str) if (name == str) SET("kOperandTypeImmediate");
-#define PCR(str) if (name == str) SET("kOperandTypeX86PCRelative");
-
-/// X86TypeFromOpName - Processes the name of a single X86 operand (which is
-/// actually its type) and translates it into an operand type
-///
-/// @arg flags - The type object to set
-/// @arg name - The name of the operand
-static int X86TypeFromOpName(LiteralConstantEmitter *type,
- const std::string &name) {
- REG("GR8");
- REG("GR8_NOREX");
- REG("GR16");
- REG("GR16_NOAX");
- REG("GR32");
- REG("GR32_NOAX");
- REG("GR32_NOREX");
- REG("GR32_TC");
- REG("FR32");
- REG("RFP32");
- REG("GR64");
- REG("GR64_NOAX");
- REG("GR64_TC");
- REG("FR64");
- REG("VR64");
- REG("RFP64");
- REG("RFP80");
- REG("VR128");
- REG("VR256");
- REG("RST");
- REG("SEGMENT_REG");
- REG("DEBUG_REG");
- REG("CONTROL_REG");
-
- IMM("i8imm");
- IMM("i16imm");
- IMM("i16i8imm");
- IMM("i32imm");
- IMM("i32i8imm");
- IMM("u32u8imm");
- IMM("i64imm");
- IMM("i64i8imm");
- IMM("i64i32imm");
- IMM("SSECC");
- IMM("AVXCC");
-
- // all R, I, R, I, R
- MEM("i8mem");
- MEM("i8mem_NOREX");
- MEM("i16mem");
- MEM("i32mem");
- MEM("i32mem_TC");
- MEM("f32mem");
- MEM("ssmem");
- MEM("opaque32mem");
- MEM("opaque48mem");
- MEM("i64mem");
- MEM("i64mem_TC");
- MEM("f64mem");
- MEM("sdmem");
- MEM("f80mem");
- MEM("opaque80mem");
- MEM("i128mem");
- MEM("i256mem");
- MEM("f128mem");
- MEM("f256mem");
- MEM("opaque512mem");
- // Gather
- MEM("vx32mem")
- MEM("vy32mem")
- MEM("vx64mem")
- MEM("vy64mem")
-
- // all R, I, R, I
- LEA("lea32mem");
- LEA("lea64_32mem");
- LEA("lea64mem");
-
- // all I
- PCR("i16imm_pcrel");
- PCR("i32imm_pcrel");
- PCR("i64i32imm_pcrel");
- PCR("brtarget8");
- PCR("offset8");
- PCR("offset16");
- PCR("offset32");
- PCR("offset64");
- PCR("brtarget");
- PCR("uncondbrtarget");
- PCR("bltarget");
-
- // all I, ARM mode only, conditional/unconditional
- PCR("br_target");
- PCR("bl_target");
- return 1;
-}
-
-#undef REG
-#undef MEM
-#undef LEA
-#undef IMM
-#undef PCR
-
-#undef SET
-
-/// X86PopulateOperands - Handles all the operands in an X86 instruction, adding
-/// the appropriate flags to their descriptors
-///
-/// \param operandTypes A reference the array of operand type objects
-/// \param inst The instruction to use as a source of information
-static void X86PopulateOperands(
- LiteralConstantEmitter *(&operandTypes)[EDIS_MAX_OPERANDS],
- const CodeGenInstruction &inst) {
- if (!inst.TheDef->isSubClassOf("X86Inst"))
- return;
-
- unsigned int index;
- unsigned int numOperands = inst.Operands.size();
-
- for (index = 0; index < numOperands; ++index) {
- const CGIOperandList::OperandInfo &operandInfo = inst.Operands[index];
- Record &rec = *operandInfo.Rec;
-
- if (X86TypeFromOpName(operandTypes[index], rec.getName()) &&
- !rec.isSubClassOf("PointerLikeRegClass")) {
- errs() << "Operand type: " << rec.getName().c_str() << "\n";
- errs() << "Operand name: " << operandInfo.Name.c_str() << "\n";
- errs() << "Instruction name: " << inst.TheDef->getName().c_str() << "\n";
- llvm_unreachable("Unhandled type");
- }
- }
-}
-
-/// decorate1 - Decorates a named operand with a new flag
-///
-/// \param operandFlags The array of operand flag objects, which don't have
-/// names
-/// \param inst The CodeGenInstruction, which provides a way to
-// translate between names and operand indices
-/// \param opName The name of the operand
-/// \param opFlag The name of the flag to add
-static inline void decorate1(
- FlagsConstantEmitter *(&operandFlags)[EDIS_MAX_OPERANDS],
- const CodeGenInstruction &inst,
- const char *opName,
- const char *opFlag) {
- unsigned opIndex;
-
- opIndex = inst.Operands.getOperandNamed(std::string(opName));
-
- operandFlags[opIndex]->addEntry(opFlag);
-}
-
-#define DECORATE1(opName, opFlag) decorate1(operandFlags, inst, opName, opFlag)
-
-#define MOV(source, target) { \
- instType.set("kInstructionTypeMove"); \
- DECORATE1(source, "kOperandFlagSource"); \
- DECORATE1(target, "kOperandFlagTarget"); \
-}
-
-#define BRANCH(target) { \
- instType.set("kInstructionTypeBranch"); \
- DECORATE1(target, "kOperandFlagTarget"); \
-}
-
-#define PUSH(source) { \
- instType.set("kInstructionTypePush"); \
- DECORATE1(source, "kOperandFlagSource"); \
-}
-
-#define POP(target) { \
- instType.set("kInstructionTypePop"); \
- DECORATE1(target, "kOperandFlagTarget"); \
-}
-
-#define CALL(target) { \
- instType.set("kInstructionTypeCall"); \
- DECORATE1(target, "kOperandFlagTarget"); \
-}
-
-#define RETURN() { \
- instType.set("kInstructionTypeReturn"); \
-}
-
-/// X86ExtractSemantics - Performs various checks on the name of an X86
-/// instruction to determine what sort of an instruction it is and then adds
-/// the appropriate flags to the instruction and its operands
-///
-/// \param instType A reference to the type for the instruction as a whole
-/// \param operandFlags A reference to the array of operand flag object pointers
-/// \param inst A reference to the original instruction
-static void X86ExtractSemantics(
- LiteralConstantEmitter &instType,
- FlagsConstantEmitter *(&operandFlags)[EDIS_MAX_OPERANDS],
- const CodeGenInstruction &inst) {
- const std::string &name = inst.TheDef->getName();
-
- if (name.find("MOV") != name.npos) {
- if (name.find("MOV_V") != name.npos) {
- // ignore (this is a pseudoinstruction)
- } else if (name.find("MASK") != name.npos) {
- // ignore (this is a masking move)
- } else if (name.find("r0") != name.npos) {
- // ignore (this is a pseudoinstruction)
- } else if (name.find("PS") != name.npos ||
- name.find("PD") != name.npos) {
- // ignore (this is a shuffling move)
- } else if (name.find("MOVS") != name.npos) {
- // ignore (this is a string move)
- } else if (name.find("_F") != name.npos) {
- // TODO handle _F moves to ST(0)
- } else if (name.find("a") != name.npos) {
- // TODO handle moves to/from %ax
- } else if (name.find("CMOV") != name.npos) {
- MOV("src2", "dst");
- } else if (name.find("PC") != name.npos) {
- MOV("label", "reg")
- } else {
- MOV("src", "dst");
- }
- }
-
- if (name.find("JMP") != name.npos ||
- name.find("J") == 0) {
- if (name.find("FAR") != name.npos && name.find("i") != name.npos) {
- BRANCH("off");
- } else {
- BRANCH("dst");
- }
- }
-
- if (name.find("PUSH") != name.npos) {
- if (name.find("CS") != name.npos ||
- name.find("DS") != name.npos ||
- name.find("ES") != name.npos ||
- name.find("FS") != name.npos ||
- name.find("GS") != name.npos ||
- name.find("SS") != name.npos) {
- instType.set("kInstructionTypePush");
- // TODO add support for fixed operands
- } else if (name.find("F") != name.npos) {
- // ignore (this pushes onto the FP stack)
- } else if (name.find("A") != name.npos) {
- // ignore (pushes all GP registoers onto the stack)
- } else if (name[name.length() - 1] == 'm') {
- PUSH("src");
- } else if (name.find("i") != name.npos) {
- PUSH("imm");
- } else {
- PUSH("reg");
- }
- }
-
- if (name.find("POP") != name.npos) {
- if (name.find("POPCNT") != name.npos) {
- // ignore (not a real pop)
- } else if (name.find("CS") != name.npos ||
- name.find("DS") != name.npos ||
- name.find("ES") != name.npos ||
- name.find("FS") != name.npos ||
- name.find("GS") != name.npos ||
- name.find("SS") != name.npos) {
- instType.set("kInstructionTypePop");
- // TODO add support for fixed operands
- } else if (name.find("F") != name.npos) {
- // ignore (this pops from the FP stack)
- } else if (name.find("A") != name.npos) {
- // ignore (pushes all GP registoers onto the stack)
- } else if (name[name.length() - 1] == 'm') {
- POP("dst");
- } else {
- POP("reg");
- }
- }
-
- if (name.find("CALL") != name.npos) {
- if (name.find("ADJ") != name.npos) {
- // ignore (not a call)
- } else if (name.find("SYSCALL") != name.npos) {
- // ignore (doesn't go anywhere we know about)
- } else if (name.find("VMCALL") != name.npos) {
- // ignore (rather different semantics than a regular call)
- } else if (name.find("VMMCALL") != name.npos) {
- // ignore (rather different semantics than a regular call)
- } else if (name.find("FAR") != name.npos && name.find("i") != name.npos) {
- CALL("off");
- } else {
- CALL("dst");
- }
- }
-
- if (name.find("RET") != name.npos) {
- RETURN();
- }
-}
-
-#undef MOV
-#undef BRANCH
-#undef PUSH
-#undef POP
-#undef CALL
-#undef RETURN
-
-/////////////////////////////////////////////////////
-// Support functions for handling ARM instructions //
-/////////////////////////////////////////////////////
-
-#define SET(flag) { type->set(flag); return 0; }
-
-#define REG(str) if (name == str) SET("kOperandTypeRegister");
-#define IMM(str) if (name == str) SET("kOperandTypeImmediate");
-
-#define MISC(str, type) if (name == str) SET(type);
-
-/// ARMFlagFromOpName - Processes the name of a single ARM operand (which is
-/// actually its type) and translates it into an operand type
-///
-/// \param type The type object to set
-/// \param name The name of the operand
-static int ARMFlagFromOpName(LiteralConstantEmitter *type,
- const std::string &name) {
- REG("GPR");
- REG("rGPR");
- REG("GPRnopc");
- REG("GPRsp");
- REG("tcGPR");
- REG("cc_out");
- REG("s_cc_out");
- REG("tGPR");
- REG("DPR");
- REG("DPR_VFP2");
- REG("DPR_8");
- REG("DPair");
- REG("SPR");
- REG("QPR");
- REG("QQPR");
- REG("QQQQPR");
- REG("VecListOneD");
- REG("VecListDPair");
- REG("VecListDPairSpaced");
- REG("VecListThreeD");
- REG("VecListFourD");
- REG("VecListOneDAllLanes");
- REG("VecListDPairAllLanes");
- REG("VecListDPairSpacedAllLanes");
-
- IMM("i32imm");
- IMM("fbits16");
- IMM("fbits32");
- IMM("i32imm_hilo16");
- IMM("bf_inv_mask_imm");
- IMM("lsb_pos_imm");
- IMM("width_imm");
- IMM("jtblock_operand");
- IMM("nohash_imm");
- IMM("p_imm");
- IMM("pf_imm");
- IMM("c_imm");
- IMM("coproc_option_imm");
- IMM("imod_op");
- IMM("iflags_op");
- IMM("cpinst_operand");
- IMM("setend_op");
- IMM("cps_opt");
- IMM("vfp_f64imm");
- IMM("vfp_f32imm");
- IMM("memb_opt");
- IMM("msr_mask");
- IMM("neg_zero");
- IMM("imm0_31");
- IMM("imm0_31_m1");
- IMM("imm1_16");
- IMM("imm1_32");
- IMM("nModImm");
- IMM("nImmSplatI8");
- IMM("nImmSplatI16");
- IMM("nImmSplatI32");
- IMM("nImmSplatI64");
- IMM("nImmVMOVI32");
- IMM("nImmVMOVF32");
- IMM("imm8");
- IMM("imm16");
- IMM("imm32");
- IMM("imm1_7");
- IMM("imm1_15");
- IMM("imm1_31");
- IMM("imm0_1");
- IMM("imm0_3");
- IMM("imm0_7");
- IMM("imm0_15");
- IMM("imm0_255");
- IMM("imm0_4095");
- IMM("imm0_65535");
- IMM("imm0_65535_expr");
- IMM("imm24b");
- IMM("pkh_lsl_amt");
- IMM("pkh_asr_amt");
- IMM("jt2block_operand");
- IMM("t_imm0_1020s4");
- IMM("t_imm0_508s4");
- IMM("pclabel");
- IMM("adrlabel");
- IMM("t_adrlabel");
- IMM("t2adrlabel");
- IMM("shift_imm");
- IMM("t2_shift_imm");
- IMM("neon_vcvt_imm32");
- IMM("shr_imm8");
- IMM("shr_imm16");
- IMM("shr_imm32");
- IMM("shr_imm64");
- IMM("t2ldrlabel");
- IMM("postidx_imm8");
- IMM("postidx_imm8s4");
- IMM("imm_sr");
- IMM("imm1_31");
- IMM("VectorIndex8");
- IMM("VectorIndex16");
- IMM("VectorIndex32");
-
- MISC("brtarget", "kOperandTypeARMBranchTarget"); // ?
- MISC("uncondbrtarget", "kOperandTypeARMBranchTarget"); // ?
- MISC("t_brtarget", "kOperandTypeARMBranchTarget"); // ?
- MISC("t_bcctarget", "kOperandTypeARMBranchTarget"); // ?
- MISC("t_cbtarget", "kOperandTypeARMBranchTarget"); // ?
- MISC("bltarget", "kOperandTypeARMBranchTarget"); // ?
-
- MISC("br_target", "kOperandTypeARMBranchTarget"); // ?
- MISC("bl_target", "kOperandTypeARMBranchTarget"); // ?
- MISC("blx_target", "kOperandTypeARMBranchTarget"); // ?
-
- MISC("t_bltarget", "kOperandTypeARMBranchTarget"); // ?
- MISC("t_blxtarget", "kOperandTypeARMBranchTarget"); // ?
- MISC("so_reg_imm", "kOperandTypeARMSoRegReg"); // R, R, I
- MISC("so_reg_reg", "kOperandTypeARMSoRegImm"); // R, R, I
- MISC("shift_so_reg_reg", "kOperandTypeARMSoRegReg"); // R, R, I
- MISC("shift_so_reg_imm", "kOperandTypeARMSoRegImm"); // R, R, I
- MISC("t2_so_reg", "kOperandTypeThumb2SoReg"); // R, I
- MISC("so_imm", "kOperandTypeARMSoImm"); // I
- MISC("rot_imm", "kOperandTypeARMRotImm"); // I
- MISC("t2_so_imm", "kOperandTypeThumb2SoImm"); // I
- MISC("so_imm2part", "kOperandTypeARMSoImm2Part"); // I
- MISC("pred", "kOperandTypeARMPredicate"); // I, R
- MISC("it_pred", "kOperandTypeARMPredicate"); // I
- MISC("addrmode_imm12", "kOperandTypeAddrModeImm12"); // R, I
- MISC("ldst_so_reg", "kOperandTypeLdStSOReg"); // R, R, I
- MISC("postidx_reg", "kOperandTypeARMAddrMode3Offset"); // R, I
- MISC("addrmode2", "kOperandTypeARMAddrMode2"); // R, R, I
- MISC("am2offset_reg", "kOperandTypeARMAddrMode2Offset"); // R, I
- MISC("am2offset_imm", "kOperandTypeARMAddrMode2Offset"); // R, I
- MISC("addrmode3", "kOperandTypeARMAddrMode3"); // R, R, I
- MISC("am3offset", "kOperandTypeARMAddrMode3Offset"); // R, I
- MISC("ldstm_mode", "kOperandTypeARMLdStmMode"); // I
- MISC("addrmode5", "kOperandTypeARMAddrMode5"); // R, I
- MISC("addrmode6", "kOperandTypeARMAddrMode6"); // R, R, I, I
- MISC("am6offset", "kOperandTypeARMAddrMode6Offset"); // R, I, I
- MISC("addrmode6dup", "kOperandTypeARMAddrMode6"); // R, R, I, I
- MISC("addrmode6oneL32", "kOperandTypeARMAddrMode6"); // R, R, I, I
- MISC("addrmodepc", "kOperandTypeARMAddrModePC"); // R, I
- MISC("addr_offset_none", "kOperandTypeARMAddrMode7"); // R
- MISC("reglist", "kOperandTypeARMRegisterList"); // I, R, ...
- MISC("dpr_reglist", "kOperandTypeARMDPRRegisterList"); // I, R, ...
- MISC("spr_reglist", "kOperandTypeARMSPRRegisterList"); // I, R, ...
- MISC("it_mask", "kOperandTypeThumbITMask"); // I
- MISC("t2addrmode_reg", "kOperandTypeThumb2AddrModeReg"); // R
- MISC("t2addrmode_posimm8", "kOperandTypeThumb2AddrModeImm8"); // R, I
- MISC("t2addrmode_negimm8", "kOperandTypeThumb2AddrModeImm8"); // R, I
- MISC("t2addrmode_imm8", "kOperandTypeThumb2AddrModeImm8"); // R, I
- MISC("t2am_imm8_offset", "kOperandTypeThumb2AddrModeImm8Offset");//I
- MISC("t2addrmode_imm12", "kOperandTypeThumb2AddrModeImm12"); // R, I
- MISC("t2addrmode_so_reg", "kOperandTypeThumb2AddrModeSoReg"); // R, R, I
- MISC("t2addrmode_imm8s4", "kOperandTypeThumb2AddrModeImm8s4"); // R, I
- MISC("t2addrmode_imm0_1020s4", "kOperandTypeThumb2AddrModeImm8s4"); // R, I
- MISC("t2am_imm8s4_offset", "kOperandTypeThumb2AddrModeImm8s4Offset");
- // R, I
- MISC("tb_addrmode", "kOperandTypeARMTBAddrMode"); // I
- MISC("t_addrmode_rrs1", "kOperandTypeThumbAddrModeRegS1"); // R, R
- MISC("t_addrmode_rrs2", "kOperandTypeThumbAddrModeRegS2"); // R, R
- MISC("t_addrmode_rrs4", "kOperandTypeThumbAddrModeRegS4"); // R, R
- MISC("t_addrmode_is1", "kOperandTypeThumbAddrModeImmS1"); // R, I
- MISC("t_addrmode_is2", "kOperandTypeThumbAddrModeImmS2"); // R, I
- MISC("t_addrmode_is4", "kOperandTypeThumbAddrModeImmS4"); // R, I
- MISC("t_addrmode_rr", "kOperandTypeThumbAddrModeRR"); // R, R
- MISC("t_addrmode_sp", "kOperandTypeThumbAddrModeSP"); // R, I
- MISC("t_addrmode_pc", "kOperandTypeThumbAddrModePC"); // R, I
- MISC("addrmode_tbb", "kOperandTypeThumbAddrModeRR"); // R, R
- MISC("addrmode_tbh", "kOperandTypeThumbAddrModeRR"); // R, R
-
- return 1;
-}
-
-#undef REG
-#undef MEM
-#undef MISC
-
-#undef SET
-
-/// ARMPopulateOperands - Handles all the operands in an ARM instruction, adding
-/// the appropriate flags to their descriptors
-///
-/// \param operandTypes A reference the array of operand type objects
-/// \param inst The instruction to use as a source of information
-static void ARMPopulateOperands(
- LiteralConstantEmitter *(&operandTypes)[EDIS_MAX_OPERANDS],
- const CodeGenInstruction &inst) {
- if (!inst.TheDef->isSubClassOf("InstARM") &&
- !inst.TheDef->isSubClassOf("InstThumb"))
- return;
-
- unsigned int index;
- unsigned int numOperands = inst.Operands.size();
-
- if (numOperands > EDIS_MAX_OPERANDS) {
- errs() << "numOperands == " << numOperands << " > " <<
- EDIS_MAX_OPERANDS << '\n';
- llvm_unreachable("Too many operands");
- }
-
- for (index = 0; index < numOperands; ++index) {
- const CGIOperandList::OperandInfo &operandInfo = inst.Operands[index];
- Record &rec = *operandInfo.Rec;
-
- if (ARMFlagFromOpName(operandTypes[index], rec.getName())) {
- errs() << "Operand type: " << rec.getName() << '\n';
- errs() << "Operand name: " << operandInfo.Name << '\n';
- errs() << "Instruction name: " << inst.TheDef->getName() << '\n';
- PrintFatalError("Unhandled type in EDEmitter");
- }
- }
-}
-
-#define BRANCH(target) { \
- instType.set("kInstructionTypeBranch"); \
- DECORATE1(target, "kOperandFlagTarget"); \
-}
-
-/// ARMExtractSemantics - Performs various checks on the name of an ARM
-/// instruction to determine what sort of an instruction it is and then adds
-/// the appropriate flags to the instruction and its operands
-///
-/// \param instType A reference to the type for the instruction as a whole
-/// \param operandTypes A reference to the array of operand type object pointers
-/// \param operandFlags A reference to the array of operand flag object pointers
-/// \param inst A reference to the original instruction
-static void ARMExtractSemantics(
- LiteralConstantEmitter &instType,
- LiteralConstantEmitter *(&operandTypes)[EDIS_MAX_OPERANDS],
- FlagsConstantEmitter *(&operandFlags)[EDIS_MAX_OPERANDS],
- const CodeGenInstruction &inst) {
- const std::string &name = inst.TheDef->getName();
-
- if (name == "tBcc" ||
- name == "tB" ||
- name == "t2Bcc" ||
- name == "Bcc" ||
- name == "tCBZ" ||
- name == "tCBNZ") {
- BRANCH("target");
- }
-
- if (name == "tBLr9" ||
- name == "BLr9_pred" ||
- name == "tBLXi_r9" ||
- name == "tBLXr_r9" ||
- name == "BLXr9" ||
- name == "t2BXJ" ||
- name == "BXJ") {
- BRANCH("func");
-
- unsigned opIndex;
- opIndex = inst.Operands.getOperandNamed("func");
- if (operandTypes[opIndex]->is("kOperandTypeImmediate"))
- operandTypes[opIndex]->set("kOperandTypeARMBranchTarget");
- }
-}
-
-#undef BRANCH
-
-/// populateInstInfo - Fills an array of InstInfos with information about each
-/// instruction in a target
-///
-/// \param infoArray The array of InstInfo objects to populate
-/// \param target The CodeGenTarget to use as a source of instructions
-static void populateInstInfo(CompoundConstantEmitter &infoArray,
- CodeGenTarget &target) {
- const std::vector<const CodeGenInstruction*> &numberedInstructions =
- target.getInstructionsByEnumValue();
-
- unsigned int index;
- unsigned int numInstructions = numberedInstructions.size();
-
- for (index = 0; index < numInstructions; ++index) {
- const CodeGenInstruction& inst = *numberedInstructions[index];
-
- CompoundConstantEmitter *infoStruct = new CompoundConstantEmitter;
- infoArray.addEntry(infoStruct);
-
- LiteralConstantEmitter *instType = new LiteralConstantEmitter;
- infoStruct->addEntry(instType);
-
- LiteralConstantEmitter *numOperandsEmitter =
- new LiteralConstantEmitter(inst.Operands.size());
- infoStruct->addEntry(numOperandsEmitter);
-
- CompoundConstantEmitter *operandTypeArray = new CompoundConstantEmitter;
- infoStruct->addEntry(operandTypeArray);
-
- LiteralConstantEmitter *operandTypes[EDIS_MAX_OPERANDS];
-
- CompoundConstantEmitter *operandFlagArray = new CompoundConstantEmitter;
- infoStruct->addEntry(operandFlagArray);
-
- FlagsConstantEmitter *operandFlags[EDIS_MAX_OPERANDS];
-
- for (unsigned operandIndex = 0;
- operandIndex < EDIS_MAX_OPERANDS;
- ++operandIndex) {
- operandTypes[operandIndex] = new LiteralConstantEmitter;
- operandTypeArray->addEntry(operandTypes[operandIndex]);
-
- operandFlags[operandIndex] = new FlagsConstantEmitter;
- operandFlagArray->addEntry(operandFlags[operandIndex]);
- }
-
- unsigned numSyntaxes = 0;
-
- // We don't need to do anything for pseudo-instructions, as we'll never
- // see them here. We'll only see real instructions.
- // We still need to emit null initializers for everything.
- if (!inst.isPseudo) {
- if (target.getName() == "X86") {
- X86PopulateOperands(operandTypes, inst);
- X86ExtractSemantics(*instType, operandFlags, inst);
- numSyntaxes = 2;
- }
- else if (target.getName() == "ARM") {
- ARMPopulateOperands(operandTypes, inst);
- ARMExtractSemantics(*instType, operandTypes, operandFlags, inst);
- numSyntaxes = 1;
- }
- }
-
- CompoundConstantEmitter *operandOrderArray = new CompoundConstantEmitter;
-
- infoStruct->addEntry(operandOrderArray);
-
- for (unsigned syntaxIndex = 0;
- syntaxIndex < EDIS_MAX_SYNTAXES;
- ++syntaxIndex) {
- CompoundConstantEmitter *operandOrder =
- new CompoundConstantEmitter(EDIS_MAX_OPERANDS);
-
- operandOrderArray->addEntry(operandOrder);
-
- if (syntaxIndex < numSyntaxes) {
- populateOperandOrder(operandOrder, inst, syntaxIndex);
- }
- }
-
- infoStruct = NULL;
- }
-}
-
-static void emitCommonEnums(raw_ostream &o, unsigned int &i) {
- EnumEmitter operandTypes("OperandTypes");
- operandTypes.addEntry("kOperandTypeNone");
- operandTypes.addEntry("kOperandTypeImmediate");
- operandTypes.addEntry("kOperandTypeRegister");
- operandTypes.addEntry("kOperandTypeX86Memory");
- operandTypes.addEntry("kOperandTypeX86EffectiveAddress");
- operandTypes.addEntry("kOperandTypeX86PCRelative");
- operandTypes.addEntry("kOperandTypeARMBranchTarget");
- operandTypes.addEntry("kOperandTypeARMSoRegReg");
- operandTypes.addEntry("kOperandTypeARMSoRegImm");
- operandTypes.addEntry("kOperandTypeARMSoImm");
- operandTypes.addEntry("kOperandTypeARMRotImm");
- operandTypes.addEntry("kOperandTypeARMSoImm2Part");
- operandTypes.addEntry("kOperandTypeARMPredicate");
- operandTypes.addEntry("kOperandTypeAddrModeImm12");
- operandTypes.addEntry("kOperandTypeLdStSOReg");
- operandTypes.addEntry("kOperandTypeARMAddrMode2");
- operandTypes.addEntry("kOperandTypeARMAddrMode2Offset");
- operandTypes.addEntry("kOperandTypeARMAddrMode3");
- operandTypes.addEntry("kOperandTypeARMAddrMode3Offset");
- operandTypes.addEntry("kOperandTypeARMLdStmMode");
- operandTypes.addEntry("kOperandTypeARMAddrMode5");
- operandTypes.addEntry("kOperandTypeARMAddrMode6");
- operandTypes.addEntry("kOperandTypeARMAddrMode6Offset");
- operandTypes.addEntry("kOperandTypeARMAddrMode7");
- operandTypes.addEntry("kOperandTypeARMAddrModePC");
- operandTypes.addEntry("kOperandTypeARMRegisterList");
- operandTypes.addEntry("kOperandTypeARMDPRRegisterList");
- operandTypes.addEntry("kOperandTypeARMSPRRegisterList");
- operandTypes.addEntry("kOperandTypeARMTBAddrMode");
- operandTypes.addEntry("kOperandTypeThumbITMask");
- operandTypes.addEntry("kOperandTypeThumbAddrModeImmS1");
- operandTypes.addEntry("kOperandTypeThumbAddrModeImmS2");
- operandTypes.addEntry("kOperandTypeThumbAddrModeImmS4");
- operandTypes.addEntry("kOperandTypeThumbAddrModeRegS1");
- operandTypes.addEntry("kOperandTypeThumbAddrModeRegS2");
- operandTypes.addEntry("kOperandTypeThumbAddrModeRegS4");
- operandTypes.addEntry("kOperandTypeThumbAddrModeRR");
- operandTypes.addEntry("kOperandTypeThumbAddrModeSP");
- operandTypes.addEntry("kOperandTypeThumbAddrModePC");
- operandTypes.addEntry("kOperandTypeThumb2AddrModeReg");
- operandTypes.addEntry("kOperandTypeThumb2SoReg");
- operandTypes.addEntry("kOperandTypeThumb2SoImm");
- operandTypes.addEntry("kOperandTypeThumb2AddrModeImm8");
- operandTypes.addEntry("kOperandTypeThumb2AddrModeImm8Offset");
- operandTypes.addEntry("kOperandTypeThumb2AddrModeImm12");
- operandTypes.addEntry("kOperandTypeThumb2AddrModeSoReg");
- operandTypes.addEntry("kOperandTypeThumb2AddrModeImm8s4");
- operandTypes.addEntry("kOperandTypeThumb2AddrModeImm8s4Offset");
- operandTypes.emit(o, i);
-
- o << "\n";
-
- EnumEmitter operandFlags("OperandFlags");
- operandFlags.addEntry("kOperandFlagSource");
- operandFlags.addEntry("kOperandFlagTarget");
- operandFlags.emitAsFlags(o, i);
-
- o << "\n";
-
- EnumEmitter instructionTypes("InstructionTypes");
- instructionTypes.addEntry("kInstructionTypeNone");
- instructionTypes.addEntry("kInstructionTypeMove");
- instructionTypes.addEntry("kInstructionTypeBranch");
- instructionTypes.addEntry("kInstructionTypePush");
- instructionTypes.addEntry("kInstructionTypePop");
- instructionTypes.addEntry("kInstructionTypeCall");
- instructionTypes.addEntry("kInstructionTypeReturn");
- instructionTypes.emit(o, i);
-
- o << "\n";
-}
-
-namespace llvm {
-
-void EmitEnhancedDisassemblerInfo(RecordKeeper &RK, raw_ostream &OS) {
- emitSourceFileHeader("Enhanced Disassembler Info", OS);
- unsigned int i = 0;
-
- CompoundConstantEmitter infoArray;
- CodeGenTarget target(RK);
-
- populateInstInfo(infoArray, target);
-
- emitCommonEnums(OS, i);
-
- OS << "static const llvm::EDInstInfo instInfo"
- << target.getName() << "[] = ";
- infoArray.emit(OS, i);
- OS << ";" << "\n";
-}
-
-} // End llvm namespace
diff --git a/utils/TableGen/FixedLenDecoderEmitter.cpp b/utils/TableGen/FixedLenDecoderEmitter.cpp
index 5cabcad..0c3017f 100644
--- a/utils/TableGen/FixedLenDecoderEmitter.cpp
+++ b/utils/TableGen/FixedLenDecoderEmitter.cpp
@@ -15,8 +15,6 @@
#define DEBUG_TYPE "decoder-emitter"
#include "CodeGenTarget.h"
-#include "llvm/TableGen/Error.h"
-#include "llvm/TableGen/Record.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
@@ -28,11 +26,12 @@
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/LEB128.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/TableGen/Error.h"
+#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/TableGenBackend.h"
-
-#include <vector>
#include <map>
#include <string>
+#include <vector>
using namespace llvm;
@@ -1867,7 +1866,7 @@ static void emitFieldFromInstruction(formatted_raw_ostream &OS) {
<< " if (numBits == sizeof(InsnType)*8)\n"
<< " fieldMask = (InsnType)(-1LL);\n"
<< " else\n"
- << " fieldMask = ((1 << numBits) - 1) << startBit;\n"
+ << " fieldMask = (((InsnType)1 << numBits) - 1) << startBit;\n"
<< " return (insn & fieldMask) >> startBit;\n"
<< "}\n\n";
}
diff --git a/utils/TableGen/InstrInfoEmitter.cpp b/utils/TableGen/InstrInfoEmitter.cpp
index 48d41d7..d6020a8 100644
--- a/utils/TableGen/InstrInfoEmitter.cpp
+++ b/utils/TableGen/InstrInfoEmitter.cpp
@@ -16,8 +16,8 @@
#include "CodeGenDAGPatterns.h"
#include "CodeGenSchedule.h"
#include "CodeGenTarget.h"
-#include "TableGenBackends.h"
#include "SequenceToOffsetTable.h"
+#include "TableGenBackends.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
@@ -271,7 +271,7 @@ void InstrInfoEmitter::run(raw_ostream &OS) {
std::string ClassName = TargetName + "GenInstrInfo";
OS << "namespace llvm {\n";
- OS << "struct " << ClassName << " : public TargetInstrInfoImpl {\n"
+ OS << "struct " << ClassName << " : public TargetInstrInfo {\n"
<< " explicit " << ClassName << "(int SO = -1, int DO = -1);\n"
<< "};\n";
OS << "} // End llvm namespace \n";
@@ -286,7 +286,7 @@ void InstrInfoEmitter::run(raw_ostream &OS) {
OS << "extern const unsigned " << TargetName << "InstrNameIndices[];\n";
OS << "extern const char " << TargetName << "InstrNameData[];\n";
OS << ClassName << "::" << ClassName << "(int SO, int DO)\n"
- << " : TargetInstrInfoImpl(SO, DO) {\n"
+ << " : TargetInstrInfo(SO, DO) {\n"
<< " InitMCInstrInfo(" << TargetName << "Insts, "
<< TargetName << "InstrNameIndices, " << TargetName << "InstrNameData, "
<< NumberedInstructions.size() << ");\n}\n";
diff --git a/utils/TableGen/IntrinsicEmitter.cpp b/utils/TableGen/IntrinsicEmitter.cpp
index fe55242..df4d847 100644
--- a/utils/TableGen/IntrinsicEmitter.cpp
+++ b/utils/TableGen/IntrinsicEmitter.cpp
@@ -221,27 +221,28 @@ enum IIT_Info {
IIT_I16 = 3,
IIT_I32 = 4,
IIT_I64 = 5,
- IIT_F32 = 6,
- IIT_F64 = 7,
- IIT_V2 = 8,
- IIT_V4 = 9,
- IIT_V8 = 10,
- IIT_V16 = 11,
- IIT_V32 = 12,
- IIT_MMX = 13,
+ IIT_F16 = 6,
+ IIT_F32 = 7,
+ IIT_F64 = 8,
+ IIT_V2 = 9,
+ IIT_V4 = 10,
+ IIT_V8 = 11,
+ IIT_V16 = 12,
+ IIT_V32 = 13,
IIT_PTR = 14,
IIT_ARG = 15,
-
+
// Values from 16+ are only encodable with the inefficient encoding.
- IIT_METADATA = 16,
- IIT_EMPTYSTRUCT = 17,
- IIT_STRUCT2 = 18,
- IIT_STRUCT3 = 19,
- IIT_STRUCT4 = 20,
- IIT_STRUCT5 = 21,
- IIT_EXTEND_VEC_ARG = 22,
- IIT_TRUNC_VEC_ARG = 23,
- IIT_ANYPTR = 24
+ IIT_MMX = 16,
+ IIT_METADATA = 17,
+ IIT_EMPTYSTRUCT = 18,
+ IIT_STRUCT2 = 19,
+ IIT_STRUCT3 = 20,
+ IIT_STRUCT4 = 21,
+ IIT_STRUCT5 = 22,
+ IIT_EXTEND_VEC_ARG = 23,
+ IIT_TRUNC_VEC_ARG = 24,
+ IIT_ANYPTR = 25
};
@@ -261,6 +262,7 @@ static void EncodeFixedValueType(MVT::SimpleValueType VT,
switch (VT) {
default: PrintFatalError("unhandled MVT in intrinsic!");
+ case MVT::f16: return Sig.push_back(IIT_F16);
case MVT::f32: return Sig.push_back(IIT_F32);
case MVT::f64: return Sig.push_back(IIT_F64);
case MVT::Metadata: return Sig.push_back(IIT_METADATA);
@@ -511,10 +513,10 @@ EmitAttributes(const std::vector<CodeGenIntrinsic> &Ints, raw_ostream &OS) {
OS << "// Add parameter attributes that are not common to all intrinsics.\n";
OS << "#ifdef GET_INTRINSIC_ATTRIBUTES\n";
if (TargetOnly)
- OS << "static AttrListPtr getAttributes(LLVMContext &C, " << TargetPrefix
+ OS << "static AttributeSet getAttributes(LLVMContext &C, " << TargetPrefix
<< "Intrinsic::ID id) {\n";
else
- OS << "AttrListPtr Intrinsic::getAttributes(LLVMContext &C, ID id) {\n";
+ OS << "AttributeSet Intrinsic::getAttributes(LLVMContext &C, ID id) {\n";
// Compute the maximum number of attribute arguments and the map
typedef std::map<const CodeGenIntrinsic*, unsigned,
@@ -532,9 +534,8 @@ EmitAttributes(const std::vector<CodeGenIntrinsic> &Ints, raw_ostream &OS) {
N = ++AttrNum;
}
- // Emit an array of AttributeWithIndex. Most intrinsics will have
- // at least one entry, for the function itself (index ~1), which is
- // usually nounwind.
+ // Emit an array of AttributeSet. Most intrinsics will have at least one
+ // entry, for the function itself (index ~1), which is usually nounwind.
OS << " static const uint8_t IntrinsicsToAttributesMap[] = {\n";
for (unsigned i = 0, e = Ints.size(); i != e; ++i) {
@@ -545,10 +546,10 @@ EmitAttributes(const std::vector<CodeGenIntrinsic> &Ints, raw_ostream &OS) {
}
OS << " };\n\n";
- OS << " AttributeWithIndex AWI[" << maxArgAttrs+1 << "];\n";
+ OS << " AttributeSet AS[" << maxArgAttrs+1 << "];\n";
OS << " unsigned NumAttrs = 0;\n";
OS << " if (id != 0) {\n";
- OS << " SmallVector<Attributes::AttrVal, 8> AttrVec;\n";
+ OS << " SmallVector<Attribute::AttrKind, 8> AttrVec;\n";
OS << " switch(IntrinsicsToAttributesMap[id - ";
if (TargetOnly)
OS << "Intrinsic::num_intrinsics";
@@ -576,14 +577,14 @@ EmitAttributes(const std::vector<CodeGenIntrinsic> &Ints, raw_ostream &OS) {
do {
switch (intrinsic.ArgumentAttributes[ai].second) {
case CodeGenIntrinsic::NoCapture:
- OS << " AttrVec.push_back(Attributes::NoCapture);\n";
+ OS << " AttrVec.push_back(Attribute::NoCapture);\n";
break;
}
++ai;
} while (ai != ae && intrinsic.ArgumentAttributes[ai].first == argNo);
- OS << " AWI[" << numAttrs++ << "] = AttributeWithIndex::get(C, "
+ OS << " AS[" << numAttrs++ << "] = AttributeSet::get(C, "
<< argNo+1 << ", AttrVec);\n";
}
}
@@ -594,34 +595,34 @@ EmitAttributes(const std::vector<CodeGenIntrinsic> &Ints, raw_ostream &OS) {
OS << " AttrVec.clear();\n";
if (!intrinsic.canThrow)
- OS << " AttrVec.push_back(Attributes::NoUnwind);\n";
+ OS << " AttrVec.push_back(Attribute::NoUnwind);\n";
if (intrinsic.isNoReturn)
- OS << " AttrVec.push_back(Attributes::NoReturn);\n";
+ OS << " AttrVec.push_back(Attribute::NoReturn);\n";
switch (modRef) {
case MRK_none: break;
case MRK_readonly:
- OS << " AttrVec.push_back(Attributes::ReadOnly);\n";
+ OS << " AttrVec.push_back(Attribute::ReadOnly);\n";
break;
case MRK_readnone:
- OS << " AttrVec.push_back(Attributes::ReadNone);\n";
+ OS << " AttrVec.push_back(Attribute::ReadNone);\n";
break;
}
- OS << " AWI[" << numAttrs++ << "] = AttributeWithIndex::get(C, "
- << "AttrListPtr::FunctionIndex, AttrVec);\n";
+ OS << " AS[" << numAttrs++ << "] = AttributeSet::get(C, "
+ << "AttributeSet::FunctionIndex, AttrVec);\n";
}
if (numAttrs) {
OS << " NumAttrs = " << numAttrs << ";\n";
OS << " break;\n";
} else {
- OS << " return AttrListPtr();\n";
+ OS << " return AttributeSet();\n";
}
}
OS << " }\n";
OS << " }\n";
- OS << " return AttrListPtr::get(C, ArrayRef<AttributeWithIndex>(AWI, "
+ OS << " return AttributeSet::get(C, ArrayRef<AttributeSet>(AS, "
"NumAttrs));\n";
OS << "}\n";
OS << "#endif // GET_INTRINSIC_ATTRIBUTES\n\n";
diff --git a/utils/TableGen/OptParserEmitter.cpp b/utils/TableGen/OptParserEmitter.cpp
new file mode 100644
index 0000000..0c1f623
--- /dev/null
+++ b/utils/TableGen/OptParserEmitter.cpp
@@ -0,0 +1,266 @@
+//===- OptParserEmitter.cpp - Table Driven Command Line Parsing -----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/TableGen/Error.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/TableGen/Record.h"
+#include "llvm/TableGen/TableGenBackend.h"
+#include <map>
+
+using namespace llvm;
+
+static int StrCmpOptionName(const char *A, const char *B) {
+ char a = *A, b = *B;
+ while (a == b) {
+ if (a == '\0')
+ return 0;
+
+ a = *++A;
+ b = *++B;
+ }
+
+ if (a == '\0') // A is a prefix of B.
+ return 1;
+ if (b == '\0') // B is a prefix of A.
+ return -1;
+
+ // Otherwise lexicographic.
+ 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;
+
+ // Sentinel options precede all others and are only ordered by precedence.
+ bool ASent = A->getValueAsDef("Kind")->getValueAsBit("Sentinel");
+ bool BSent = B->getValueAsDef("Kind")->getValueAsBit("Sentinel");
+ if (ASent != BSent)
+ return ASent ? -1 : 1;
+
+ // Compare options by name, unless they are sentinels.
+ if (!ASent)
+ if (int Cmp = StrCmpOptionName(A->getValueAsString("Name").c_str(),
+ B->getValueAsString("Name").c_str()))
+ return Cmp;
+
+ if (!ASent) {
+ std::vector<std::string> APrefixes = A->getValueAsListOfStrings("Prefixes");
+ std::vector<std::string> BPrefixes = B->getValueAsListOfStrings("Prefixes");
+
+ for (std::vector<std::string>::const_iterator APre = APrefixes.begin(),
+ AEPre = APrefixes.end(),
+ BPre = BPrefixes.begin(),
+ BEPre = BPrefixes.end();
+ APre != AEPre &&
+ BPre != BEPre;
+ ++APre, ++BPre) {
+ if (int Cmp = StrCmpOptionName(APre->c_str(), BPre->c_str()))
+ return Cmp;
+ }
+ }
+
+ // Then by the kind precedence;
+ int APrec = A->getValueAsDef("Kind")->getValueAsInt("Precedence");
+ int BPrec = B->getValueAsDef("Kind")->getValueAsInt("Precedence");
+ if (APrec == BPrec &&
+ A->getValueAsListOfStrings("Prefixes") ==
+ B->getValueAsListOfStrings("Prefixes")) {
+ PrintError(A->getLoc(), Twine("Option is equivilent to"));
+ PrintError(B->getLoc(), Twine("Other defined here"));
+ PrintFatalError("Equivalent Options found.");
+ }
+ return APrec < BPrec ? -1 : 1;
+}
+
+static const std::string getOptionName(const Record &R) {
+ // Use the record name unless EnumName is defined.
+ if (isa<UnsetInit>(R.getValueInit("EnumName")))
+ return R.getName();
+
+ return R.getValueAsString("EnumName");
+}
+
+static raw_ostream &write_cstring(raw_ostream &OS, llvm::StringRef Str) {
+ OS << '"';
+ OS.write_escaped(Str);
+ OS << '"';
+ return OS;
+}
+
+/// OptParserEmitter - This tablegen backend takes an input .td file
+/// describing a list of options and emits a data structure for parsing and
+/// working with those options when given an input command line.
+namespace llvm {
+void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) {
+ // Get the option groups and options.
+ const std::vector<Record*> &Groups =
+ Records.getAllDerivedDefinitions("OptionGroup");
+ std::vector<Record*> Opts = Records.getAllDerivedDefinitions("Option");
+
+ emitSourceFileHeader("Option Parsing Definitions", OS);
+
+ array_pod_sort(Opts.begin(), Opts.end(), CompareOptionRecords);
+ // Generate prefix groups.
+ typedef SmallVector<SmallString<2>, 2> PrefixKeyT;
+ typedef std::map<PrefixKeyT, std::string> PrefixesT;
+ PrefixesT Prefixes;
+ Prefixes.insert(std::make_pair(PrefixKeyT(), "prefix_0"));
+ unsigned CurPrefix = 0;
+ for (unsigned i = 0, e = Opts.size(); i != e; ++i) {
+ const Record &R = *Opts[i];
+ std::vector<std::string> prf = R.getValueAsListOfStrings("Prefixes");
+ PrefixKeyT prfkey(prf.begin(), prf.end());
+ unsigned NewPrefix = CurPrefix + 1;
+ if (Prefixes.insert(std::make_pair(prfkey, (Twine("prefix_") +
+ Twine(NewPrefix)).str())).second)
+ CurPrefix = NewPrefix;
+ }
+
+ // Dump prefixes.
+
+ OS << "/////////\n";
+ OS << "// Prefixes\n\n";
+ OS << "#ifdef PREFIX\n";
+ OS << "#define COMMA ,\n";
+ for (PrefixesT::const_iterator I = Prefixes.begin(), E = Prefixes.end();
+ I != E; ++I) {
+ OS << "PREFIX(";
+
+ // Prefix name.
+ OS << I->second;
+
+ // Prefix values.
+ OS << ", {";
+ for (PrefixKeyT::const_iterator PI = I->first.begin(),
+ PE = I->first.end(); PI != PE; ++PI) {
+ OS << "\"" << *PI << "\" COMMA ";
+ }
+ OS << "0})\n";
+ }
+ OS << "#undef COMMA\n";
+ OS << "#endif\n\n";
+
+ OS << "/////////\n";
+ OS << "// Groups\n\n";
+ OS << "#ifdef OPTION\n";
+ for (unsigned i = 0, e = Groups.size(); i != e; ++i) {
+ const Record &R = *Groups[i];
+
+ // Start a single option entry.
+ OS << "OPTION(";
+
+ // The option prefix;
+ OS << "0";
+
+ // The option string.
+ OS << ", \"" << R.getValueAsString("Name") << '"';
+
+ // The option identifier name.
+ OS << ", "<< getOptionName(R);
+
+ // The option kind.
+ OS << ", Group";
+
+ // The containing option group (if any).
+ OS << ", ";
+ if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group")))
+ OS << getOptionName(*DI->getDef());
+ else
+ OS << "INVALID";
+
+ // The other option arguments (unused for groups).
+ OS << ", INVALID, 0, 0";
+
+ // The option help text.
+ if (!isa<UnsetInit>(R.getValueInit("HelpText"))) {
+ OS << ",\n";
+ OS << " ";
+ write_cstring(OS, R.getValueAsString("HelpText"));
+ } else
+ OS << ", 0";
+
+ // The option meta-variable name (unused).
+ OS << ", 0)\n";
+ }
+ OS << "\n";
+
+ OS << "//////////\n";
+ OS << "// Options\n\n";
+ for (unsigned i = 0, e = Opts.size(); i != e; ++i) {
+ const Record &R = *Opts[i];
+
+ // Start a single option entry.
+ OS << "OPTION(";
+
+ // The option prefix;
+ std::vector<std::string> prf = R.getValueAsListOfStrings("Prefixes");
+ OS << Prefixes[PrefixKeyT(prf.begin(), prf.end())] << ", ";
+
+ // The option string.
+ write_cstring(OS, R.getValueAsString("Name"));
+
+ // The option identifier name.
+ OS << ", "<< getOptionName(R);
+
+ // The option kind.
+ OS << ", " << R.getValueAsDef("Kind")->getValueAsString("Name");
+
+ // The containing option group (if any).
+ OS << ", ";
+ if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group")))
+ OS << getOptionName(*DI->getDef());
+ else
+ OS << "INVALID";
+
+ // The option alias (if any).
+ OS << ", ";
+ if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Alias")))
+ OS << getOptionName(*DI->getDef());
+ else
+ OS << "INVALID";
+
+ // The option flags.
+ const ListInit *LI = R.getValueAsListInit("Flags");
+ if (LI->empty()) {
+ OS << ", 0";
+ } else {
+ OS << ", ";
+ for (unsigned i = 0, e = LI->size(); i != e; ++i) {
+ if (i)
+ OS << " | ";
+ OS << cast<DefInit>(LI->getElement(i))->getDef()->getName();
+ }
+ }
+
+ // The option parameter field.
+ OS << ", " << R.getValueAsInt("NumArgs");
+
+ // The option help text.
+ if (!isa<UnsetInit>(R.getValueInit("HelpText"))) {
+ OS << ",\n";
+ OS << " ";
+ write_cstring(OS, R.getValueAsString("HelpText"));
+ } else
+ OS << ", 0";
+
+ // The option meta-variable name.
+ OS << ", ";
+ if (!isa<UnsetInit>(R.getValueInit("MetaVarName")))
+ write_cstring(OS, R.getValueAsString("MetaVarName"));
+ else
+ OS << "0";
+
+ OS << ")\n";
+ }
+ OS << "#endif\n";
+}
+} // end namespace llvm
diff --git a/utils/TableGen/PseudoLoweringEmitter.cpp b/utils/TableGen/PseudoLoweringEmitter.cpp
index 64aaee7..1ea6f79 100644
--- a/utils/TableGen/PseudoLoweringEmitter.cpp
+++ b/utils/TableGen/PseudoLoweringEmitter.cpp
@@ -252,6 +252,7 @@ void PseudoLoweringEmitter::emitLoweringEmitter(raw_ostream &o) {
MIOpNo += Dest.Operands[OpNo].MINumOperands;
}
if (Dest.Operands.isVariadic) {
+ MIOpNo = Source.Operands.size() + 1;
o << " // variable_ops\n";
o << " for (unsigned i = " << MIOpNo
<< ", e = MI->getNumOperands(); i != e; ++i)\n"
diff --git a/utils/TableGen/RegisterInfoEmitter.cpp b/utils/TableGen/RegisterInfoEmitter.cpp
index 95b6267..1b5d90b 100644
--- a/utils/TableGen/RegisterInfoEmitter.cpp
+++ b/utils/TableGen/RegisterInfoEmitter.cpp
@@ -185,6 +185,36 @@ EmitRegUnitPressure(raw_ostream &OS, const CodeGenRegBank &RegBank,
<< " return RCWeightTable[RC->getID()];\n"
<< "}\n\n";
+ // Reasonable targets (not ARMv7) have unit weight for all units, so don't
+ // bother generating a table.
+ bool RegUnitsHaveUnitWeight = true;
+ for (unsigned UnitIdx = 0, UnitEnd = RegBank.getNumNativeRegUnits();
+ UnitIdx < UnitEnd; ++UnitIdx) {
+ if (RegBank.getRegUnit(UnitIdx).Weight > 1)
+ RegUnitsHaveUnitWeight = false;
+ }
+ OS << "/// Get the weight in units of pressure for this register unit.\n"
+ << "unsigned " << ClassName << "::\n"
+ << "getRegUnitWeight(unsigned RegUnit) const {\n"
+ << " assert(RegUnit < " << RegBank.getNumNativeRegUnits()
+ << " && \"invalid register unit\");\n";
+ if (!RegUnitsHaveUnitWeight) {
+ OS << " static const uint8_t RUWeightTable[] = {\n ";
+ for (unsigned UnitIdx = 0, UnitEnd = RegBank.getNumNativeRegUnits();
+ UnitIdx < UnitEnd; ++UnitIdx) {
+ const RegUnit &RU = RegBank.getRegUnit(UnitIdx);
+ assert(RU.Weight < 256 && "RegUnit too heavy");
+ OS << RU.Weight << ", ";
+ }
+ OS << "0 };\n"
+ << " return RUWeightTable[RegUnit];\n";
+ }
+ else {
+ OS << " // All register units have unit weight.\n"
+ << " return 1;\n";
+ }
+ OS << "}\n\n";
+
OS << "\n"
<< "// Get the number of dimensions of register pressure.\n"
<< "unsigned " << ClassName << "::getNumRegPressureSets() const {\n"
@@ -215,14 +245,13 @@ EmitRegUnitPressure(raw_ostream &OS, const CodeGenRegBank &RegBank,
<< " return PressureLimitTable[Idx];\n"
<< "}\n\n";
- OS << "/// Get the dimensions of register pressure "
- << "impacted by this register class.\n"
- << "/// Returns a -1 terminated array of pressure set IDs\n"
- << "const int* " << ClassName << "::\n"
- << "getRegClassPressureSets(const TargetRegisterClass *RC) const {\n"
- << " static const int RCSetsTable[] = {\n ";
- std::vector<unsigned> RCSetStarts(NumRCs);
- for (unsigned i = 0, StartIdx = 0, e = NumRCs; i != e; ++i) {
+ // This table may be larger than NumRCs if some register units needed a list
+ // of unit sets that did not correspond to a register class.
+ unsigned NumRCUnitSets = RegBank.getNumRegClassPressureSetLists();
+ OS << "/// Table of pressure sets per register class or unit.\n"
+ << "static const int RCSetsTable[] = {\n ";
+ std::vector<unsigned> RCSetStarts(NumRCUnitSets);
+ for (unsigned i = 0, StartIdx = 0, e = NumRCUnitSets; i != e; ++i) {
RCSetStarts[i] = StartIdx;
ArrayRef<unsigned> PSetIDs = RegBank.getRCPressureSetIDs(i);
for (ArrayRef<unsigned>::iterator PSetI = PSetIDs.begin(),
@@ -230,10 +259,26 @@ EmitRegUnitPressure(raw_ostream &OS, const CodeGenRegBank &RegBank,
OS << *PSetI << ", ";
++StartIdx;
}
- OS << "-1, \t// " << RegBank.getRegClasses()[i]->getName() << "\n ";
+ OS << "-1, \t// #" << RCSetStarts[i] << " ";
+ if (i < NumRCs)
+ OS << RegBank.getRegClasses()[i]->getName();
+ else {
+ OS << "inferred";
+ for (ArrayRef<unsigned>::iterator PSetI = PSetIDs.begin(),
+ PSetE = PSetIDs.end(); PSetI != PSetE; ++PSetI) {
+ OS << "~" << RegBank.getRegPressureSet(*PSetI).Name;
+ }
+ }
+ OS << "\n ";
++StartIdx;
}
- OS << "-1 };\n";
+ OS << "-1 };\n\n";
+
+ OS << "/// Get the dimensions of register pressure impacted by this "
+ << "register class.\n"
+ << "/// Returns a -1 terminated array of pressure set IDs\n"
+ << "const int* " << ClassName << "::\n"
+ << "getRegClassPressureSets(const TargetRegisterClass *RC) const {\n";
OS << " static const unsigned RCSetStartTable[] = {\n ";
for (unsigned i = 0, e = NumRCs; i != e; ++i) {
OS << RCSetStarts[i] << ",";
@@ -242,6 +287,23 @@ EmitRegUnitPressure(raw_ostream &OS, const CodeGenRegBank &RegBank,
<< " unsigned SetListStart = RCSetStartTable[RC->getID()];\n"
<< " return &RCSetsTable[SetListStart];\n"
<< "}\n\n";
+
+ OS << "/// Get the dimensions of register pressure impacted by this "
+ << "register unit.\n"
+ << "/// Returns a -1 terminated array of pressure set IDs\n"
+ << "const int* " << ClassName << "::\n"
+ << "getRegUnitPressureSets(unsigned RegUnit) const {\n"
+ << " assert(RegUnit < " << RegBank.getNumNativeRegUnits()
+ << " && \"invalid register unit\");\n";
+ OS << " static const unsigned RUSetStartTable[] = {\n ";
+ for (unsigned UnitIdx = 0, UnitEnd = RegBank.getNumNativeRegUnits();
+ UnitIdx < UnitEnd; ++UnitIdx) {
+ OS << RCSetStarts[RegBank.getRegUnit(UnitIdx).RegClassUnitSetsIdx] << ",";
+ }
+ OS << "0 };\n"
+ << " unsigned SetListStart = RUSetStartTable[RegUnit];\n"
+ << " return &RCSetsTable[SetListStart];\n"
+ << "}\n\n";
}
void
@@ -729,7 +791,7 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target,
const std::string &TargetName = Target.getName();
// Emit the shared table of differential lists.
- OS << "extern const uint16_t " << TargetName << "RegDiffLists[] = {\n";
+ OS << "extern const MCPhysReg " << TargetName << "RegDiffLists[] = {\n";
DiffSeqs.emit(OS, printDiff16);
OS << "};\n\n";
@@ -859,9 +921,9 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target,
// MCRegisterInfo initialization routine.
OS << "static inline void Init" << TargetName
<< "MCRegisterInfo(MCRegisterInfo *RI, unsigned RA, "
- << "unsigned DwarfFlavour = 0, unsigned EHFlavour = 0) {\n"
+ << "unsigned DwarfFlavour = 0, unsigned EHFlavour = 0, unsigned PC = 0) {\n"
<< " RI->InitMCRegisterInfo(" << TargetName << "RegDesc, "
- << Regs.size()+1 << ", RA, " << TargetName << "MCRegisterClasses, "
+ << Regs.size()+1 << ", RA, PC, " << TargetName << "MCRegisterClasses, "
<< RegisterClasses.size() << ", "
<< TargetName << "RegUnitRoots, "
<< RegBank.getNumNativeRegUnits() << ", "
@@ -896,7 +958,7 @@ RegisterInfoEmitter::runTargetHeader(raw_ostream &OS, CodeGenTarget &Target,
OS << "struct " << ClassName << " : public TargetRegisterInfo {\n"
<< " explicit " << ClassName
- << "(unsigned RA, unsigned D = 0, unsigned E = 0);\n"
+ << "(unsigned RA, unsigned D = 0, unsigned E = 0, unsigned PC = 0);\n"
<< " virtual bool needsStackRealignment(const MachineFunction &) const\n"
<< " { return false; }\n";
if (!RegBank.getSubRegIndices().empty()) {
@@ -907,11 +969,13 @@ RegisterInfoEmitter::runTargetHeader(raw_ostream &OS, CodeGenTarget &Target,
}
OS << " virtual const RegClassWeight &getRegClassWeight("
<< "const TargetRegisterClass *RC) const;\n"
+ << " virtual unsigned getRegUnitWeight(unsigned RegUnit) const;\n"
<< " virtual unsigned getNumRegPressureSets() const;\n"
<< " virtual const char *getRegPressureSetName(unsigned Idx) const;\n"
<< " virtual unsigned getRegPressureSetLimit(unsigned Idx) const;\n"
<< " virtual const int *getRegClassPressureSets("
<< "const TargetRegisterClass *RC) const;\n"
+ << " virtual const int *getRegUnitPressureSets(unsigned RegUnit) const;\n"
<< "};\n\n";
ArrayRef<CodeGenRegisterClass*> RegisterClasses = RegBank.getRegClasses();
@@ -967,7 +1031,7 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
}
// Build a shared array of value types.
- SequenceToOffsetTable<std::vector<MVT::SimpleValueType> > VTSeqs;
+ SequenceToOffsetTable<SmallVector<MVT::SimpleValueType, 4> > VTSeqs;
for (unsigned rc = 0, e = RegisterClasses.size(); rc != e; ++rc)
VTSeqs.add(RegisterClasses[rc]->VTs);
VTSeqs.layout();
@@ -1074,12 +1138,12 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
OS << "\nstatic inline unsigned " << RC.getName()
<< "AltOrderSelect(const MachineFunction &MF) {"
<< RC.AltOrderSelect << "}\n\n"
- << "static ArrayRef<uint16_t> " << RC.getName()
+ << "static ArrayRef<MCPhysReg> " << RC.getName()
<< "GetRawAllocationOrder(const MachineFunction &MF) {\n";
for (unsigned oi = 1 , oe = RC.getNumOrders(); oi != oe; ++oi) {
ArrayRef<Record*> Elems = RC.getOrder(oi);
if (!Elems.empty()) {
- OS << " static const uint16_t AltOrder" << oi << "[] = {";
+ OS << " static const MCPhysReg AltOrder" << oi << "[] = {";
for (unsigned elem = 0; elem != Elems.size(); ++elem)
OS << (elem ? ", " : " ") << getQualifiedName(Elems[elem]);
OS << " };\n";
@@ -1087,11 +1151,11 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
}
OS << " const MCRegisterClass &MCR = " << Target.getName()
<< "MCRegisterClasses[" << RC.getQualifiedName() + "RegClassID];\n"
- << " const ArrayRef<uint16_t> Order[] = {\n"
+ << " const ArrayRef<MCPhysReg> Order[] = {\n"
<< " makeArrayRef(MCR.begin(), MCR.getNumRegs()";
for (unsigned oi = 1, oe = RC.getNumOrders(); oi != oe; ++oi)
if (RC.getOrder(oi).empty())
- OS << "),\n ArrayRef<uint16_t>(";
+ OS << "),\n ArrayRef<MCPhysReg>(";
else
OS << "),\n makeArrayRef(AltOrder" << oi;
OS << ")\n };\n const unsigned Select = " << RC.getName()
@@ -1194,7 +1258,7 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
// Emit the constructor of the class...
OS << "extern const MCRegisterDesc " << TargetName << "RegDesc[];\n";
- OS << "extern const uint16_t " << TargetName << "RegDiffLists[];\n";
+ OS << "extern const MCPhysReg " << TargetName << "RegDiffLists[];\n";
OS << "extern const char " << TargetName << "RegStrings[];\n";
OS << "extern const uint16_t " << TargetName << "RegUnitRoots[][2];\n";
OS << "extern const uint16_t " << TargetName << "SubRegIdxLists[];\n";
@@ -1203,12 +1267,12 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
EmitRegMappingTables(OS, Regs, true);
OS << ClassName << "::\n" << ClassName
- << "(unsigned RA, unsigned DwarfFlavour, unsigned EHFlavour)\n"
+ << "(unsigned RA, unsigned DwarfFlavour, unsigned EHFlavour, unsigned PC)\n"
<< " : TargetRegisterInfo(" << TargetName << "RegInfoDesc"
<< ", RegisterClasses, RegisterClasses+" << RegisterClasses.size() <<",\n"
<< " SubRegIndexNameTable, SubRegIndexLaneMaskTable) {\n"
<< " InitMCRegisterInfo(" << TargetName << "RegDesc, "
- << Regs.size()+1 << ", RA,\n " << TargetName
+ << Regs.size()+1 << ", RA, PC,\n " << TargetName
<< "MCRegisterClasses, " << RegisterClasses.size() << ",\n"
<< " " << TargetName << "RegUnitRoots,\n"
<< " " << RegBank.getNumNativeRegUnits() << ",\n"
@@ -1232,7 +1296,7 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
assert(Regs && "Cannot expand CalleeSavedRegs instance");
// Emit the *_SaveList list of callee-saved registers.
- OS << "static const uint16_t " << CSRSet->getName()
+ OS << "static const MCPhysReg " << CSRSet->getName()
<< "_SaveList[] = { ";
for (unsigned r = 0, re = Regs->size(); r != re; ++r)
OS << getQualifiedName((*Regs)[r]) << ", ";
diff --git a/utils/TableGen/SequenceToOffsetTable.h b/utils/TableGen/SequenceToOffsetTable.h
index d4db152..fcda233 100644
--- a/utils/TableGen/SequenceToOffsetTable.h
+++ b/utils/TableGen/SequenceToOffsetTable.h
@@ -17,11 +17,11 @@
#define TBLGEN_SEQUENCE_TO_OFFSET_TABLE_H
#include "llvm/Support/raw_ostream.h"
-#include <functional>
#include <algorithm>
-#include <vector>
#include <cassert>
#include <cctype>
+#include <functional>
+#include <vector>
namespace llvm {
diff --git a/utils/TableGen/SetTheory.cpp b/utils/TableGen/SetTheory.cpp
index 0dd9853..3e5c38c 100644
--- a/utils/TableGen/SetTheory.cpp
+++ b/utils/TableGen/SetTheory.cpp
@@ -13,9 +13,9 @@
//===----------------------------------------------------------------------===//
#include "SetTheory.h"
+#include "llvm/Support/Format.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
-#include "llvm/Support/Format.h"
using namespace llvm;
diff --git a/utils/TableGen/SetTheory.h b/utils/TableGen/SetTheory.h
index 122372a..5baed79 100644
--- a/utils/TableGen/SetTheory.h
+++ b/utils/TableGen/SetTheory.h
@@ -47,8 +47,8 @@
#ifndef SETTHEORY_H
#define SETTHEORY_H
-#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/SetVector.h"
+#include "llvm/ADT/StringMap.h"
#include "llvm/Support/SourceMgr.h"
#include <map>
#include <vector>
diff --git a/utils/TableGen/StringToOffsetTable.h b/utils/TableGen/StringToOffsetTable.h
index a098d7d..d94d3a2 100644
--- a/utils/TableGen/StringToOffsetTable.h
+++ b/utils/TableGen/StringToOffsetTable.h
@@ -11,8 +11,8 @@
#define TBLGEN_STRING_TO_OFFSET_TABLE_H
#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringMap.h"
#include "llvm/Support/raw_ostream.h"
#include <cctype>
diff --git a/utils/TableGen/SubtargetEmitter.cpp b/utils/TableGen/SubtargetEmitter.cpp
index f1a06bb..98892e1 100644
--- a/utils/TableGen/SubtargetEmitter.cpp
+++ b/utils/TableGen/SubtargetEmitter.cpp
@@ -15,14 +15,14 @@
#include "CodeGenTarget.h"
#include "CodeGenSchedule.h"
-#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/MC/MCInstrItineraries.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Format.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/TableGenBackend.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/Format.h"
#include <algorithm>
#include <map>
#include <string>
@@ -87,6 +87,8 @@ class SubtargetEmitter {
const CodeGenProcModel &ProcModel);
Record *FindReadAdvance(const CodeGenSchedRW &SchedRead,
const CodeGenProcModel &ProcModel);
+ void ExpandProcResources(RecVec &PRVec, std::vector<int64_t> &Cycles,
+ const CodeGenProcModel &ProcModel);
void GenSchedClassTables(const CodeGenProcModel &ProcModel,
SchedClassTables &SchedTables);
void EmitSchedClassTables(SchedClassTables &SchedTables, raw_ostream &OS);
@@ -445,17 +447,15 @@ EmitStageAndOperandCycleData(raw_ostream &OS,
// If this processor defines no itineraries, then leave the itinerary list
// empty.
std::vector<InstrItinerary> &ItinList = ProcItinLists.back();
- if (ProcModel.ItinDefList.empty())
+ if (!ProcModel.hasItineraries())
continue;
- // Reserve index==0 for NoItinerary.
- ItinList.resize(SchedModels.numItineraryClasses()+1);
-
const std::string &Name = ProcModel.ItinsDef->getName();
- // For each itinerary data
- for (unsigned SchedClassIdx = 0,
- SchedClassEnd = ProcModel.ItinDefList.size();
+ ItinList.resize(SchedModels.numInstrSchedClasses());
+ assert(ProcModel.ItinDefList.size() == ItinList.size() && "bad Itins");
+
+ for (unsigned SchedClassIdx = 0, SchedClassEnd = ItinList.size();
SchedClassIdx < SchedClassEnd; ++SchedClassIdx) {
// Next itinerary data
@@ -631,13 +631,31 @@ void SubtargetEmitter::EmitProcessorResources(const CodeGenProcModel &ProcModel,
for (unsigned i = 0, e = ProcModel.ProcResourceDefs.size(); i < e; ++i) {
Record *PRDef = ProcModel.ProcResourceDefs[i];
- // Find the SuperIdx
- unsigned SuperIdx = 0;
Record *SuperDef = 0;
- if (PRDef->getValueInit("Super")->isComplete()) {
- SuperDef =
- SchedModels.findProcResUnits(PRDef->getValueAsDef("Super"), ProcModel);
- SuperIdx = ProcModel.getProcResourceIdx(SuperDef);
+ unsigned SuperIdx = 0;
+ unsigned NumUnits = 0;
+ bool IsBuffered = true;
+ if (PRDef->isSubClassOf("ProcResGroup")) {
+ RecVec ResUnits = PRDef->getValueAsListOfDefs("Resources");
+ for (RecIter RUI = ResUnits.begin(), RUE = ResUnits.end();
+ RUI != RUE; ++RUI) {
+ if (!NumUnits)
+ IsBuffered = (*RUI)->getValueAsBit("Buffered");
+ else if(IsBuffered != (*RUI)->getValueAsBit("Buffered"))
+ PrintFatalError(PRDef->getLoc(),
+ "Mixing buffered and unbuffered resources.");
+ NumUnits += (*RUI)->getValueAsInt("NumUnits");
+ }
+ }
+ else {
+ // Find the SuperIdx
+ if (PRDef->getValueInit("Super")->isComplete()) {
+ SuperDef = SchedModels.findProcResUnits(
+ PRDef->getValueAsDef("Super"), ProcModel);
+ SuperIdx = ProcModel.getProcResourceIdx(SuperDef);
+ }
+ NumUnits = PRDef->getValueAsInt("NumUnits");
+ IsBuffered = PRDef->getValueAsBit("Buffered");
}
// Emit the ProcResourceDesc
if (i+1 == e)
@@ -645,8 +663,8 @@ void SubtargetEmitter::EmitProcessorResources(const CodeGenProcModel &ProcModel,
OS << " {DBGFIELD(\"" << PRDef->getName() << "\") ";
if (PRDef->getName().size() < 15)
OS.indent(15 - PRDef->getName().size());
- OS << PRDef->getValueAsInt("NumUnits") << ", " << SuperIdx << ", "
- << PRDef->getValueAsBit("Buffered") << "}" << Sep << " // #" << i+1;
+ OS << NumUnits << ", " << SuperIdx << ", "
+ << IsBuffered << "}" << Sep << " // #" << i+1;
if (SuperDef)
OS << ", Super=" << SuperDef->getName();
OS << "\n";
@@ -763,6 +781,51 @@ Record *SubtargetEmitter::FindReadAdvance(const CodeGenSchedRW &SchedRead,
return ResDef;
}
+// Expand an explicit list of processor resources into a full list of implied
+// resource groups that cover them.
+//
+// FIXME: Effectively consider a super-resource a group that include all of its
+// subresources to allow mixing and matching super-resources and groups.
+//
+// FIXME: Warn if two overlapping groups don't have a common supergroup.
+void SubtargetEmitter::ExpandProcResources(RecVec &PRVec,
+ std::vector<int64_t> &Cycles,
+ const CodeGenProcModel &ProcModel) {
+ // Default to 1 resource cycle.
+ Cycles.resize(PRVec.size(), 1);
+ for (unsigned i = 0, e = PRVec.size(); i != e; ++i) {
+ RecVec SubResources;
+ if (PRVec[i]->isSubClassOf("ProcResGroup")) {
+ SubResources = PRVec[i]->getValueAsListOfDefs("Resources");
+ std::sort(SubResources.begin(), SubResources.end(), LessRecord());
+ }
+ else {
+ SubResources.push_back(PRVec[i]);
+ }
+ for (RecIter PRI = ProcModel.ProcResourceDefs.begin(),
+ PRE = ProcModel.ProcResourceDefs.end();
+ PRI != PRE; ++PRI) {
+ if (*PRI == PRVec[i] || !(*PRI)->isSubClassOf("ProcResGroup"))
+ continue;
+ RecVec SuperResources = (*PRI)->getValueAsListOfDefs("Resources");
+ std::sort(SuperResources.begin(), SuperResources.end(), LessRecord());
+ RecIter SubI = SubResources.begin(), SubE = SubResources.end();
+ RecIter SuperI = SuperResources.begin(), SuperE = SuperResources.end();
+ for ( ; SubI != SubE && SuperI != SuperE; ++SuperI) {
+ if (*SubI < *SuperI)
+ break;
+ else if (*SuperI < *SubI)
+ continue;
+ ++SubI;
+ }
+ if (SubI == SubE) {
+ PRVec.push_back(*PRI);
+ Cycles.push_back(Cycles[i]);
+ }
+ }
+ }
+}
+
// Generate the SchedClass table for this processor and update global
// tables. Must be called for each processor in order.
void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,
@@ -787,7 +850,22 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,
SCDesc.ReadAdvanceIdx = 0;
// A Variant SchedClass has no resources of its own.
- if (!SCI->Transitions.empty()) {
+ bool HasVariants = false;
+ for (std::vector<CodeGenSchedTransition>::const_iterator
+ TI = SCI->Transitions.begin(), TE = SCI->Transitions.end();
+ TI != TE; ++TI) {
+ if (TI->ProcIndices[0] == 0) {
+ HasVariants = true;
+ break;
+ }
+ IdxIter PIPos = std::find(TI->ProcIndices.begin(),
+ TI->ProcIndices.end(), ProcModel.Index);
+ if (PIPos != TI->ProcIndices.end()) {
+ HasVariants = true;
+ break;
+ }
+ }
+ if (HasVariants) {
SCDesc.NumMicroOps = MCSchedClassDesc::VariantNumMicroOps;
continue;
}
@@ -804,27 +882,8 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,
}
IdxVec Writes = SCI->Writes;
IdxVec Reads = SCI->Reads;
- if (SCI->ItinClassDef) {
- assert(SCI->InstRWs.empty() && "ItinClass should not have InstRWs");
- // Check this processor's itinerary class resources.
- for (RecIter II = ProcModel.ItinRWDefs.begin(),
- IE = ProcModel.ItinRWDefs.end(); II != IE; ++II) {
- RecVec Matched = (*II)->getValueAsListOfDefs("MatchedItinClasses");
- if (std::find(Matched.begin(), Matched.end(), SCI->ItinClassDef)
- != Matched.end()) {
- SchedModels.findRWs((*II)->getValueAsListOfDefs("OperandReadWrites"),
- Writes, Reads);
- break;
- }
- }
- if (Writes.empty()) {
- DEBUG(dbgs() << ProcModel.ItinsDef->getName()
- << " does not have resources for itinerary class "
- << SCI->ItinClassDef->getName() << '\n');
- }
- }
- else if (!SCI->InstRWs.empty()) {
- // This class may have a default ReadWrite list which can be overriden by
+ if (!SCI->InstRWs.empty()) {
+ // This class has a default ReadWrite list which can be overriden by
// InstRW definitions.
Record *RWDef = 0;
for (RecIter RWI = SCI->InstRWs.begin(), RWE = SCI->InstRWs.end();
@@ -842,6 +901,23 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,
Writes, Reads);
}
}
+ if (Writes.empty()) {
+ // Check this processor's itinerary class resources.
+ for (RecIter II = ProcModel.ItinRWDefs.begin(),
+ IE = ProcModel.ItinRWDefs.end(); II != IE; ++II) {
+ RecVec Matched = (*II)->getValueAsListOfDefs("MatchedItinClasses");
+ if (std::find(Matched.begin(), Matched.end(), SCI->ItinClassDef)
+ != Matched.end()) {
+ SchedModels.findRWs((*II)->getValueAsListOfDefs("OperandReadWrites"),
+ Writes, Reads);
+ break;
+ }
+ }
+ if (Writes.empty()) {
+ DEBUG(dbgs() << ProcModel.ModelName
+ << " does not have resources for class " << SCI->Name << '\n');
+ }
+ }
// Sum resources across all operand writes.
std::vector<MCWriteProcResEntry> WriteProcResources;
std::vector<MCWriteLatencyEntry> WriteLatencies;
@@ -859,7 +935,8 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,
WriterNames.push_back(SchedModels.getSchedWrite(WriteID).Name);
// If this Write is not referenced by a ReadAdvance, don't distinguish it
// from other WriteLatency entries.
- if (!SchedModels.hasReadOfWrite(SchedModels.getSchedWrite(WriteID).TheDef)) {
+ if (!SchedModels.hasReadOfWrite(
+ SchedModels.getSchedWrite(WriteID).TheDef)) {
WriteID = 0;
}
WLEntry.WriteResourceID = WriteID;
@@ -884,16 +961,29 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,
RecVec PRVec = WriteRes->getValueAsListOfDefs("ProcResources");
std::vector<int64_t> Cycles =
WriteRes->getValueAsListOfInts("ResourceCycles");
+
+ ExpandProcResources(PRVec, Cycles, ProcModel);
+
for (unsigned PRIdx = 0, PREnd = PRVec.size();
PRIdx != PREnd; ++PRIdx) {
MCWriteProcResEntry WPREntry;
WPREntry.ProcResourceIdx = ProcModel.getProcResourceIdx(PRVec[PRIdx]);
assert(WPREntry.ProcResourceIdx && "Bad ProcResourceIdx");
- if (Cycles.size() > PRIdx)
- WPREntry.Cycles = Cycles[PRIdx];
- else
- WPREntry.Cycles = 1;
- WriteProcResources.push_back(WPREntry);
+ WPREntry.Cycles = Cycles[PRIdx];
+ // If this resource is already used in this sequence, add the current
+ // entry's cycles so that the same resource appears to be used
+ // serially, rather than multiple parallel uses. This is important for
+ // in-order machine where the resource consumption is a hazard.
+ unsigned WPRIdx = 0, WPREnd = WriteProcResources.size();
+ for( ; WPRIdx != WPREnd; ++WPRIdx) {
+ if (WriteProcResources[WPRIdx].ProcResourceIdx
+ == WPREntry.ProcResourceIdx) {
+ WriteProcResources[WPRIdx].Cycles += WPREntry.Cycles;
+ break;
+ }
+ }
+ if (WPRIdx == WPREnd)
+ WriteProcResources.push_back(WPREntry);
}
}
WriteLatencies.push_back(WLEntry);
@@ -1062,7 +1152,7 @@ void SubtargetEmitter::EmitSchedClassTables(SchedClassTables &SchedTables,
// The first class is always invalid. We no way to distinguish it except by
// name and position.
- assert(SchedModels.getSchedClass(0).Name == "NoItinerary"
+ assert(SchedModels.getSchedClass(0).Name == "NoInstrModel"
&& "invalid class not first");
OS << " {DBGFIELD(\"InvalidSchedClass\") "
<< MCSchedClassDesc::InvalidNumMicroOps
@@ -1108,6 +1198,7 @@ void SubtargetEmitter::EmitProcessorModels(raw_ostream &OS) {
EmitProcessorProp(OS, PI->ModelDef, "MinLatency", ',');
EmitProcessorProp(OS, PI->ModelDef, "LoadLatency", ',');
EmitProcessorProp(OS, PI->ModelDef, "HighLatency", ',');
+ EmitProcessorProp(OS, PI->ModelDef, "ILPWindow", ',');
EmitProcessorProp(OS, PI->ModelDef, "MispredictPenalty", ',');
OS << " " << PI->Index << ", // Processor ID\n";
if (PI->hasInstrSchedModel())
@@ -1118,7 +1209,7 @@ void SubtargetEmitter::EmitProcessorModels(raw_ostream &OS) {
- SchedModels.schedClassBegin()) << ",\n";
else
OS << " 0, 0, 0, 0, // No instruction-level machine model.\n";
- if (SchedModels.hasItineraryClasses())
+ if (SchedModels.hasItineraries())
OS << " " << PI->ItinsDef->getName() << ");\n";
else
OS << " 0); // No Itinerary\n";
@@ -1175,7 +1266,7 @@ void SubtargetEmitter::EmitSchedModel(raw_ostream &OS) {
<< "#define DBGFIELD(x)\n"
<< "#endif\n";
- if (SchedModels.hasItineraryClasses()) {
+ if (SchedModels.hasItineraries()) {
std::vector<std::vector<InstrItinerary> > ProcItinLists;
// Emit the stage data
EmitStageAndOperandCycleData(OS, ProcItinLists);
@@ -1216,7 +1307,7 @@ void SubtargetEmitter::EmitSchedModelHelpers(std::string ClassName,
SCE = SchedModels.schedClassEnd(); SCI != SCE; ++SCI) {
if (SCI->Transitions.empty())
continue;
- VariantClasses.push_back(SCI - SchedModels.schedClassBegin());
+ VariantClasses.push_back(SCI->Index);
}
if (!VariantClasses.empty()) {
OS << " switch (SchedClass) {\n";
@@ -1263,13 +1354,8 @@ void SubtargetEmitter::EmitSchedModelHelpers(std::string ClassName,
if (*PI == 0)
break;
}
- unsigned SCIdx = 0;
- if (SC.ItinClassDef)
- SCIdx = SchedModels.getSchedClassIdxForItin(SC.ItinClassDef);
- else
- SCIdx = SchedModels.findSchedClassIdx(SC.Writes, SC.Reads);
- if (SCIdx != *VCI)
- OS << " return " << SCIdx << ";\n";
+ if (SC.isInferred())
+ OS << " return " << SC.Index << ";\n";
OS << " break;\n";
}
OS << " };\n";
@@ -1375,7 +1461,7 @@ void SubtargetEmitter::run(raw_ostream &OS) {
<< Target << "WriteProcResTable, "
<< Target << "WriteLatencyTable, "
<< Target << "ReadAdvanceTable, ";
- if (SchedModels.hasItineraryClasses()) {
+ if (SchedModels.hasItineraries()) {
OS << '\n'; OS.indent(22);
OS << Target << "Stages, "
<< Target << "OperandCycles, "
@@ -1432,7 +1518,7 @@ void SubtargetEmitter::run(raw_ostream &OS) {
OS << "extern const llvm::MCReadAdvanceEntry "
<< Target << "ReadAdvanceTable[];\n";
- if (SchedModels.hasItineraryClasses()) {
+ if (SchedModels.hasItineraries()) {
OS << "extern const llvm::InstrStage " << Target << "Stages[];\n";
OS << "extern const unsigned " << Target << "OperandCycles[];\n";
OS << "extern const unsigned " << Target << "ForwardingPaths[];\n";
@@ -1456,7 +1542,7 @@ void SubtargetEmitter::run(raw_ostream &OS) {
<< Target << "WriteLatencyTable, "
<< Target << "ReadAdvanceTable, ";
OS << '\n'; OS.indent(22);
- if (SchedModels.hasItineraryClasses()) {
+ if (SchedModels.hasItineraries()) {
OS << Target << "Stages, "
<< Target << "OperandCycles, "
<< Target << "ForwardingPaths, ";
diff --git a/utils/TableGen/TableGen.cpp b/utils/TableGen/TableGen.cpp
index 49efe7e..b5c3ca7 100644
--- a/utils/TableGen/TableGen.cpp
+++ b/utils/TableGen/TableGen.cpp
@@ -12,7 +12,6 @@
//===----------------------------------------------------------------------===//
#include "TableGenBackends.h" // Declares all backends.
-
#include "SetTheory.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/PrettyStackTrace.h"
@@ -39,9 +38,10 @@ enum ActionType {
GenSubtarget,
GenIntrinsic,
GenTgtIntrinsic,
- GenEDInfo,
PrintEnums,
- PrintSets
+ PrintSets,
+ GenOptParserDefs,
+ GenCTags
};
namespace {
@@ -77,12 +77,14 @@ namespace {
"Generate intrinsic information"),
clEnumValN(GenTgtIntrinsic, "gen-tgt-intrinsic",
"Generate target intrinsic information"),
- clEnumValN(GenEDInfo, "gen-enhanced-disassembly-info",
- "Generate enhanced disassembly info"),
clEnumValN(PrintEnums, "print-enums",
"Print enum values for a class"),
clEnumValN(PrintSets, "print-sets",
"Print expanded sets for testing DAG exprs"),
+ clEnumValN(GenOptParserDefs, "gen-opt-parser-defs",
+ "Generate option definitions"),
+ clEnumValN(GenCTags, "gen-ctags",
+ "Generate ctags-compatible index"),
clEnumValEnd));
cl::opt<std::string>
@@ -136,8 +138,8 @@ bool LLVMTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
case GenTgtIntrinsic:
EmitIntrinsics(Records, OS, true);
break;
- case GenEDInfo:
- EmitEnhancedDisassemblerInfo(Records, OS);
+ case GenOptParserDefs:
+ EmitOptParser(Records, OS);
break;
case PrintEnums:
{
@@ -162,6 +164,9 @@ bool LLVMTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
}
break;
}
+ case GenCTags:
+ EmitCTags(Records, OS);
+ break;
}
return false;
diff --git a/utils/TableGen/TableGenBackends.h b/utils/TableGen/TableGenBackends.h
index f0d25d8..28b626e 100644
--- a/utils/TableGen/TableGenBackends.h
+++ b/utils/TableGen/TableGenBackends.h
@@ -68,12 +68,13 @@ void EmitCodeEmitter(RecordKeeper &RK, raw_ostream &OS);
void EmitDAGISel(RecordKeeper &RK, raw_ostream &OS);
void EmitDFAPacketizer(RecordKeeper &RK, raw_ostream &OS);
void EmitDisassembler(RecordKeeper &RK, raw_ostream &OS);
-void EmitEnhancedDisassemblerInfo(RecordKeeper &RK, raw_ostream &OS);
void EmitFastISel(RecordKeeper &RK, raw_ostream &OS);
void EmitInstrInfo(RecordKeeper &RK, raw_ostream &OS);
void EmitPseudoLowering(RecordKeeper &RK, raw_ostream &OS);
void EmitRegisterInfo(RecordKeeper &RK, raw_ostream &OS);
void EmitSubtarget(RecordKeeper &RK, raw_ostream &OS);
void EmitMapTable(RecordKeeper &RK, raw_ostream &OS);
+void EmitOptParser(RecordKeeper &RK, raw_ostream &OS);
+void EmitCTags(RecordKeeper &RK, raw_ostream &OS);
} // End llvm namespace
diff --git a/utils/TableGen/X86DisassemblerShared.h b/utils/TableGen/X86DisassemblerShared.h
index c13a0cc..3ff922b 100644
--- a/utils/TableGen/X86DisassemblerShared.h
+++ b/utils/TableGen/X86DisassemblerShared.h
@@ -10,8 +10,8 @@
#ifndef X86DISASSEMBLERSHARED_H
#define X86DISASSEMBLERSHARED_H
-#include <string>
#include <string.h>
+#include <string>
#define INSTRUCTION_SPECIFIER_FIELDS \
struct OperandSpecifier operands[X86_MAX_OPERANDS]; \
diff --git a/utils/TableGen/X86DisassemblerTables.cpp b/utils/TableGen/X86DisassemblerTables.cpp
index 468a1f8..40a0c1b 100644
--- a/utils/TableGen/X86DisassemblerTables.cpp
+++ b/utils/TableGen/X86DisassemblerTables.cpp
@@ -14,13 +14,12 @@
//
//===----------------------------------------------------------------------===//
-#include "X86DisassemblerShared.h"
#include "X86DisassemblerTables.h"
-
-#include "llvm/TableGen/TableGenBackend.h"
+#include "X86DisassemblerShared.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Format.h"
+#include "llvm/TableGen/TableGenBackend.h"
#include <map>
using namespace llvm;
diff --git a/utils/TableGen/X86DisassemblerTables.h b/utils/TableGen/X86DisassemblerTables.h
index ea006c0..01aeaaf 100644
--- a/utils/TableGen/X86DisassemblerTables.h
+++ b/utils/TableGen/X86DisassemblerTables.h
@@ -19,9 +19,7 @@
#include "X86DisassemblerShared.h"
#include "X86ModRMFilters.h"
-
#include "llvm/Support/raw_ostream.h"
-
#include <vector>
namespace llvm {
diff --git a/utils/TableGen/X86RecognizableInstr.cpp b/utils/TableGen/X86RecognizableInstr.cpp
index d6ed2fe..61b9813 100644
--- a/utils/TableGen/X86RecognizableInstr.cpp
+++ b/utils/TableGen/X86RecognizableInstr.cpp
@@ -14,12 +14,10 @@
//
//===----------------------------------------------------------------------===//
-#include "X86DisassemblerShared.h"
#include "X86RecognizableInstr.h"
+#include "X86DisassemblerShared.h"
#include "X86ModRMFilters.h"
-
#include "llvm/Support/ErrorHandling.h"
-
#include <string>
using namespace llvm;
@@ -39,14 +37,15 @@ using namespace llvm;
MAP(D1, 46) \
MAP(D4, 47) \
MAP(D5, 48) \
- MAP(D8, 49) \
- MAP(D9, 50) \
- MAP(DA, 51) \
- MAP(DB, 52) \
- MAP(DC, 53) \
- MAP(DD, 54) \
- MAP(DE, 55) \
- MAP(DF, 56)
+ MAP(D6, 49) \
+ MAP(D8, 50) \
+ MAP(D9, 51) \
+ MAP(DA, 52) \
+ MAP(DB, 53) \
+ MAP(DC, 54) \
+ MAP(DD, 55) \
+ MAP(DE, 56) \
+ MAP(DF, 57)
// A clone of X86 since we can't depend on something that is generated.
namespace X86Local {
@@ -121,6 +120,7 @@ namespace X86Local {
#define TWO_BYTE_EXTENSION_TABLES \
EXTENSION_TABLE(00) \
EXTENSION_TABLE(01) \
+ EXTENSION_TABLE(0d) \
EXTENSION_TABLE(18) \
EXTENSION_TABLE(71) \
EXTENSION_TABLE(72) \
@@ -765,6 +765,17 @@ void RecognizableInstr::emitInstructionSpecifier(DisassemblerTables &tables) {
HANDLE_OPERAND(immediate)
HANDLE_OPERAND(immediate)
break;
+ case X86Local::MRM_F8:
+ if (Opcode == 0xc6) {
+ assert(numPhysicalOperands == 1 &&
+ "Unexpected number of operands for X86Local::MRM_F8");
+ HANDLE_OPERAND(immediate)
+ } else if (Opcode == 0xc7) {
+ assert(numPhysicalOperands == 1 &&
+ "Unexpected number of operands for X86Local::MRM_F8");
+ HANDLE_OPERAND(relocation)
+ }
+ break;
case X86Local::MRMInitReg:
// Ignored.
break;
diff --git a/utils/TableGen/X86RecognizableInstr.h b/utils/TableGen/X86RecognizableInstr.h
index 9feb3c3..9ec36a3 100644
--- a/utils/TableGen/X86RecognizableInstr.h
+++ b/utils/TableGen/X86RecognizableInstr.h
@@ -17,13 +17,11 @@
#ifndef X86RECOGNIZABLEINSTR_H
#define X86RECOGNIZABLEINSTR_H
-#include "X86DisassemblerTables.h"
-
#include "CodeGenTarget.h"
-
-#include "llvm/TableGen/Record.h"
-#include "llvm/Support/DataTypes.h"
+#include "X86DisassemblerTables.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/DataTypes.h"
+#include "llvm/TableGen/Record.h"
namespace llvm {
diff --git a/utils/TableGen/tdtags b/utils/TableGen/tdtags
new file mode 100644
index 0000000..5214485
--- /dev/null
+++ b/utils/TableGen/tdtags
@@ -0,0 +1,453 @@
+#!/bin/sh
+#===-- tdtags - TableGen tags wrapper ---------------------------*- sh -*-===#
+# vim:set sts=2 sw=2 et:
+#===----------------------------------------------------------------------===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===----------------------------------------------------------------------===#
+#
+# This is a wrapper script to simplify generating ctags(1)-compatible index
+# files for target .td files. Run tdtags -H for more documentation.
+#
+# For portability, this script is intended to conform to IEEE Std 1003.1-2008.
+#
+#===----------------------------------------------------------------------===#
+
+SELF=${0##*/}
+
+usage() {
+cat <<END
+Usage: $SELF [ <options> ] tdfile
+ or: $SELF [ <options> ] -x recipe [arg ...]
+OPTIONS
+ -H Display further help.
+ -a Append the tags to an existing tags file.
+ -f <file> Write tags to the specified file (defaults to 'tags').
+ -I <dir> Add the directory to the search path for tblgen include files.
+ -x <recipe> Generate tags file(s) for a common use case:
+ -q Suppress $TBLGEN error messages.
+ -v Be verbose; report progress.
+END
+ usage_recipes
+}
+
+usage_recipes() {
+cat <<END
+ all - Generate an index in each directory that contains .td files
+ in the LLVM source tree.
+ here - Generate an index for all .td files in the current directory.
+ recurse - Generate an index in each directory that contains .td files
+ in and under the current directory.
+ target [<target> ...]
+ - Generate a tags file for each specified LLVM code generator
+ target, or if none are specified, all targets.
+END
+}
+
+help() {
+cat <<END
+NAME
+ $SELF - generate ctags(1)-compatible index files for tblgen .td source
+
+SYNOPSIS
+ $SELF [ options ] -x recipe [arg ...]
+ $SELF [ options ] [file ...]
+
+DESCRIPTION
+ With the '-x' option, $SELF produces one or more tags files for a
+ particular common use case. See the RECIPES section below for details.
+
+ Without the '-x' option, $SELF provides a ctags(1)-like interface to
+ $TBLGEN.
+
+OPTIONS
+ -a Append newly generated tags to those already in an existing
+ tags file. Without ths option, any and all existing tags are
+ replaced. NOTE: When building a mixed tags file, using ${SELF}
+ for tblgen tags and ctags(1) for other languages, it is best
+ to run ${SELF} first without '-a', and ctags(1) second with '-a',
+ because ctags(1) handling is more capable.
+ -f <file> Use the name <file> for the tags file, rather than the default
+ "tags". If the <file> is "-", then the tag index is written to
+ standard output.
+ -H Display this document.
+ -I <dir> Add the directory <dir> to the search path for 'include'
+ statements in tblgen source.
+ -x Run a canned recipe, rather than operate on specified files.
+ When '-x' is present, the first non-option argument is the
+ name of a recipe, and any further arguments are arguments to
+ that recipe. With no arguments, lists the available recipes.
+ -q Suppress $TBLGEN error messages. Not all .td files are well-
+ formed outside a specific context, so recipes will sometimes
+ produce error messages for certain .td files. These errors
+ do not affect the indices produced for valid files.
+ -v Be verbose; report progress.
+
+RECIPES
+ $SELF -x all
+ Produce a tags file in every directory in the LLVM source tree
+ that contains any .td files.
+ $SELF -x here
+ Produce a tags file from .td files in the current directory.
+ $SELF -x recurse
+ Produce a tags file in every directory that contains any .td
+ files, in and under the current directory.
+ $SELF -x target [<target> ...]
+ Produce a tags file for each named code generator target, or
+ if none are named, for all code generator targets.
+END
+}
+
+# Temporary file management.
+#
+# Since SUS sh(1) has no arrays, this script makes extensive use of
+# temporary files. The follow are 'global' and used to carry information
+# across functions:
+# $TMP:D Include directories.
+# $TMP:I Included files.
+# $TMP:T Top-level files, that are not included by another.
+# $TMP:W Directories in which to generate tags (Worklist).
+# For portability to OS X, names must not differ only in case.
+#
+TMP=${TMPDIR:-/tmp}/$SELF:$$
+trap "rm -f $TMP*" 0
+trap exit 1 2 13 15
+>$TMP:D
+
+td_dump()
+{
+ if [ $OPT_VERBOSE -gt 1 ]
+ then
+ printf '===== %s =====\n' "$1"
+ cat <"$1"
+ fi
+}
+
+# Escape the arguments, taken as a whole.
+e() {
+ printf '%s' "$*" |
+ sed -e "s/'/'\\\\''/g" -e "1s/^/'/" -e "\$s/\$/'/"
+}
+
+# Determine whether the given directory contains at least one .td file.
+dir_has_td() {
+ for i in $1/*.td
+ do
+ [ -f "$i" ] && return 0
+ done
+ return 1
+}
+
+# Partition the supplied list of files, plus any files included from them,
+# into two groups:
+# $TMP:T Top-level files, that are not included by another.
+# $TMP:I Included files.
+# Add standard directories to the include paths in $TMP:D if this would
+# benefit the any of the included files.
+td_prep() {
+ >$TMP:E
+ >$TMP:J
+ for i in *.td
+ do
+ [ "x$i" = 'x*.td' ] && return 1
+ if [ -f "$i" ]
+ then
+ printf '%s\n' "$i" >>$TMP:E
+ sed -n -e 's/include[[:space:]]"\(.*\)".*/\1/p' <"$i" >>$TMP:J
+ else
+ printf >&2 '%s: "%s" not found.\n' "$SELF" "$i"
+ exit 7
+ fi
+ done
+ sort -u <$TMP:E >$TMP:X
+ sort -u <$TMP:J >$TMP:I
+ # A file that exists but is not included is toplevel.
+ comm -23 $TMP:X $TMP:I >$TMP:T
+ td_dump $TMP:T
+ td_dump $TMP:I
+ # Check include files.
+ while read i
+ do
+ [ -f "$i" ] && continue
+ while read d
+ do
+ [ -f "$d/$i" ] && break
+ done <$TMP:D
+ if [ -z "$d" ]
+ then
+ # See whether this include file can be found in a common location.
+ for d in $LLVM_SRC_ROOT/include \
+ $LLVM_SRC_ROOT/tools/clang/include
+ do
+ if [ -f "$d/$i" ]
+ then
+ printf '%s\n' "$d" >>$TMP:D
+ break
+ fi
+ done
+ fi
+ done <$TMP:I
+ td_dump $TMP:D
+}
+
+# Generate tags for the list of files in $TMP:T.
+td_tag() {
+ # Collect include directories.
+ inc=
+ while read d
+ do
+ inc="${inc}${inc:+ }$(e "-I=$d")"
+ done <$TMP:D
+
+ if [ $OPT_VERBOSE -ne 0 ]
+ then
+ printf >&2 'In "%s",\n' "$PWD"
+ fi
+
+ # Generate tags for each file.
+ n=0
+ while read i
+ do
+ if [ $OPT_VERBOSE -ne 0 ]
+ then
+ printf >&2 ' generating tags from "%s"\n' "$i"
+ fi
+ n=$((n + 1))
+ t=$(printf '%s:A:%05u' "$TMP" $n)
+ eval $TBLGEN --gen-ctags $inc "$i" >$t 2>$TMP:F
+ [ $OPT_NOTBLGENERR -eq 1 ] || cat $TMP:F
+ done <$TMP:T
+
+ # Add existing tags if requested.
+ if [ $OPT_APPEND -eq 1 -a -f "$OPT_TAGSFILE" ]
+ then
+ if [ $OPT_VERBOSE -ne 0 ]
+ then
+ printf >&2 ' and existing tags from "%s"\n' "$OPT_TAGSFILE"
+ fi
+ n=$((n + 1))
+ t=$(printf '%s:A:%05u' "$TMP" $n)
+ sed -e '/^!_TAG_/d' <"$OPT_TAGSFILE" | sort -u >$t
+ fi
+
+ # Merge tags.
+ if [ $n = 1 ]
+ then
+ mv -f "$t" $TMP:M
+ else
+ sort -m -u $TMP:A:* >$TMP:M
+ fi
+
+ # Emit tags.
+ if [ x${OPT_TAGSFILE}x = x-x ]
+ then
+ cat $TMP:M
+ else
+ if [ $OPT_VERBOSE -ne 0 ]
+ then
+ printf >&2 ' into "%s".\n' "$OPT_TAGSFILE"
+ fi
+ mv -f $TMP:M "$OPT_TAGSFILE"
+ fi
+}
+
+# Generate tags for the current directory.
+td_here() {
+ td_prep
+ [ -s $TMP:T ] || return 1
+ td_tag
+}
+
+# Generate tags for the current directory, and report an error if there are
+# no .td files present.
+do_here()
+{
+ if ! td_here
+ then
+ printf >&2 '%s: Nothing to do here.\n' "$SELF"
+ exit 1
+ fi
+}
+
+# Generate tags for all .td files under the current directory.
+do_recurse()
+{
+ td_find "$PWD"
+ td_dirs
+}
+
+# Generate tags for all .td files in LLVM.
+do_all()
+{
+ td_find "$LLVM_SRC_ROOT"
+ td_dirs
+}
+
+# Generate tags for each directory in the worklist $TMP:W.
+td_dirs()
+{
+ while read d
+ do
+ (cd "$d" && td_here)
+ done <$TMP:W
+}
+
+# Find directories containing .td files within the specified directory,
+# and record them in the worklist $TMP:W.
+td_find()
+{
+ find -L "$1" -type f -name '*.td' |
+ sed -e 's:/[^/]*$::' |
+ sort -u >$TMP:W
+ td_dump $TMP:W
+}
+
+# Generate tags for the specified code generator targets, or
+# if there are no arguments, all targets.
+do_targets() {
+ cd $LLVM_SRC_ROOT/lib/Target
+ if [ -z "$*" ]
+ then
+ td_find "$PWD"
+ else
+ # Check that every specified argument is a target directory;
+ # if not, list all target directories.
+ for d
+ do
+ if [ -d "$d" ] && dir_has_td "$d"
+ then
+ printf '%s/%s\n' "$PWD" "$d"
+ else
+ printf >&2 '%s: "%s" is not a target. Targets are:\n' "$SELF" "$d"
+ for d in *
+ do
+ [ -d "$d" ] || continue
+ dir_has_td "$d" && printf >&2 ' %s\n' "$d"
+ done
+ exit 2
+ fi
+ done >$TMP:W
+ fi
+ td_dirs
+}
+
+# Change to the directory at the top of the enclosing LLVM source tree,
+# if possible.
+llvm_src_root() {
+ while [ "$PWD" != / ]
+ do
+ # Use this directory if multiple notable subdirectories are present.
+ [ -d include/llvm -a -d lib/Target ] && return 0
+ cd ..
+ done
+ return 1
+}
+
+# Ensure sort(1) behaves consistently.
+LC_ALL=C
+export LC_ALL
+
+# Globals.
+TBLGEN=llvm-tblgen
+LLVM_SRC_ROOT=
+
+# Command options.
+OPT_TAGSFILE=tags
+OPT_RECIPES=0
+OPT_APPEND=0
+OPT_VERBOSE=0
+OPT_NOTBLGENERR=0
+
+while getopts 'af:hxqvHI:' opt
+do
+ case $opt in
+ a)
+ OPT_APPEND=1
+ ;;
+ f)
+ OPT_TAGSFILE="$OPTARG"
+ ;;
+ x)
+ OPT_RECIPES=1
+ ;;
+ q)
+ OPT_NOTBLGENERR=1
+ ;;
+ v)
+ OPT_VERBOSE=$((OPT_VERBOSE + 1))
+ ;;
+ I)
+ printf '%s\n' "$OPTARG" >>$TMP:D
+ ;;
+ [hH])
+ help
+ exit 0
+ ;;
+ *)
+ usage >&2
+ exit 4
+ ;;
+ esac
+done
+shift $((OPTIND - 1))
+
+# Handle the case where tdtags is a simple ctags(1)-like wrapper for tblgen.
+if [ $OPT_RECIPES -eq 0 ]
+then
+ if [ -z "$*" ]
+ then
+ help >&2
+ exit 5
+ fi
+ for i
+ do
+ printf '%s\n' "$i"
+ done >$TMP:T
+ td_tag
+ exit $?
+fi
+
+# Find the directory at the top of the enclosing LLVM source tree.
+if ! LLVM_SRC_ROOT=$(llvm_src_root && pwd)
+then
+ printf >&2 '%s: Run from within the LLVM source tree.\n' "$SELF"
+ exit 3
+fi
+
+# Select canned actions.
+RECIPE="$1"
+case "$RECIPE" in
+all)
+ shift
+ do_all
+ ;;
+.|cwd|here)
+ shift
+ do_here
+ ;;
+recurse)
+ shift
+ do_recurse
+ ;;
+target)
+ shift
+ do_targets "$@"
+ ;;
+*)
+ if [ -n "$RECIPE" ]
+ then
+ shift
+ printf >&2 '%s: Unknown recipe "-x %s". ' "$SELF" "$RECIPE"
+ fi
+ printf >&2 'Recipes:\n'
+ usage_recipes >&2
+ printf >&2 'Run "%s -H" for help.\n' "$SELF"
+ exit 6
+ ;;
+esac
+
+exit $?
diff --git a/utils/UpdateCMakeLists.pl b/utils/UpdateCMakeLists.pl
index d92a767..c896ea8 100755
--- a/utils/UpdateCMakeLists.pl
+++ b/utils/UpdateCMakeLists.pl
@@ -68,7 +68,7 @@ sub UpdateCMake {
while(<IN>) {
if (!$foundLibrary) {
print OUT $_;
- if (/^add_[^_]+_library\(/ || /^add_llvm_target\(/ || /^add_executable\(/) {
+ if (/^add_[^_]+_library\(/ || /^add_llvm_target\(/ || /^add_[^_]+_executable\(/) {
$foundLibrary = 1;
EmitCMakeList($dir);
}
diff --git a/utils/buildit/build_llvm b/utils/buildit/build_llvm
index 6aee831..c056b97 100755
--- a/utils/buildit/build_llvm
+++ b/utils/buildit/build_llvm
@@ -77,6 +77,45 @@ rm $SRC_DIR/Makefile || exit 1
# Now create our own by editing the top-level Makefile, deleting every line marked "Apple-style":
sed -e '/[Aa]pple-style/d' -e '/include.*GNUmakefile/d' $ORIG_SRC_DIR/Makefile > $SRC_DIR/Makefile || exit 1
+SUBVERSION=`echo $RC_ProjectSourceVersion | sed -e 's/.*\.\([0-9]*\).*/\1/'`
+if [ "x$SUBVERSION" != "x$RC_ProjectSourceVersion" ]; then
+ LLVM_SUBMIT_SUBVERSION=`printf "%02d" $SUBVERSION`
+ RC_ProjectSourceVersion=`echo $RC_ProjectSourceVersion | sed -e 's/\..*//'`
+ LLVM_SUBMIT_VERSION=$RC_ProjectSourceVersion
+fi
+if [ "x$LLVM_SUBMIT_SUBVERSION" = "x00" -o "x$LLVM_SUBMIT_SUBVERSION" = "x0" ]; then
+ LLVM_VERSION="$LLVM_SUBMIT_VERSION"
+else
+ LLVM_VERSION="$LLVM_SUBMIT_VERSION-$LLVM_SUBMIT_SUBVERSION"
+fi
+
+# Figure out how many make processes to run.
+SYSCTL=`sysctl -n hw.activecpu`
+# sysctl -n hw.* does not work when invoked via B&I chroot /BuildRoot.
+# Builders can default to 2, since even if they are single processor,
+# nothing else is running on the machine.
+if [ -z "$SYSCTL" ]; then
+ SYSCTL=2
+fi
+JOBS_FLAG="-j $SYSCTL"
+
+COMMON_CONFIGURE_OPTS="\
+ --prefix=$DEST_DIR$DEST_ROOT \
+ --enable-assertions=$LLVM_ASSERTIONS \
+ --enable-optimized=$LLVM_OPTIMIZED \
+ --disable-bindings"
+
+COMMON_MAKEFLAGS="\
+ UNIVERSAL=1 \
+ UNIVERSAL_SDK_PATH=$SDKROOT \
+ NO_RUNTIME_LIBS=1 \
+ DISABLE_EDIS=1 \
+ REQUIRES_RTTI=1 \
+ DEBUG_SYMBOLS=1 \
+ LLVM_SUBMIT_VERSION=$LLVM_SUBMIT_VERSION \
+ LLVM_SUBMIT_SUBVERSION=$LLVM_SUBMIT_SUBVERSION \
+ VERBOSE=1"
+
# Build the LLVM tree universal.
mkdir -p $DIR/obj-llvm || exit 1
cd $DIR/obj-llvm || exit 1
@@ -89,6 +128,7 @@ if [ "$ARM_HOSTED_BUILD" = yes ]; then
for prog in ar nm ranlib strip lipo ld as ; do
P=$DIR/bin/arm-apple-darwin$DARWIN_VERS-${prog}
T=`xcrun -sdk $SDKROOT -find ${prog}`
+ ln -s $T $DIR/bin/$prog
echo '#!/bin/sh' > $P || exit 1
echo 'exec '$T' "$@"' >> $P || exit 1
chmod a+x $P || exit 1
@@ -97,80 +137,74 @@ if [ "$ARM_HOSTED_BUILD" = yes ]; then
for prog in clang clang++ ; do
P=$DIR/bin/arm-apple-darwin$DARWIN_VERS-${prog}
T=`xcrun -sdk $SDKROOT -find ${prog}`
+ ln -s $T $DIR/bin/$prog
echo '#!/bin/sh' > $P || exit 1
echo 'exec '$T' -arch armv7 -isysroot '${SDKROOT}' "$@"' >> $P || exit 1
chmod a+x $P || exit 1
done
PATH=$DIR/bin:$PATH
-fi
-if [ "$ARM_HOSTED_BUILD" = yes ]; then
- configure_opts="--enable-targets=arm --host=arm-apple-darwin10 \
- --target=arm-apple-darwin10 --build=i686-apple-darwin10"
-elif [ "$IOS_SIM_BUILD" = yes ]; then
- # Use a non-standard "darwin_sim" host triple to trigger a cross-build.
- configure_opts="--enable-targets=x86 --host=i686-apple-darwin_sim \
- --build=i686-apple-darwin10"
+ unset SDKROOT && \
+ $SRC_DIR/configure $COMMON_CONFIGURE_OPTS \
+ --enable-targets=arm \
+ --host=arm-apple-darwin10 \
+ --target=arm-apple-darwin10 \
+ --build=i686-apple-darwin10 \
+ --program-prefix="" \
+ || exit 1
+
+ if [ -n "$IPHONEOS_DEPLOYMENT_TARGET" ]; then
+ COMMON_MAKEFLAGS="$COMMON_MAKEFLAGS \
+ DEPLOYMENT_TARGET=-mios-version-min=$IPHONEOS_DEPLOYMENT_TARGET"
+ fi
+
+ make $JOBS_FLAG $COMMON_MAKEFLAGS SDKROOT= UNIVERSAL_ARCH="$HOSTS" \
+ CXXFLAGS="-DLLVM_VERSION_INFO='\" Apple Build #$LLVM_VERSION\"'"
+ if [ $? != 0 ] ; then
+ echo "error: LLVM 'make' failed!"
+ exit 1
+ fi
+
else
- configure_opts="--enable-targets=arm,x86"
-fi
+# not $ARM_HOSTED_BUILD
+
+ export CC=`xcrun -find clang`
+ export CXX=`xcrun -find clang++`
+
+ if [ "$IOS_SIM_BUILD" = yes ]; then
+ # Use a non-standard "darwin_sim" host triple to trigger a cross-build.
+ configure_opts="--enable-targets=x86 --host=i686-apple-darwin_sim \
+ --build=i686-apple-darwin10"
+ if [ -n "$IPHONEOS_DEPLOYMENT_TARGET" ]; then
+ COMMON_MAKEFLAGS="$COMMON_MAKEFLAGS \
+ DEPLOYMENT_TARGET=-mios-simulator-version-min=$IPHONEOS_DEPLOYMENT_TARGET"
+ fi
+ else
+ configure_opts="--enable-targets=arm,x86"
+ if [ -n "$MACOSX_DEPLOYMENT_TARGET" ]; then
+ COMMON_MAKEFLAGS="$COMMON_MAKEFLAGS \
+ DEPLOYMENT_TARGET=-mmacosx-version-min=$MACOSX_DEPLOYMENT_TARGET"
+ fi
+ fi
-if [ "$ARM_HOSTED_BUILD" != yes ]; then
if [ $SDKROOT ]; then
CPPFLAGS="$CPPFLAGS -isysroot $SDKROOT"
fi
for host in $HOSTS; do :; done
CPPFLAGS="$CPPFLAGS -arch $host"
-fi
-if [ \! -f Makefile.config ]; then
- $SRC_DIR/configure --prefix=$DEST_DIR$DEST_ROOT $configure_opts \
- --enable-assertions=$LLVM_ASSERTIONS \
- --enable-optimized=$LLVM_OPTIMIZED \
- --disable-bindings \
+ $SRC_DIR/configure $COMMON_CONFIGURE_OPTS $configure_opts \
+ --program-prefix="" \
CPPFLAGS="$CPPFLAGS" \
|| exit 1
-fi
-
-SUBVERSION=`echo $RC_ProjectSourceVersion | sed -e 's/.*\.\([0-9]*\).*/\1/'`
-
-if [ "x$SUBVERSION" != "x$RC_ProjectSourceVersion" ]; then
- LLVM_SUBMIT_SUBVERSION=`printf "%02d" $SUBVERSION`
- RC_ProjectSourceVersion=`echo $RC_ProjectSourceVersion | sed -e 's/\..*//'`
- LLVM_SUBMIT_VERSION=$RC_ProjectSourceVersion
-fi
-if [ "x$LLVM_SUBMIT_SUBVERSION" = "x00" -o "x$LLVM_SUBMIT_SUBVERSION" = "x0" ]; then
- LLVM_VERSION="$LLVM_SUBMIT_VERSION"
-else
- LLVM_VERSION="$LLVM_SUBMIT_VERSION-$LLVM_SUBMIT_SUBVERSION"
-fi
-
-# Figure out how many make processes to run.
-SYSCTL=`sysctl -n hw.activecpu`
-# sysctl -n hw.* does not work when invoked via B&I chroot /BuildRoot.
-# Builders can default to 2, since even if they are single processor,
-# nothing else is running on the machine.
-if [ -z "$SYSCTL" ]; then
- SYSCTL=2
-fi
-JOBS_FLAG="-j $SYSCTL"
-
-make $JOBS_FLAG $OPTIMIZE_OPTS UNIVERSAL=1 UNIVERSAL_ARCH="$HOSTS" \
- UNIVERSAL_SDK_PATH=$SDKROOT \
- NO_RUNTIME_LIBS=1 \
- DISABLE_EDIS=1 \
- REQUIRES_RTTI=1 \
- DEBUG_SYMBOLS=1 \
- LLVM_SUBMIT_VERSION=$LLVM_SUBMIT_VERSION \
- LLVM_SUBMIT_SUBVERSION=$LLVM_SUBMIT_SUBVERSION \
- CXXFLAGS="-DLLVM_VERSION_INFO='\" Apple Build #$LLVM_VERSION\"'" \
- VERBOSE=1
-
-if [ $? != 0 ] ; then
+ make $JOBS_FLAG $COMMON_MAKEFLAGS UNIVERSAL_ARCH="$HOSTS" \
+ CXXFLAGS="-DLLVM_VERSION_INFO='\" Apple Build #$LLVM_VERSION\"'"
+ if [ $? != 0 ] ; then
echo "error: LLVM 'make' failed!"
exit 1
+ fi
fi
################################################################################
@@ -185,14 +219,7 @@ rm -rf * || exit 1
cd $DIR/obj-llvm || exit 1
# Install the tree into the destination directory.
-make $LOCAL_MAKEFLAGS $OPTIMIZE_OPTS UNIVERSAL=1 UNIVERSAL_ARCH="$HOSTS" \
- NO_RUNTIME_LIBS=1 \
- DISABLE_EDIS=1 \
- DEBUG_SYMBOLS=1 \
- LLVM_SUBMIT_VERSION=$LLVM_SUBMIT_VERSION \
- LLVM_SUBMIT_SUBVERSION=$LLVM_SUBMIT_SUBVERSION \
- OPTIMIZE_OPTION='-O3' VERBOSE=1 install
-
+make $JOBS_FLAG $COMMON_MAKEFLAGS UNIVERSAL_ARCH="$HOSTS" install
if ! test $? == 0 ; then
echo "error: LLVM 'make install' failed!"
exit 1
@@ -207,6 +234,16 @@ RC_ProjectSourceSubversion=`printf "%d" $LLVM_MINOR_VERSION`
echo "#define LLVM_VERSION ${RC_ProjectSourceVersion}" > $DEST_DIR$DEST_ROOT/include/llvm/Version.h
echo "#define LLVM_MINOR_VERSION ${RC_ProjectSourceSubversion}" >> $DEST_DIR$DEST_ROOT/include/llvm/Version.h
+# Run unifdef to preprocess the installed headers to reflect whether this
+# was a debug or release build.
+for file in `find $DEST_DIR$DEST_ROOT/include -type f -print`; do
+ if [ "$LLVM_ASSERTIONS" = yes ]; then
+ unifdef -UNDEBUG -D_DEBUG -o $file $file
+ else
+ unifdef -DNDEBUG -U_DEBUG -ULLVM_ENABLE_DUMP -o $file $file
+ fi
+done
+
# Find the right version of strip to use.
STRIP=strip
if [ -n "$SDKROOT" ]; then
@@ -263,9 +300,10 @@ cd $SYM_DIR || exit 1
rm -rf * || exit 1
# Generate .dSYM files
+DSYMUTIL=`xcrun -find dsymutil`
find $DEST_DIR -perm -0111 -type f \
! \( -name '*.la' -o -name gccas -o -name gccld -o -name llvm-config -o -name '*.a' \) \
- -print | xargs -n 1 -P ${SYSCTL} dsymutil
+ -print | xargs -n 1 -P ${SYSCTL} ${DSYMUTIL}
# Save .dSYM files and .a archives
cd $DEST_DIR || exit 1
diff --git a/utils/clang-parse-diagnostics-file b/utils/clang-parse-diagnostics-file
index b8ea8ea..59b13f3 100755
--- a/utils/clang-parse-diagnostics-file
+++ b/utils/clang-parse-diagnostics-file
@@ -1,5 +1,6 @@
#!/usr/bin/env python
+import os
import plistlib
def main():
@@ -59,20 +60,37 @@ Utility for dumping Clang-style logged diagnostics.\
</array>
</plist>""" % data
- # Load the diagnostics.
+ # Get the list of files and diagnostics to report.
+ to_report = []
diags = plistlib.readPlistFromString(data)
+ for file_diags in diags:
+ file = file_diags.get('main-file')
+
+ # Ignore diagnostics for 'conftest.c', which is the file autoconf uses
+ # for its tests (which frequently will have warnings).
+ if os.path.basename(file) == 'conftest.c':
+ continue
+
+ # Get the diagnostics for the selected levels.
+ selected_diags = [d
+ for d in file_diags.get('diagnostics', ())
+ if levels[d.get('level')] or opts.all]
+ if selected_diags:
+ to_report.append((file, selected_diags))
- # Print out the diagnostics.
+ # If there are no diagnostics to report, show nothing.
+ if not to_report:
+ return
+
+ # Otherwise, print out the diagnostics.
print
print "**** BUILD DIAGNOSTICS ****"
- for i, file_diags in enumerate(diags):
- file = file_diags.get('main-file')
+ for file,selected_diags in to_report:
print "*** %s ***" % file
- for d in file_diags.get('diagnostics', ()):
- if levels[d.get('level')] or opts.all:
- print " %s:%s:%s: %s: %s" % (
- d.get('filename'), d.get('line'), d.get('column'),
- d.get('level'), d.get('message'))
+ for d in selected_diags:
+ print " %s:%s:%s: %s: %s" % (
+ d.get('filename'), d.get('line'), d.get('column'),
+ d.get('level'), d.get('message'))
if __name__ == "__main__":
main()
diff --git a/utils/emacs/llvm-mode.el b/utils/emacs/llvm-mode.el
index 3780624..25d9742 100644
--- a/utils/emacs/llvm-mode.el
+++ b/utils/emacs/llvm-mode.el
@@ -5,7 +5,6 @@
;; Create mode-specific tables.
(defvar llvm-mode-syntax-table nil
"Syntax table used while in LLVM mode.")
-
(defvar llvm-font-lock-keywords
(list
;; Comments
@@ -31,12 +30,14 @@
"define" "global" "constant" "const" "internal" "linkonce" "linkonce_odr"
"weak" "weak_odr" "appending" "uninitialized" "implementation" "..."
"null" "undef" "to" "except" "not" "target" "endian" "little" "big"
- "pointersize" "deplibs" "volatile" "fastcc" "coldcc" "cc") 'words) . font-lock-keyword-face)
+ "pointersize" "volatile" "fastcc" "coldcc" "cc") 'words) . font-lock-keyword-face)
;; Arithmetic and Logical Operators
`(,(regexp-opt '("add" "sub" "mul" "div" "rem" "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" "vaarg" "vanext") 'words) . font-lock-keyword-face)
+ `(,(regexp-opt '("phi" "tail" "call" "cast" "select" "to" "shl" "shr" "fcmp" "icmp" "vaarg" "vanext") 'words) . font-lock-keyword-face)
;; Control instructions
`(,(regexp-opt '("ret" "br" "switch" "invoke" "unwind" "unreachable") 'words) . font-lock-keyword-face)
;; Memory operators
@@ -111,7 +112,7 @@
(interactive)
(kill-all-local-variables)
(use-local-map llvm-mode-map) ; Provides the local keymap.
- (setq major-mode 'llvm-mode)
+ (setq major-mode 'llvm-mode)
(make-local-variable 'font-lock-defaults)
(setq major-mode 'llvm-mode ; This is how describe-mode
diff --git a/utils/git/find-rev b/utils/git/find-rev
index a6161db..059ca0b 100755
--- a/utils/git/find-rev
+++ b/utils/git/find-rev
@@ -5,9 +5,9 @@ import os, sys, subprocess
def main():
from optparse import OptionParser, OptionGroup
parser = OptionParser("usage: %prog [options] <repo> <revision>")
- parser.add_option("", "--dump-section-data", dest="dumpSectionData",
- help="Dump the contents of sections",
- action="store_true", default=False)
+ parser.add_option("", "--branch", dest="branch",
+ help="Ref for the branch to search [%default]",
+ action="store", default="git-svn")
(opts, args) = parser.parse_args()
if len(args) != 2:
@@ -21,7 +21,7 @@ def main():
parser.error("invalid revision argument (not an integer)")
os.chdir(repo)
- p = subprocess.Popen(['git', 'rev-list', 'git-svn', '--pretty'],
+ p = subprocess.Popen(['git', 'rev-list', opts.branch, '--pretty'],
stdout=subprocess.PIPE)
bestRev = bestCommit = None
diff --git a/utils/kate/llvm.xml b/utils/kate/llvm.xml
index 074fa16..1778cfc 100644
--- a/utils/kate/llvm.xml
+++ b/utils/kate/llvm.xml
@@ -90,6 +90,7 @@
<item> readonly </item>
<item> ssp </item>
<item> sspreq </item>
+ <item> sspstrong </item>
</list>
<list name="types">
<item> float </item>
diff --git a/utils/lit/MANIFEST.in b/utils/lit/MANIFEST.in
new file mode 100644
index 0000000..6491a02
--- /dev/null
+++ b/utils/lit/MANIFEST.in
@@ -0,0 +1,7 @@
+include TODO lit.py
+recursive-include tests *
+global-exclude *pyc
+global-exclude *~
+prune tests/Output
+prune tests/*/Output
+prune tests/*/*/Output
diff --git a/utils/lit/TODO b/utils/lit/TODO
index 6d7f7ea..d2ff842 100644
--- a/utils/lit/TODO
+++ b/utils/lit/TODO
@@ -7,3 +7,20 @@
- Support valgrind in all configs, and LLVM style valgrind.
- Support a timeout / ulimit.
+
+ - Rename 'lit' injected variable for config to be lit_config.
+
+ - Allow import of 'lit' in test suite definitions.
+
+ - Create an explicit test suite object (instead of using the top-level
+ TestingConfig object).
+
+ - Allow 'lit' driver to cooperate with test suites to add options (or at least
+ sanitize accepted params).
+
+ - 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.
+
diff --git a/utils/lit/lit/ExampleTests/Clang/lit.cfg b/utils/lit/lit/ExampleTests/Clang/lit.cfg
index 1e1e807..9295bd9 100644
--- a/utils/lit/lit/ExampleTests/Clang/lit.cfg
+++ b/utils/lit/lit/ExampleTests/Clang/lit.cfg
@@ -14,7 +14,7 @@ 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 and TclTest formats for XFAIL checks.
+# target_triple: Used by ShTest format for XFAIL checks.
config.target_triple = 'foo'
###
diff --git a/utils/lit/lit/ExampleTests/LLVM.InTree/test/Bar/data.txt b/utils/lit/lit/ExampleTests/LLVM.InTree/test/Bar/data.txt
new file mode 100644
index 0000000..45b983b
--- /dev/null
+++ b/utils/lit/lit/ExampleTests/LLVM.InTree/test/Bar/data.txt
@@ -0,0 +1 @@
+hi
diff --git a/utils/lit/lit/ExampleTests/LLVM.InTree/test/Bar/dg.exp b/utils/lit/lit/ExampleTests/LLVM.InTree/test/Bar/dg.exp
deleted file mode 100644
index 2bda07a..0000000
--- a/utils/lit/lit/ExampleTests/LLVM.InTree/test/Bar/dg.exp
+++ /dev/null
@@ -1,6 +0,0 @@
-load_lib llvm.exp
-
-if { [llvm_supports_target X86] } {
- RunLLVMTests [lsort [glob -nocomplain $srcdir/$subdir/*.{ll}]]
-}
-
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
new file mode 100644
index 0000000..3ff3633
--- /dev/null
+++ b/utils/lit/lit/ExampleTests/LLVM.InTree/test/Bar/pct-S.ll
@@ -0,0 +1 @@
+; 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
index 3fdd63c..533c445 100644
--- a/utils/lit/lit/ExampleTests/LLVM.InTree/test/lit.cfg
+++ b/utils/lit/lit/ExampleTests/LLVM.InTree/test/lit.cfg
@@ -8,11 +8,11 @@ import os
config.name = 'LLVM'
# testFormat: The test format to use to interpret tests.
-config.test_format = lit.formats.TclTest()
+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 = []
+config.suffixes = [ '.ll' ]
# test_source_root: The root path where tests are located.
config.test_source_root = os.path.dirname(__file__)
@@ -64,74 +64,3 @@ if config.test_exec_root is None:
lit.load_config(config, site_cfg)
raise SystemExit
-###
-
-# Load site data from DejaGNU's site.exp.
-import re
-site_exp = {}
-# FIXME: Implement lit.site.cfg.
-for line in open(os.path.join(config.llvm_obj_root, 'test', 'site.exp')):
- m = re.match('set ([^ ]+) "([^"]*)"', line)
- if m:
- site_exp[m.group(1)] = m.group(2)
-
-excludes = []
-
-# Provide target_triple for use in XFAIL.
-config.target_triple = site_exp['target_triplet']
-
-# Provide llvm_supports_target for use in local configs.
-targets = set(site_exp["TARGETS_TO_BUILD"].split())
-def llvm_supports_target(name):
- return name in targets
-
-# Provide on_clone hook for reading 'dg.exp'.
-import os
-simpleLibData = re.compile(r"""load_lib llvm.exp
-
-RunLLVMTests \[lsort \[glob -nocomplain \$srcdir/\$subdir/\*\.(.*)\]\]""",
- re.MULTILINE)
-conditionalLibData = re.compile(r"""load_lib llvm.exp
-
-if.*\[ ?(llvm[^ ]*) ([^ ]*) ?\].*{
- *RunLLVMTests \[lsort \[glob -nocomplain \$srcdir/\$subdir/\*\.(.*)\]\]
-\}""", re.MULTILINE)
-def on_clone(parent, cfg, for_path):
- def addSuffixes(match):
- if match[0] == '{' and match[-1] == '}':
- cfg.suffixes = ['.' + s for s in match[1:-1].split(',')]
- else:
- cfg.suffixes = ['.' + match]
-
- libPath = os.path.join(os.path.dirname(for_path),
- 'dg.exp')
- if not os.path.exists(libPath):
- cfg.unsupported = True
- return
-
- # Reset unsupported, in case we inherited it.
- cfg.unsupported = False
- lib = open(libPath).read().strip()
-
- # Check for a simple library.
- m = simpleLibData.match(lib)
- if m:
- addSuffixes(m.group(1))
- return
-
- # Check for a conditional test set.
- m = conditionalLibData.match(lib)
- if m:
- funcname,arg,match = m.groups()
- addSuffixes(match)
-
- func = globals().get(funcname)
- if not func:
- lit.error('unsupported predicate %r' % funcname)
- elif not func(arg):
- cfg.unsupported = True
- return
- # Otherwise, give up.
- lit.error('unable to understand %r:\n%s' % (libPath, lib))
-
-config.on_clone = on_clone
diff --git a/utils/lit/lit/ExampleTests/LLVM.InTree/test/lit.site.cfg b/utils/lit/lit/ExampleTests/LLVM.InTree/test/lit.site.cfg
index 3bfee54..d45f3ac 100644
--- a/utils/lit/lit/ExampleTests/LLVM.InTree/test/lit.site.cfg
+++ b/utils/lit/lit/ExampleTests/LLVM.InTree/test/lit.site.cfg
@@ -1,8 +1,5 @@
# -*- Python -*-
-## Autogenerated by Makefile ##
-# Do not edit!
-
# Preserve some key paths for use by main LLVM test suite config.
config.llvm_obj_root = os.path.dirname(os.path.dirname(__file__))
diff --git a/utils/lit/lit/ExampleTests/LLVM.InTree/test/site.exp b/utils/lit/lit/ExampleTests/LLVM.InTree/test/site.exp
deleted file mode 100644
index 4bc58d7..0000000
--- a/utils/lit/lit/ExampleTests/LLVM.InTree/test/site.exp
+++ /dev/null
@@ -1,10 +0,0 @@
-## these variables are automatically generated by make ##
-# Do not edit here. If you wish to override these values
-# edit the last section
-set target_triplet "x86_64-apple-darwin10"
-set TARGETS_TO_BUILD "X86 Sparc PowerPC ARM Mips CellSPU PIC16 XCore MSP430 Blackfin MSIL CppBackend"
-set srcroot "/Volumes/Data/ddunbar/llvm"
-set objroot "/Volumes/Data/ddunbar/llvm.obj.64"
-set srcdir "/Volumes/Data/ddunbar/llvm/test"
-set objdir "/Volumes/Data/ddunbar/llvm.obj.64/test"
-## All variables above are generated by configure. Do Not Edit ##
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
index bdcc35e..94a02d8 100644
--- a/utils/lit/lit/ExampleTests/LLVM.OutOfTree/obj/test/lit.site.cfg
+++ b/utils/lit/lit/ExampleTests/LLVM.OutOfTree/obj/test/lit.site.cfg
@@ -1,8 +1,5 @@
# -*- Python -*-
-## Autogenerated by Makefile ##
-# Do not edit!
-
# Preserve some key paths for use by main LLVM test suite config.
config.llvm_obj_root = os.path.dirname(os.path.dirname(__file__))
diff --git a/utils/lit/lit/ExampleTests/LLVM.OutOfTree/obj/test/site.exp b/utils/lit/lit/ExampleTests/LLVM.OutOfTree/obj/test/site.exp
deleted file mode 100644
index 4bc58d7..0000000
--- a/utils/lit/lit/ExampleTests/LLVM.OutOfTree/obj/test/site.exp
+++ /dev/null
@@ -1,10 +0,0 @@
-## these variables are automatically generated by make ##
-# Do not edit here. If you wish to override these values
-# edit the last section
-set target_triplet "x86_64-apple-darwin10"
-set TARGETS_TO_BUILD "X86 Sparc PowerPC ARM Mips CellSPU PIC16 XCore MSP430 Blackfin MSIL CppBackend"
-set srcroot "/Volumes/Data/ddunbar/llvm"
-set objroot "/Volumes/Data/ddunbar/llvm.obj.64"
-set srcdir "/Volumes/Data/ddunbar/llvm/test"
-set objdir "/Volumes/Data/ddunbar/llvm.obj.64/test"
-## All variables above are generated by configure. Do Not Edit ##
diff --git a/utils/lit/lit/ExampleTests/LLVM.OutOfTree/src/test/Foo/dg.exp b/utils/lit/lit/ExampleTests/LLVM.OutOfTree/src/test/Foo/dg.exp
deleted file mode 100644
index 2bda07a..0000000
--- a/utils/lit/lit/ExampleTests/LLVM.OutOfTree/src/test/Foo/dg.exp
+++ /dev/null
@@ -1,6 +0,0 @@
-load_lib llvm.exp
-
-if { [llvm_supports_target X86] } {
- RunLLVMTests [lsort [glob -nocomplain $srcdir/$subdir/*.{ll}]]
-}
-
diff --git a/utils/lit/lit/ExampleTests/LLVM.OutOfTree/src/test/lit.cfg b/utils/lit/lit/ExampleTests/LLVM.OutOfTree/src/test/lit.cfg
index 3fdd63c..533c445 100644
--- a/utils/lit/lit/ExampleTests/LLVM.OutOfTree/src/test/lit.cfg
+++ b/utils/lit/lit/ExampleTests/LLVM.OutOfTree/src/test/lit.cfg
@@ -8,11 +8,11 @@ import os
config.name = 'LLVM'
# testFormat: The test format to use to interpret tests.
-config.test_format = lit.formats.TclTest()
+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 = []
+config.suffixes = [ '.ll' ]
# test_source_root: The root path where tests are located.
config.test_source_root = os.path.dirname(__file__)
@@ -64,74 +64,3 @@ if config.test_exec_root is None:
lit.load_config(config, site_cfg)
raise SystemExit
-###
-
-# Load site data from DejaGNU's site.exp.
-import re
-site_exp = {}
-# FIXME: Implement lit.site.cfg.
-for line in open(os.path.join(config.llvm_obj_root, 'test', 'site.exp')):
- m = re.match('set ([^ ]+) "([^"]*)"', line)
- if m:
- site_exp[m.group(1)] = m.group(2)
-
-excludes = []
-
-# Provide target_triple for use in XFAIL.
-config.target_triple = site_exp['target_triplet']
-
-# Provide llvm_supports_target for use in local configs.
-targets = set(site_exp["TARGETS_TO_BUILD"].split())
-def llvm_supports_target(name):
- return name in targets
-
-# Provide on_clone hook for reading 'dg.exp'.
-import os
-simpleLibData = re.compile(r"""load_lib llvm.exp
-
-RunLLVMTests \[lsort \[glob -nocomplain \$srcdir/\$subdir/\*\.(.*)\]\]""",
- re.MULTILINE)
-conditionalLibData = re.compile(r"""load_lib llvm.exp
-
-if.*\[ ?(llvm[^ ]*) ([^ ]*) ?\].*{
- *RunLLVMTests \[lsort \[glob -nocomplain \$srcdir/\$subdir/\*\.(.*)\]\]
-\}""", re.MULTILINE)
-def on_clone(parent, cfg, for_path):
- def addSuffixes(match):
- if match[0] == '{' and match[-1] == '}':
- cfg.suffixes = ['.' + s for s in match[1:-1].split(',')]
- else:
- cfg.suffixes = ['.' + match]
-
- libPath = os.path.join(os.path.dirname(for_path),
- 'dg.exp')
- if not os.path.exists(libPath):
- cfg.unsupported = True
- return
-
- # Reset unsupported, in case we inherited it.
- cfg.unsupported = False
- lib = open(libPath).read().strip()
-
- # Check for a simple library.
- m = simpleLibData.match(lib)
- if m:
- addSuffixes(m.group(1))
- return
-
- # Check for a conditional test set.
- m = conditionalLibData.match(lib)
- if m:
- funcname,arg,match = m.groups()
- addSuffixes(match)
-
- func = globals().get(funcname)
- if not func:
- lit.error('unsupported predicate %r' % funcname)
- elif not func(arg):
- cfg.unsupported = True
- return
- # Otherwise, give up.
- lit.error('unable to understand %r:\n%s' % (libPath, lib))
-
-config.on_clone = on_clone
diff --git a/utils/lit/lit/ExampleTests/ManyTests/lit.local.cfg b/utils/lit/lit/ExampleTests/ManyTests/lit.local.cfg
new file mode 100644
index 0000000..6cc4752
--- /dev/null
+++ b/utils/lit/lit/ExampleTests/ManyTests/lit.local.cfg
@@ -0,0 +1,23 @@
+# -*- Python -*-
+
+Test = lit.Test
+
+class ManyTests(object):
+ def __init__(self, N=10000):
+ self.N = N
+
+ def getTestsInDirectory(self, testSuite, path_in_suite,
+ litConfig, localConfig):
+ for i in range(self.N):
+ test_name = 'test-%04d' % (i,)
+ yield Test.Test(testSuite, path_in_suite + (test_name,),
+ localConfig)
+
+ def execute(self, test, litConfig):
+ # Do a "non-trivial" amount of Python work.
+ sum = 0
+ for i in range(10000):
+ sum += i
+ return Test.PASS,''
+
+config.test_format = ManyTests()
diff --git a/utils/lit/lit/ExampleTests/TclTest/lit.local.cfg b/utils/lit/lit/ExampleTests/TclTest/lit.local.cfg
deleted file mode 100644
index 6a37129..0000000
--- a/utils/lit/lit/ExampleTests/TclTest/lit.local.cfg
+++ /dev/null
@@ -1,5 +0,0 @@
-# -*- Python -*-
-
-config.test_format = lit.formats.TclTest()
-
-config.suffixes = ['.ll']
diff --git a/utils/lit/lit/ExampleTests/TclTest/stderr-pipe.ll b/utils/lit/lit/ExampleTests/TclTest/stderr-pipe.ll
deleted file mode 100644
index 6c55fe8..0000000
--- a/utils/lit/lit/ExampleTests/TclTest/stderr-pipe.ll
+++ /dev/null
@@ -1 +0,0 @@
-; RUN: gcc -### > /dev/null |& grep {gcc version}
diff --git a/utils/lit/lit/ExampleTests/TclTest/tcl-redir-1.ll b/utils/lit/lit/ExampleTests/TclTest/tcl-redir-1.ll
deleted file mode 100644
index 61240ba..0000000
--- a/utils/lit/lit/ExampleTests/TclTest/tcl-redir-1.ll
+++ /dev/null
@@ -1,7 +0,0 @@
-; RUN: echo 'hi' > %t.1 | echo 'hello' > %t.2
-; RUN: not grep 'hi' %t.1
-; RUN: grep 'hello' %t.2
-
-
-
-
diff --git a/utils/lit/lit/ExampleTests/lit.cfg b/utils/lit/lit/ExampleTests/lit.cfg
index 2629918..164daba 100644
--- a/utils/lit/lit/ExampleTests/lit.cfg
+++ b/utils/lit/lit/ExampleTests/lit.cfg
@@ -19,8 +19,8 @@ config.test_source_root = None
# root).
config.test_exec_root = None
-# target_triple: Used by ShTest and TclTest formats for XFAIL checks.
+# target_triple: Used by ShTest format for XFAIL checks.
config.target_triple = 'foo'
-# available_features: Used by ShTest and TclTest formats for REQUIRES checks.
+# available_features: Used by ShTest format for REQUIRES checks.
config.available_features.add('some-feature-name')
diff --git a/utils/lit/lit/LitConfig.py b/utils/lit/lit/LitConfig.py
index 0a359a3..9bcf20b 100644
--- a/utils/lit/lit/LitConfig.py
+++ b/utils/lit/lit/LitConfig.py
@@ -12,16 +12,15 @@ class LitConfig:
import Test
# Provide access to built-in formats.
- import LitFormats as formats
+ import TestFormats as formats
# Provide access to built-in utility functions.
import Util as util
def __init__(self, progname, path, quiet,
useValgrind, valgrindLeakCheck, valgrindArgs,
- useTclAsSh,
noExecute, ignoreStdErr, debug, isWindows,
- params):
+ params, config_prefix = None):
# The name of the test runner.
self.progname = progname
# The items to add to the PATH environment variable.
@@ -30,7 +29,6 @@ class LitConfig:
self.useValgrind = bool(useValgrind)
self.valgrindLeakCheck = bool(valgrindLeakCheck)
self.valgrindUserArgs = list(valgrindArgs)
- self.useTclAsSh = bool(useTclAsSh)
self.noExecute = noExecute
self.ignoreStdErr = ignoreStdErr
self.debug = debug
@@ -38,6 +36,12 @@ class LitConfig:
self.params = dict(params)
self.bashPath = None
+ # Configuration files to look for when discovering test suites.
+ self.config_prefix = config_prefix or 'lit'
+ self.config_name = '%s.cfg' % (self.config_prefix,)
+ self.site_config_name = '%s.site.cfg' % (self.config_prefix,)
+ self.local_config_name = '%s.local.cfg' % (self.config_prefix,)
+
self.numErrors = 0
self.numWarnings = 0
@@ -80,7 +84,7 @@ class LitConfig:
break
if self.bashPath is None:
- self.warning("Unable to find 'bash', running Tcl tests internally.")
+ self.warning("Unable to find 'bash'.")
self.bashPath = ''
return self.bashPath
diff --git a/utils/lit/lit/LitFormats.py b/utils/lit/lit/LitFormats.py
deleted file mode 100644
index 931d107..0000000
--- a/utils/lit/lit/LitFormats.py
+++ /dev/null
@@ -1,3 +0,0 @@
-from TestFormats import FileBasedTest
-from TestFormats import GoogleTest, ShTest, TclTest
-from TestFormats import SyntaxCheckTest, OneCommandPerFileTest
diff --git a/utils/lit/lit/ShUtil.py b/utils/lit/lit/ShUtil.py
index dda622a..50f7910 100644
--- a/utils/lit/lit/ShUtil.py
+++ b/utils/lit/lit/ShUtil.py
@@ -35,7 +35,7 @@ class ShLexer:
if ('|' in chunk or '&' in chunk or
'<' in chunk or '>' in chunk or
"'" in chunk or '"' in chunk or
- '\\' in chunk):
+ ';' in chunk or '\\' in chunk):
return None
self.pos = self.pos - 1 + len(chunk)
@@ -48,7 +48,7 @@ class ShLexer:
str = c
while self.pos != self.end:
c = self.look()
- if c.isspace() or c in "|&":
+ if c.isspace() or c in "|&;":
break
elif c in '><':
# This is an annoying case; we treat '2>' as a single token so
@@ -129,7 +129,7 @@ class ShLexer:
lex_one_token - Lex a single 'sh' token. """
c = self.eat()
- if c in ';!':
+ if c == ';':
return (c,)
if c == '|':
if self.maybe_eat('|'):
@@ -219,9 +219,6 @@ class ShParser:
def parse_pipeline(self):
negate = False
- if self.look() == ('!',):
- self.lex()
- negate = True
commands = [self.parse_command()]
while self.look() == ('|',):
@@ -253,9 +250,9 @@ class TestShLexer(unittest.TestCase):
return list(ShLexer(str, *args, **kwargs).lex())
def test_basic(self):
- self.assertEqual(self.lex('a|b>c&d<e'),
+ self.assertEqual(self.lex('a|b>c&d<e;f'),
['a', ('|',), 'b', ('>',), 'c', ('&',), 'd',
- ('<',), 'e'])
+ ('<',), 'e', (';',), 'f'])
def test_redirection_tokens(self):
self.assertEqual(self.lex('a2>c'),
@@ -317,10 +314,6 @@ class TestShParse(unittest.TestCase):
Command(['c'], [])],
False))
- self.assertEqual(self.parse('! a'),
- Pipeline([Command(['a'], [])],
- True))
-
def test_list(self):
self.assertEqual(self.parse('a ; b'),
Seq(Pipeline([Command(['a'], [])], False),
@@ -349,5 +342,10 @@ class TestShParse(unittest.TestCase):
'||',
Pipeline([Command(['c'], [])], False)))
+ self.assertEqual(self.parse('a; b'),
+ Seq(Pipeline([Command(['a'], [])], False),
+ ';',
+ Pipeline([Command(['b'], [])], False)))
+
if __name__ == '__main__':
unittest.main()
diff --git a/utils/lit/lit/TclUtil.py b/utils/lit/lit/TclUtil.py
deleted file mode 100644
index 4a3f345..0000000
--- a/utils/lit/lit/TclUtil.py
+++ /dev/null
@@ -1,322 +0,0 @@
-import itertools
-
-from ShCommands import Command, Pipeline
-
-def tcl_preprocess(data):
- # Tcl has a preprocessing step to replace escaped newlines.
- i = data.find('\\\n')
- if i == -1:
- return data
-
- # Replace '\\\n' and subsequent whitespace by a single space.
- n = len(data)
- str = data[:i]
- i += 2
- while i < n and data[i] in ' \t':
- i += 1
- return str + ' ' + data[i:]
-
-class TclLexer:
- """TclLexer - Lex a string into "words", following the Tcl syntax."""
-
- def __init__(self, data):
- self.data = tcl_preprocess(data)
- self.pos = 0
- self.end = len(self.data)
-
- def at_end(self):
- return self.pos == self.end
-
- def eat(self):
- c = self.data[self.pos]
- self.pos += 1
- return c
-
- def look(self):
- return self.data[self.pos]
-
- def maybe_eat(self, c):
- """
- maybe_eat(c) - Consume the character c if it is the next character,
- returning True if a character was consumed. """
- if self.data[self.pos] == c:
- self.pos += 1
- return True
- return False
-
- def escape(self, c):
- if c == 'a':
- return '\x07'
- elif c == 'b':
- return '\x08'
- elif c == 'f':
- return '\x0c'
- elif c == 'n':
- return '\n'
- elif c == 'r':
- return '\r'
- elif c == 't':
- return '\t'
- elif c == 'v':
- return '\x0b'
- elif c in 'uxo':
- raise ValueError,'Invalid quoted character %r' % c
- else:
- return c
-
- def lex_braced(self):
- # Lex until whitespace or end of string, the opening brace has already
- # been consumed.
-
- str = ''
- while 1:
- if self.at_end():
- raise ValueError,"Unterminated '{' quoted word"
-
- c = self.eat()
- if c == '}':
- break
- elif c == '{':
- str += '{' + self.lex_braced() + '}'
- elif c == '\\' and self.look() in '{}':
- str += self.eat()
- else:
- str += c
-
- return str
-
- def lex_quoted(self):
- str = ''
-
- while 1:
- if self.at_end():
- raise ValueError,"Unterminated '\"' quoted word"
-
- c = self.eat()
- if c == '"':
- break
- elif c == '\\':
- if self.at_end():
- raise ValueError,'Missing quoted character'
-
- str += self.escape(self.eat())
- else:
- str += c
-
- return str
-
- def lex_unquoted(self, process_all=False):
- # Lex until whitespace or end of string.
- str = ''
- while not self.at_end():
- if not process_all:
- if self.look().isspace() or self.look() == ';':
- break
-
- c = self.eat()
- if c == '\\':
- if self.at_end():
- raise ValueError,'Missing quoted character'
-
- str += self.escape(self.eat())
- elif c == '[':
- raise NotImplementedError, ('Command substitution is '
- 'not supported')
- elif c == '$' and not self.at_end() and (self.look().isalpha() or
- self.look() == '{'):
- raise NotImplementedError, ('Variable substitution is '
- 'not supported')
- else:
- str += c
-
- return str
-
- def lex_one_token(self):
- if self.maybe_eat('"'):
- return self.lex_quoted()
- elif self.maybe_eat('{'):
- # Check for argument substitution.
- if not self.maybe_eat('*'):
- return self.lex_braced()
-
- if not self.maybe_eat('}'):
- return '*' + self.lex_braced()
-
- if self.at_end() or self.look().isspace():
- return '*'
-
- raise NotImplementedError, "Argument substitution is unsupported"
- else:
- return self.lex_unquoted()
-
- def lex(self):
- while not self.at_end():
- c = self.look()
- if c in ' \t':
- self.eat()
- elif c in ';\n':
- self.eat()
- yield (';',)
- else:
- yield self.lex_one_token()
-
-class TclExecCommand:
- kRedirectPrefixes1 = ('<', '>')
- kRedirectPrefixes2 = ('<@', '<<', '2>', '>&', '>>', '>@')
- kRedirectPrefixes3 = ('2>@', '2>>', '>>&', '>&@')
- kRedirectPrefixes4 = ('2>@1',)
-
- def __init__(self, args):
- self.args = iter(args)
-
- def lex(self):
- try:
- return self.args.next()
- except StopIteration:
- return None
-
- def look(self):
- next = self.lex()
- if next is not None:
- self.args = itertools.chain([next], self.args)
- return next
-
- def parse_redirect(self, tok, length):
- if len(tok) == length:
- arg = self.lex()
- if arg is None:
- raise ValueError,'Missing argument to %r redirection' % tok
- else:
- tok,arg = tok[:length],tok[length:]
-
- if tok[0] == '2':
- op = (tok[1:],2)
- else:
- op = (tok,)
- return (op, arg)
-
- def parse_pipeline(self):
- if self.look() is None:
- raise ValueError,"Expected at least one argument to exec"
-
- commands = [Command([],[])]
- while 1:
- arg = self.lex()
- if arg is None:
- break
- elif arg == '|':
- commands.append(Command([],[]))
- elif arg == '|&':
- # Write this as a redirect of stderr; it must come first because
- # stdout may have already been redirected.
- commands[-1].redirects.insert(0, (('>&',2),'1'))
- commands.append(Command([],[]))
- elif arg[:4] in TclExecCommand.kRedirectPrefixes4:
- commands[-1].redirects.append(self.parse_redirect(arg, 4))
- elif arg[:3] in TclExecCommand.kRedirectPrefixes3:
- commands[-1].redirects.append(self.parse_redirect(arg, 3))
- elif arg[:2] in TclExecCommand.kRedirectPrefixes2:
- commands[-1].redirects.append(self.parse_redirect(arg, 2))
- elif arg[:1] in TclExecCommand.kRedirectPrefixes1:
- commands[-1].redirects.append(self.parse_redirect(arg, 1))
- else:
- commands[-1].args.append(arg)
-
- return Pipeline(commands, False, pipe_err=True)
-
- def parse(self):
- ignoreStderr = False
- keepNewline = False
-
- # Parse arguments.
- while 1:
- next = self.look()
- if not isinstance(next, str) or next[0] != '-':
- break
-
- if next == '--':
- self.lex()
- break
- elif next == '-ignorestderr':
- ignoreStderr = True
- elif next == '-keepnewline':
- keepNewline = True
- else:
- raise ValueError,"Invalid exec argument %r" % next
-
- return (ignoreStderr, keepNewline, self.parse_pipeline())
-
-###
-
-import unittest
-
-class TestTclLexer(unittest.TestCase):
- def lex(self, str, *args, **kwargs):
- return list(TclLexer(str, *args, **kwargs).lex())
-
- def test_preprocess(self):
- self.assertEqual(tcl_preprocess('a b'), 'a b')
- self.assertEqual(tcl_preprocess('a\\\nb c'), 'a b c')
-
- def test_unquoted(self):
- self.assertEqual(self.lex('a b c'),
- ['a', 'b', 'c'])
- self.assertEqual(self.lex(r'a\nb\tc\ '),
- ['a\nb\tc '])
- self.assertEqual(self.lex(r'a \\\$b c $\\'),
- ['a', r'\$b', 'c', '$\\'])
-
- def test_braced(self):
- self.assertEqual(self.lex('a {b c} {}'),
- ['a', 'b c', ''])
- self.assertEqual(self.lex(r'a {b {c\n}}'),
- ['a', 'b {c\\n}'])
- self.assertEqual(self.lex(r'a {b\{}'),
- ['a', 'b{'])
- self.assertEqual(self.lex(r'{*}'), ['*'])
- self.assertEqual(self.lex(r'{*} a'), ['*', 'a'])
- self.assertEqual(self.lex(r'{*} a'), ['*', 'a'])
- self.assertEqual(self.lex('{a\\\n b}'),
- ['a b'])
-
- def test_quoted(self):
- self.assertEqual(self.lex('a "b c"'),
- ['a', 'b c'])
-
- def test_terminators(self):
- self.assertEqual(self.lex('a\nb'),
- ['a', (';',), 'b'])
- self.assertEqual(self.lex('a;b'),
- ['a', (';',), 'b'])
- self.assertEqual(self.lex('a ; b'),
- ['a', (';',), 'b'])
-
-class TestTclExecCommand(unittest.TestCase):
- def parse(self, str):
- return TclExecCommand(list(TclLexer(str).lex())).parse()
-
- def test_basic(self):
- self.assertEqual(self.parse('echo hello'),
- (False, False,
- Pipeline([Command(['echo', 'hello'], [])],
- False, True)))
- self.assertEqual(self.parse('echo hello | grep hello'),
- (False, False,
- Pipeline([Command(['echo', 'hello'], []),
- Command(['grep', 'hello'], [])],
- False, True)))
-
- def test_redirect(self):
- self.assertEqual(self.parse('echo hello > a >b >>c 2> d |& e'),
- (False, False,
- Pipeline([Command(['echo', 'hello'],
- [(('>&',2),'1'),
- (('>',),'a'),
- (('>',),'b'),
- (('>>',),'c'),
- (('>',2),'d')]),
- Command(['e'], [])],
- False, True)))
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/utils/lit/lit/Test.py b/utils/lit/lit/Test.py
index db2e032..9471e3a 100644
--- a/utils/lit/lit/Test.py
+++ b/utils/lit/lit/Test.py
@@ -7,6 +7,10 @@ class TestResult:
self.name = name
self.isFailure = isFailure
+ def __repr__(self):
+ return '%s%r' % (self.__class__.__name__,
+ (self.name, self.isFailure))
+
PASS = TestResult('PASS', False)
XFAIL = TestResult('XFAIL', False)
FAIL = TestResult('FAIL', True)
diff --git a/utils/lit/lit/TestFormats.py b/utils/lit/lit/TestFormats.py
index d1c0558..26541f1 100644
--- a/utils/lit/lit/TestFormats.py
+++ b/utils/lit/lit/TestFormats.py
@@ -54,28 +54,36 @@ class GoogleTest(object):
else:
yield ''.join(nested_tests) + ln
+ 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 + (dirname, basename, testname)
+ yield 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):
- # Check for the one subdirectory (build directory) tests will be in.
- if not '.' in self.test_sub_dir:
+ 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
-
- filepath = os.path.join(source_path, filename)
- if not os.path.isdir(filepath):
- continue
-
- for subfilename in os.listdir(filepath):
- if subfilename.endswith(self.test_suffix):
+ for subfilename in os.listdir(filepath):
execpath = os.path.join(filepath, subfilename)
-
- # Discover the tests in this executable.
- for name in self.getGTestTests(execpath, litConfig,
- localConfig):
- testPath = path_in_suite + (filename, subfilename, name)
- yield Test.Test(testSuite, testPath, localConfig)
+ for test in self.getTestsInExecutable(
+ testSuite, path_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())
@@ -89,6 +97,9 @@ class GoogleTest(object):
if litConfig.useValgrind:
cmd = litConfig.valgrindArgs + cmd
+ if litConfig.noExecute:
+ return Test.PASS, ''
+
out, err, exitCode = TestRunner.executeCommand(
cmd, env=test.config.environment)
@@ -124,14 +135,6 @@ class ShTest(FileBasedTest):
return TestRunner.executeShTest(test, litConfig,
self.execute_external)
-class TclTest(FileBasedTest):
- def __init__(self, ignoreStdErr=False):
- self.ignoreStdErr = ignoreStdErr
-
- def execute(self, test, litConfig):
- litConfig.ignoreStdErr = self.ignoreStdErr
- return TestRunner.executeTclTest(test, litConfig)
-
###
import re
@@ -221,12 +224,3 @@ class OneCommandPerFileTest:
report += """Output:\n--\n%s--""" % diags
return Test.FAIL, report
-
-class SyntaxCheckTest(OneCommandPerFileTest):
- def __init__(self, compiler, dir, extra_cxx_args=[], *args, **kwargs):
- cmd = [compiler, '-x', 'c++', '-fsyntax-only'] + extra_cxx_args
- OneCommandPerFileTest.__init__(self, cmd, dir,
- useTempInput=1, *args, **kwargs)
-
- def createTempInput(self, tmp, test):
- print >>tmp, '#include "%s"' % test.source_path
diff --git a/utils/lit/lit/TestRunner.py b/utils/lit/lit/TestRunner.py
index 0c1911e..8417699 100644
--- a/utils/lit/lit/TestRunner.py
+++ b/utils/lit/lit/TestRunner.py
@@ -49,13 +49,14 @@ def executeShCmd(cmd, cfg, cwd, results):
return executeShCmd(cmd.rhs, cfg, cwd, results)
if cmd.op == '&':
- raise NotImplementedError,"unsupported test command: '&'"
+ raise InternalShellError(cmd,"unsupported shell operator: '&'")
if cmd.op == '||':
res = executeShCmd(cmd.lhs, cfg, cwd, results)
if res != 0:
res = executeShCmd(cmd.rhs, cfg, cwd, results)
return res
+
if cmd.op == '&&':
res = executeShCmd(cmd.lhs, cfg, cwd, results)
if res is None:
@@ -77,7 +78,7 @@ def executeShCmd(cmd, cfg, cwd, results):
# output. This is null until we have seen some output using
# stderr.
for i,j in enumerate(cmd.commands):
- # Apply the redirections, we use (N,) as a sentinal to indicate stdin,
+ # Apply the redirections, we use (N,) as a sentinel to indicate stdin,
# stdout, stderr for N equal to 0, 1, or 2 respectively. Redirects to or
# from a file are represented with a list [file, mode, file-object]
# where file-object is initially None.
@@ -98,7 +99,7 @@ def executeShCmd(cmd, cfg, cwd, results):
elif r[0] == ('<',):
redirects[0] = [r[1], 'r', None]
else:
- raise NotImplementedError,"Unsupported redirect: %r" % (r,)
+ raise InternalShellError(j,"Unsupported redirect: %r" % (r,))
# Map from the final redirections to something subprocess can handle.
final_redirects = []
@@ -107,14 +108,14 @@ def executeShCmd(cmd, cfg, cwd, results):
result = input
elif r == (1,):
if index == 0:
- raise NotImplementedError,"Unsupported redirect for stdin"
+ raise InternalShellError(j,"Unsupported redirect for stdin")
elif index == 1:
result = subprocess.PIPE
else:
result = subprocess.STDOUT
elif r == (2,):
if index != 2:
- raise NotImplementedError,"Unsupported redirect on stdout"
+ raise InternalShellError(j,"Unsupported redirect on stdout")
result = subprocess.PIPE
else:
if r[2] is None:
@@ -241,98 +242,26 @@ def executeShCmd(cmd, cfg, cwd, results):
return exitCode
def executeScriptInternal(test, litConfig, tmpBase, commands, cwd):
- ln = ' &&\n'.join(commands)
- try:
- cmd = ShUtil.ShParser(ln, litConfig.isWindows).parse()
- except:
- return (Test.FAIL, "shell parser error on: %r" % ln)
-
- results = []
- try:
- exitCode = executeShCmd(cmd, test.config, cwd, results)
- except InternalShellError,e:
- out = ''
- err = e.message
- exitCode = 255
-
- out = err = ''
- for i,(cmd, cmd_out,cmd_err,res) in enumerate(results):
- out += 'Command %d: %s\n' % (i, ' '.join('"%s"' % s for s in cmd.args))
- out += 'Command %d Result: %r\n' % (i, res)
- out += 'Command %d Output:\n%s\n\n' % (i, cmd_out)
- out += 'Command %d Stderr:\n%s\n\n' % (i, cmd_err)
-
- return out, err, exitCode
-
-def executeTclScriptInternal(test, litConfig, tmpBase, commands, cwd):
- import TclUtil
cmds = []
for ln in commands:
- # Given the unfortunate way LLVM's test are written, the line gets
- # backslash substitution done twice.
- ln = TclUtil.TclLexer(ln).lex_unquoted(process_all = True)
-
try:
- tokens = list(TclUtil.TclLexer(ln).lex())
+ cmds.append(ShUtil.ShParser(ln, litConfig.isWindows).parse())
except:
- return (Test.FAIL, "Tcl lexer error on: %r" % ln)
-
- # Validate there are no control tokens.
- for t in tokens:
- if not isinstance(t, str):
- return (Test.FAIL,
- "Invalid test line: %r containing %r" % (ln, t))
-
- try:
- cmds.append(TclUtil.TclExecCommand(tokens).parse_pipeline())
- except:
- return (Test.FAIL, "Tcl 'exec' parse error on: %r" % ln)
-
- if litConfig.useValgrind:
- for pipeline in cmds:
- if pipeline.commands:
- # Only valgrind the first command in each pipeline, to avoid
- # valgrinding things like grep, not, and FileCheck.
- cmd = pipeline.commands[0]
- cmd.args = litConfig.valgrindArgs + cmd.args
+ return (Test.FAIL, "shell parser error on: %r" % ln)
cmd = cmds[0]
for c in cmds[1:]:
cmd = ShUtil.Seq(cmd, '&&', c)
- # FIXME: This is lame, we shouldn't need bash. See PR5240.
- bashPath = litConfig.getBashPath()
- if litConfig.useTclAsSh and bashPath:
- script = tmpBase + '.script'
-
- # Write script file
- f = open(script,'w')
- print >>f, 'set -o pipefail'
- cmd.toShell(f, pipefail = True)
- f.close()
-
- if 0:
- print >>sys.stdout, cmd
- print >>sys.stdout, open(script).read()
- print >>sys.stdout
- return '', '', 0
-
- command = [litConfig.getBashPath(), script]
- out,err,exitCode = executeCommand(command, cwd=cwd,
- env=test.config.environment)
-
- return out,err,exitCode
- else:
- results = []
- try:
- exitCode = executeShCmd(cmd, test.config, cwd, results)
- except InternalShellError,e:
- results.append((e.command, '', e.message + '\n', 255))
- exitCode = 255
+ results = []
+ try:
+ exitCode = executeShCmd(cmd, test.config, cwd, results)
+ except InternalShellError,e:
+ exitCode = 127
+ results.append((e.command, '', e.message, exitCode))
out = err = ''
-
- for i,(cmd, cmd_out, cmd_err, res) in enumerate(results):
+ for i,(cmd, cmd_out,cmd_err,res) in enumerate(results):
out += 'Command %d: %s\n' % (i, ' '.join('"%s"' % s for s in cmd.args))
out += 'Command %d Result: %r\n' % (i, res)
out += 'Command %d Output:\n%s\n\n' % (i, cmd_out)
@@ -348,11 +277,14 @@ def executeScript(test, litConfig, tmpBase, commands, cwd):
script += '.bat'
# Write script file
- f = open(script,'w')
+ mode = 'w'
+ if litConfig.isWindows and not isWin32CMDEXE:
+ mode += 'b' # Avoid CRLFs when writing bash scripts.
+ f = open(script, mode)
if isWin32CMDEXE:
f.write('\nif %ERRORLEVEL% NEQ 0 EXIT\n'.join(commands))
else:
- f.write(' &&\n'.join(commands))
+ f.write('{ ' + '; } &&\n{ '.join(commands) + '; }')
f.write('\n')
f.close()
@@ -424,15 +356,15 @@ def parseIntegratedTestScript(test, normalize_slashes=False,
('%{pathsep}', os.pathsep),
('%t', tmpBase + '.tmp'),
('%T', tmpDir),
- # FIXME: Remove this once we kill DejaGNU.
- ('%abs_tmp', tmpBase + '.tmp'),
('#_MARKER_#', '%')])
# 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:')
@@ -441,6 +373,15 @@ def parseIntegratedTestScript(test, normalize_slashes=False,
# Trim trailing whitespace.
ln = ln.rstrip()
+ # Substitute line number expressions
+ ln = re.sub('%\(line\)', str(line_number), ln)
+ def replace_line_number(match):
+ if match.group(1) == '+':
+ return str(line_number + int(match.group(2)))
+ if match.group(1) == '-':
+ return str(line_number - int(match.group(2)))
+ ln = re.sub('%\(line *([\+-]) *(\d+)\)', replace_line_number, ln)
+
# Collapse lines with trailing '\\'.
if script and script[-1][-1] == '\\':
script[-1] = script[-1][:-1] + ln
@@ -490,17 +431,14 @@ def parseIntegratedTestScript(test, normalize_slashes=False,
isXFail = isExpectedFail(test, xfails)
return script,isXFail,tmpBase,execdir
-def formatTestOutput(status, out, err, exitCode, failDueToStderr, script):
+def formatTestOutput(status, out, err, exitCode, script):
output = StringIO.StringIO()
print >>output, "Script:"
print >>output, "--"
print >>output, '\n'.join(script)
print >>output, "--"
print >>output, "Exit Code: %r" % exitCode,
- if failDueToStderr:
- print >>output, "(but there was output on stderr)"
- else:
- print >>output
+ print >>output
if out:
print >>output, "Command Output (stdout):"
print >>output, "--"
@@ -513,53 +451,6 @@ def formatTestOutput(status, out, err, exitCode, failDueToStderr, script):
print >>output, "--"
return (status, output.getvalue())
-def executeTclTest(test, litConfig):
- if test.config.unsupported:
- return (Test.UNSUPPORTED, 'Test is unsupported')
-
- # Parse the test script, normalizing slashes in substitutions on Windows
- # (since otherwise Tcl style lexing will treat them as escapes).
- res = parseIntegratedTestScript(test, normalize_slashes=kIsWindows)
- if len(res) == 2:
- return res
-
- script, isXFail, tmpBase, execdir = res
-
- if litConfig.noExecute:
- return (Test.PASS, '')
-
- # Create the output directory if it does not already exist.
- Util.mkdir_p(os.path.dirname(tmpBase))
-
- res = executeTclScriptInternal(test, litConfig, tmpBase, script, execdir)
- if len(res) == 2:
- return res
-
- # Test for failure. In addition to the exit code, Tcl commands are
- # considered to fail if there is any standard error output.
- out,err,exitCode = res
- if isXFail:
- ok = exitCode != 0 or err and not litConfig.ignoreStdErr
- if ok:
- status = Test.XFAIL
- else:
- status = Test.XPASS
- else:
- ok = exitCode == 0 and (not err or litConfig.ignoreStdErr)
- if ok:
- status = Test.PASS
- else:
- status = Test.FAIL
-
- if ok:
- return (status,'')
-
- # Set a flag for formatTestOutput so it can explain why the test was
- # considered to have failed, despite having an exit code of 0.
- failDueToStderr = exitCode == 0 and err and not litConfig.ignoreStdErr
-
- return formatTestOutput(status, out, err, exitCode, failDueToStderr, script)
-
def executeShTest(test, litConfig, useExternalSh,
extra_substitutions=[]):
if test.config.unsupported:
@@ -601,7 +492,4 @@ def executeShTest(test, litConfig, useExternalSh,
if ok:
return (status,'')
- # Sh tests are not considered to fail just from stderr output.
- failDueToStderr = False
-
- return formatTestOutput(status, out, err, exitCode, failDueToStderr, script)
+ return formatTestOutput(status, out, err, exitCode, script)
diff --git a/utils/lit/lit/__init__.py b/utils/lit/lit/__init__.py
index f3fbb1c..3e61bbd 100644
--- a/utils/lit/lit/__init__.py
+++ b/utils/lit/lit/__init__.py
@@ -4,7 +4,7 @@ from main import main
__author__ = 'Daniel Dunbar'
__email__ = 'daniel@zuster.org'
-__versioninfo__ = (0, 2, 0)
+__versioninfo__ = (0, 3, 0)
__version__ = '.'.join(map(str, __versioninfo__)) + 'dev'
__all__ = []
diff --git a/utils/lit/lit/discovery.py b/utils/lit/lit/discovery.py
new file mode 100644
index 0000000..c869a67
--- /dev/null
+++ b/utils/lit/lit/discovery.py
@@ -0,0 +1,234 @@
+"""
+Test discovery functions.
+"""
+
+import os
+import sys
+
+from lit.TestingConfig import TestingConfig
+from lit import LitConfig, Test
+
+def dirContainsTestSuite(path, lit_config):
+ cfgpath = os.path.join(path, lit_config.site_config_name)
+ if os.path.exists(cfgpath):
+ return cfgpath
+ cfgpath = os.path.join(path, lit_config.config_name)
+ if os.path.exists(cfgpath):
+ return cfgpath
+
+def getTestSuite(item, litConfig, cache):
+ """getTestSuite(item, litConfig, cache) -> (suite, relative_path)
+
+ Find the test suite containing @arg item.
+
+ @retval (None, ...) - Indicates no test suite contains @arg item.
+ @retval (suite, relative_path) - The suite that @arg item is in, and its
+ relative path inside that suite.
+ """
+ def search1(path):
+ # Check for a site config or a lit config.
+ cfgpath = dirContainsTestSuite(path, litConfig)
+
+ # If we didn't find a config file, keep looking.
+ if not cfgpath:
+ parent,base = os.path.split(path)
+ if parent == path:
+ return (None, ())
+
+ ts, relative = search(parent)
+ return (ts, relative + (base,))
+
+ # We found a config file, load it.
+ if litConfig.debug:
+ litConfig.note('loading suite config %r' % cfgpath)
+
+ cfg = TestingConfig.frompath(cfgpath, None, litConfig, mustExist = True)
+ 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), ()
+
+ def search(path):
+ # Check for an already instantiated test suite.
+ res = cache.get(path)
+ if res is None:
+ cache[path] = res = search1(path)
+ return res
+
+ # Canonicalize the path.
+ item = os.path.realpath(item)
+
+ # Skip files and virtual components.
+ components = []
+ while not os.path.isdir(item):
+ parent,base = os.path.split(item)
+ if parent == item:
+ return (None, ())
+ components.append(base)
+ item = parent
+ components.reverse()
+
+ ts, relative = search(item)
+ return ts, tuple(relative + tuple(components))
+
+def getLocalConfig(ts, path_in_suite, litConfig, cache):
+ def search1(path_in_suite):
+ # Get the parent config.
+ if not path_in_suite:
+ parent = ts.config
+ else:
+ parent = search(path_in_suite[:-1])
+
+ # Load the local configuration.
+ source_path = ts.getSourcePath(path_in_suite)
+ cfgpath = os.path.join(source_path, litConfig.local_config_name)
+ if litConfig.debug:
+ litConfig.note('loading local config %r' % cfgpath)
+ return TestingConfig.frompath(cfgpath, parent, litConfig,
+ mustExist = False,
+ config = parent.clone(cfgpath))
+
+ def search(path_in_suite):
+ key = (ts, path_in_suite)
+ res = cache.get(key)
+ if res is None:
+ cache[key] = res = search1(path_in_suite)
+ return res
+
+ return search(path_in_suite)
+
+def getTests(path, litConfig, testSuiteCache, localConfigCache):
+ # Find the test suite for this input and its relative path.
+ ts,path_in_suite = getTestSuite(path, litConfig, testSuiteCache)
+ if ts is None:
+ litConfig.warning('unable to find test suite for %r' % path)
+ return (),()
+
+ if litConfig.debug:
+ litConfig.note('resolved input %r to %r::%r' % (path, ts.name,
+ path_in_suite))
+
+ return ts, getTestsInSuite(ts, path_in_suite, litConfig,
+ testSuiteCache, localConfigCache)
+
+def getTestsInSuite(ts, path_in_suite, litConfig,
+ testSuiteCache, localConfigCache):
+ # Check that the source path exists (errors here are reported by the
+ # caller).
+ source_path = ts.getSourcePath(path_in_suite)
+ if not os.path.exists(source_path):
+ return
+
+ # Check if the user named a test directly.
+ if not os.path.isdir(source_path):
+ lc = getLocalConfig(ts, path_in_suite[:-1], litConfig, localConfigCache)
+ yield Test.Test(ts, path_in_suite, lc)
+ return
+
+ # Otherwise we have a directory to search for tests, start by getting the
+ # local configuration.
+ lc = getLocalConfig(ts, path_in_suite, litConfig, localConfigCache)
+
+ # Search for tests.
+ if lc.test_format is not None:
+ for res in lc.test_format.getTestsInDirectory(ts, path_in_suite,
+ litConfig, lc):
+ yield res
+
+ # Search subdirectories.
+ for filename in os.listdir(source_path):
+ # FIXME: This doesn't belong here?
+ if filename in ('Output', '.svn') or filename in lc.excludes:
+ continue
+
+ # Ignore non-directories.
+ file_sourcepath = os.path.join(source_path, filename)
+ if not os.path.isdir(file_sourcepath):
+ continue
+
+ # Check for nested test suites, first in the execpath in case there is a
+ # site configuration and then in the source path.
+ file_execpath = ts.getExecPath(path_in_suite + (filename,))
+ if dirContainsTestSuite(file_execpath, litConfig):
+ sub_ts, subiter = getTests(file_execpath, litConfig,
+ testSuiteCache, localConfigCache)
+ elif dirContainsTestSuite(file_sourcepath, litConfig):
+ sub_ts, subiter = getTests(file_sourcepath, litConfig,
+ testSuiteCache, localConfigCache)
+ else:
+ # Otherwise, continue loading from inside this test suite.
+ subiter = getTestsInSuite(ts, path_in_suite + (filename,),
+ litConfig, testSuiteCache,
+ localConfigCache)
+ sub_ts = None
+
+ N = 0
+ for res in subiter:
+ N += 1
+ yield res
+ if sub_ts and not N:
+ litConfig.warning('test suite %r contained no tests' % sub_ts.name)
+
+def find_tests_for_inputs(lit_config, inputs):
+ """
+ find_tests_for_inputs(lit_config, inputs) -> [Test]
+
+ Given a configuration object and a list of input specifiers, find all the
+ tests to execute.
+ """
+
+ # Expand '@...' form in inputs.
+ actual_inputs = []
+ for input in inputs:
+ if os.path.exists(input) or not input.startswith('@'):
+ actual_inputs.append(input)
+ else:
+ f = open(input[1:])
+ try:
+ for ln in f:
+ ln = ln.strip()
+ if ln:
+ actual_inputs.append(ln)
+ finally:
+ f.close()
+
+ # Load the tests from the inputs.
+ tests = []
+ test_suite_cache = {}
+ local_config_cache = {}
+ for input in actual_inputs:
+ prev = len(tests)
+ tests.extend(getTests(input, lit_config,
+ test_suite_cache, local_config_cache)[1])
+ if prev == len(tests):
+ lit_config.warning('input %r contained no tests' % input)
+
+ # If there were any errors during test discovery, exit now.
+ if lit_config.numErrors:
+ print >>sys.stderr, '%d errors, exiting.' % lit_config.numErrors
+ sys.exit(2)
+
+ return tests
+
+def load_test_suite(inputs):
+ import platform
+ import unittest
+ from lit.LitTestCase import LitTestCase
+
+ # Create the global config object.
+ litConfig = LitConfig.LitConfig(progname = 'lit',
+ path = [],
+ quiet = False,
+ useValgrind = False,
+ valgrindLeakCheck = False,
+ valgrindArgs = [],
+ noExecute = False,
+ ignoreStdErr = False,
+ debug = False,
+ isWindows = (platform.system()=='Windows'),
+ params = {})
+
+ tests = 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])
+
diff --git a/utils/lit/lit/main.py b/utils/lit/lit/main.py
index 25bbcbd..da961ee 100755
--- a/utils/lit/lit/main.py
+++ b/utils/lit/lit/main.py
@@ -12,18 +12,10 @@ import ProgressBar
import TestRunner
import Util
-from TestingConfig import TestingConfig
import LitConfig
import Test
-# Configuration files to look for when discovering test suites. These can be
-# overridden with --config-prefix.
-#
-# FIXME: Rename to 'config.lit', 'site.lit', and 'local.lit' ?
-gConfigName = 'lit.cfg'
-gSiteConfigName = 'lit.site.cfg'
-
-kLocalConfigName = 'lit.local.cfg'
+import lit.discovery
class TestingProgressDisplay:
def __init__(self, opts, numTests, progressBar=None):
@@ -137,166 +129,6 @@ class Tester(threading.Thread):
test.setResult(result, output, elapsed)
self.display.update(test)
-def dirContainsTestSuite(path):
- cfgpath = os.path.join(path, gSiteConfigName)
- if os.path.exists(cfgpath):
- return cfgpath
- cfgpath = os.path.join(path, gConfigName)
- if os.path.exists(cfgpath):
- return cfgpath
-
-def getTestSuite(item, litConfig, cache):
- """getTestSuite(item, litConfig, cache) -> (suite, relative_path)
-
- Find the test suite containing @arg item.
-
- @retval (None, ...) - Indicates no test suite contains @arg item.
- @retval (suite, relative_path) - The suite that @arg item is in, and its
- relative path inside that suite.
- """
- def search1(path):
- # Check for a site config or a lit config.
- cfgpath = dirContainsTestSuite(path)
-
- # If we didn't find a config file, keep looking.
- if not cfgpath:
- parent,base = os.path.split(path)
- if parent == path:
- return (None, ())
-
- ts, relative = search(parent)
- return (ts, relative + (base,))
-
- # We found a config file, load it.
- if litConfig.debug:
- litConfig.note('loading suite config %r' % cfgpath)
-
- cfg = TestingConfig.frompath(cfgpath, None, litConfig, mustExist = True)
- 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), ()
-
- def search(path):
- # Check for an already instantiated test suite.
- res = cache.get(path)
- if res is None:
- cache[path] = res = search1(path)
- return res
-
- # Canonicalize the path.
- item = os.path.realpath(item)
-
- # Skip files and virtual components.
- components = []
- while not os.path.isdir(item):
- parent,base = os.path.split(item)
- if parent == item:
- return (None, ())
- components.append(base)
- item = parent
- components.reverse()
-
- ts, relative = search(item)
- return ts, tuple(relative + tuple(components))
-
-def getLocalConfig(ts, path_in_suite, litConfig, cache):
- def search1(path_in_suite):
- # Get the parent config.
- if not path_in_suite:
- parent = ts.config
- else:
- parent = search(path_in_suite[:-1])
-
- # Load the local configuration.
- source_path = ts.getSourcePath(path_in_suite)
- cfgpath = os.path.join(source_path, kLocalConfigName)
- if litConfig.debug:
- litConfig.note('loading local config %r' % cfgpath)
- return TestingConfig.frompath(cfgpath, parent, litConfig,
- mustExist = False,
- config = parent.clone(cfgpath))
-
- def search(path_in_suite):
- key = (ts, path_in_suite)
- res = cache.get(key)
- if res is None:
- cache[key] = res = search1(path_in_suite)
- return res
-
- return search(path_in_suite)
-
-def getTests(path, litConfig, testSuiteCache, localConfigCache):
- # Find the test suite for this input and its relative path.
- ts,path_in_suite = getTestSuite(path, litConfig, testSuiteCache)
- if ts is None:
- litConfig.warning('unable to find test suite for %r' % path)
- return (),()
-
- if litConfig.debug:
- litConfig.note('resolved input %r to %r::%r' % (path, ts.name,
- path_in_suite))
-
- return ts, getTestsInSuite(ts, path_in_suite, litConfig,
- testSuiteCache, localConfigCache)
-
-def getTestsInSuite(ts, path_in_suite, litConfig,
- testSuiteCache, localConfigCache):
- # Check that the source path exists (errors here are reported by the
- # caller).
- source_path = ts.getSourcePath(path_in_suite)
- if not os.path.exists(source_path):
- return
-
- # Check if the user named a test directly.
- if not os.path.isdir(source_path):
- lc = getLocalConfig(ts, path_in_suite[:-1], litConfig, localConfigCache)
- yield Test.Test(ts, path_in_suite, lc)
- return
-
- # Otherwise we have a directory to search for tests, start by getting the
- # local configuration.
- lc = getLocalConfig(ts, path_in_suite, litConfig, localConfigCache)
-
- # Search for tests.
- if lc.test_format is not None:
- for res in lc.test_format.getTestsInDirectory(ts, path_in_suite,
- litConfig, lc):
- yield res
-
- # Search subdirectories.
- for filename in os.listdir(source_path):
- # FIXME: This doesn't belong here?
- if filename in ('Output', '.svn') or filename in lc.excludes:
- continue
-
- # Ignore non-directories.
- file_sourcepath = os.path.join(source_path, filename)
- if not os.path.isdir(file_sourcepath):
- continue
-
- # Check for nested test suites, first in the execpath in case there is a
- # site configuration and then in the source path.
- file_execpath = ts.getExecPath(path_in_suite + (filename,))
- if dirContainsTestSuite(file_execpath):
- sub_ts, subiter = getTests(file_execpath, litConfig,
- testSuiteCache, localConfigCache)
- elif dirContainsTestSuite(file_sourcepath):
- sub_ts, subiter = getTests(file_sourcepath, litConfig,
- testSuiteCache, localConfigCache)
- else:
- # Otherwise, continue loading from inside this test suite.
- subiter = getTestsInSuite(ts, path_in_suite + (filename,),
- litConfig, testSuiteCache,
- localConfigCache)
- sub_ts = None
-
- N = 0
- for res in subiter:
- N += 1
- yield res
- if sub_ts and not N:
- litConfig.warning('test suite %r contained no tests' % sub_ts.name)
-
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.
@@ -316,50 +148,8 @@ def runTests(numThreads, litConfig, provider, display):
except KeyboardInterrupt:
sys.exit(2)
-def load_test_suite(inputs):
- import unittest
-
- # Create the global config object.
- litConfig = LitConfig.LitConfig(progname = 'lit',
- path = [],
- quiet = False,
- useValgrind = False,
- valgrindLeakCheck = False,
- valgrindArgs = [],
- useTclAsSh = False,
- noExecute = False,
- ignoreStdErr = False,
- debug = False,
- isWindows = (platform.system()=='Windows'),
- params = {})
-
- # Load the tests from the inputs.
- tests = []
- testSuiteCache = {}
- localConfigCache = {}
- for input in inputs:
- prev = len(tests)
- tests.extend(getTests(input, litConfig,
- testSuiteCache, localConfigCache)[1])
- if prev == len(tests):
- litConfig.warning('input %r contained no tests' % input)
-
- # If there were any errors during test discovery, exit now.
- if litConfig.numErrors:
- print >>sys.stderr, '%d errors, exiting.' % litConfig.numErrors
- sys.exit(2)
-
- # Return a unittest test suite which just runs the tests in order.
- def get_test_fn(test):
- return unittest.FunctionTestCase(
- lambda: test.config.test_format.execute(
- test, litConfig),
- description = test.getFullName())
-
- from LitTestCase import LitTestCase
- return unittest.TestSuite([LitTestCase(test, litConfig) for test in tests])
-
-def main(builtinParameters = {}): # Bump the GIL check interval, its more important to get any one thread to a
+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.
@@ -442,9 +232,6 @@ def main(builtinParameters = {}): # Bump the GIL check interval, its more imp
group.add_option("", "--show-suites", dest="showSuites",
help="Show discovered test suites",
action="store_true", default=False)
- group.add_option("", "--no-tcl-as-sh", dest="useTclAsSh",
- help="Don't run Tcl scripts using 'sh'",
- action="store_false", default=True)
group.add_option("", "--repeat", dest="repeatTests", metavar="N",
help="Repeat tests N times (for timing)",
action="store", default=None, type=int)
@@ -455,12 +242,6 @@ def main(builtinParameters = {}): # Bump the GIL check interval, its more imp
if not args:
parser.error('No inputs specified')
- if opts.configPrefix is not None:
- global gConfigName, gSiteConfigName, kLocalConfigName
- gConfigName = '%s.cfg' % opts.configPrefix
- gSiteConfigName = '%s.site.cfg' % opts.configPrefix
- kLocalConfigName = '%s.local.cfg' % opts.configPrefix
-
if opts.numThreads is None:
# Python <2.5 has a race condition causing lit to always fail with numThreads>1
# http://bugs.python.org/issue1731717
@@ -489,50 +270,20 @@ def main(builtinParameters = {}): # Bump the GIL check interval, its more imp
useValgrind = opts.useValgrind,
valgrindLeakCheck = opts.valgrindLeakCheck,
valgrindArgs = opts.valgrindArgs,
- useTclAsSh = opts.useTclAsSh,
noExecute = opts.noExecute,
ignoreStdErr = False,
debug = opts.debug,
isWindows = (platform.system()=='Windows'),
- params = userParams)
+ params = userParams,
+ config_prefix = opts.configPrefix)
- # Expand '@...' form in inputs.
- actual_inputs = []
- for input in inputs:
- if os.path.exists(input) or not input.startswith('@'):
- actual_inputs.append(input)
- else:
- f = open(input[1:])
- try:
- for ln in f:
- ln = ln.strip()
- if ln:
- actual_inputs.append(ln)
- finally:
- f.close()
-
-
- # Load the tests from the inputs.
- tests = []
- testSuiteCache = {}
- localConfigCache = {}
- for input in actual_inputs:
- prev = len(tests)
- tests.extend(getTests(input, litConfig,
- testSuiteCache, localConfigCache)[1])
- if prev == len(tests):
- litConfig.warning('input %r contained no tests' % input)
-
- # If there were any errors during test discovery, exit now.
- if litConfig.numErrors:
- print >>sys.stderr, '%d errors, exiting.' % litConfig.numErrors
- sys.exit(2)
+ tests = lit.discovery.find_tests_for_inputs(litConfig, inputs)
if opts.showSuites:
- suitesAndTests = dict([(ts,[])
- for ts,_ in testSuiteCache.values()
- if ts])
+ suitesAndTests = {}
for t in tests:
+ if t.suite not in suitesAndTests:
+ suitesAndTests[t.suite] = []
suitesAndTests[t.suite].append(t)
print '-- Test Suites --'
diff --git a/utils/lit/tests/.coveragerc b/utils/lit/tests/.coveragerc
new file mode 100644
index 0000000..c886d0a
--- /dev/null
+++ b/utils/lit/tests/.coveragerc
@@ -0,0 +1,11 @@
+# .coveragerc to control coverage.py
+[run]
+branch = False
+parallel = True
+source = lit
+
+[html]
+directory = coverage_html_report
+
+[report]
+omit = Inputs
diff --git a/utils/lit/tests/Inputs/discovery/lit.cfg b/utils/lit/tests/Inputs/discovery/lit.cfg
new file mode 100644
index 0000000..3513bff
--- /dev/null
+++ b/utils/lit/tests/Inputs/discovery/lit.cfg
@@ -0,0 +1,5 @@
+config.name = 'top-level-suite'
+config.suffixes = ['.txt']
+config.test_format = lit.formats.ShTest()
+config.test_source_root = None
+config.test_exec_root = None
diff --git a/utils/lit/tests/Inputs/discovery/subdir/lit.local.cfg b/utils/lit/tests/Inputs/discovery/subdir/lit.local.cfg
new file mode 100644
index 0000000..5ae6b3c
--- /dev/null
+++ b/utils/lit/tests/Inputs/discovery/subdir/lit.local.cfg
@@ -0,0 +1 @@
+config.suffixes = ['.py']
diff --git a/utils/lit/tests/Inputs/discovery/subdir/test-three.py b/utils/lit/tests/Inputs/discovery/subdir/test-three.py
new file mode 100644
index 0000000..b80b60b
--- /dev/null
+++ b/utils/lit/tests/Inputs/discovery/subdir/test-three.py
@@ -0,0 +1 @@
+# RUN: true
diff --git a/utils/lit/tests/Inputs/discovery/subsuite/lit.cfg b/utils/lit/tests/Inputs/discovery/subsuite/lit.cfg
new file mode 100644
index 0000000..0c2979d
--- /dev/null
+++ b/utils/lit/tests/Inputs/discovery/subsuite/lit.cfg
@@ -0,0 +1,5 @@
+config.name = 'sub-suite'
+config.suffixes = ['.txt']
+config.test_format = lit.formats.ShTest()
+config.test_source_root = None
+config.test_exec_root = None
diff --git a/utils/lit/tests/Inputs/discovery/subsuite/test-one.txt b/utils/lit/tests/Inputs/discovery/subsuite/test-one.txt
new file mode 100644
index 0000000..b80b60b
--- /dev/null
+++ b/utils/lit/tests/Inputs/discovery/subsuite/test-one.txt
@@ -0,0 +1 @@
+# RUN: true
diff --git a/utils/lit/tests/Inputs/discovery/subsuite/test-two.txt b/utils/lit/tests/Inputs/discovery/subsuite/test-two.txt
new file mode 100644
index 0000000..b80b60b
--- /dev/null
+++ b/utils/lit/tests/Inputs/discovery/subsuite/test-two.txt
@@ -0,0 +1 @@
+# RUN: true
diff --git a/utils/lit/tests/Inputs/discovery/test-one.txt b/utils/lit/tests/Inputs/discovery/test-one.txt
new file mode 100644
index 0000000..b80b60b
--- /dev/null
+++ b/utils/lit/tests/Inputs/discovery/test-one.txt
@@ -0,0 +1 @@
+# RUN: true
diff --git a/utils/lit/tests/Inputs/discovery/test-two.txt b/utils/lit/tests/Inputs/discovery/test-two.txt
new file mode 100644
index 0000000..b80b60b
--- /dev/null
+++ b/utils/lit/tests/Inputs/discovery/test-two.txt
@@ -0,0 +1 @@
+# RUN: true
diff --git a/utils/lit/tests/Inputs/shtest-format/external_shell/fail.txt b/utils/lit/tests/Inputs/shtest-format/external_shell/fail.txt
new file mode 100644
index 0000000..1e74be5
--- /dev/null
+++ b/utils/lit/tests/Inputs/shtest-format/external_shell/fail.txt
@@ -0,0 +1,3 @@
+# Run a command that fails with error on stdout.
+#
+# RUN: cat "does-not-exist"
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
new file mode 100644
index 0000000..d14d147
--- /dev/null
+++ b/utils/lit/tests/Inputs/shtest-format/external_shell/lit.local.cfg
@@ -0,0 +1 @@
+config.test_format = lit.formats.ShTest(execute_external=True)
diff --git a/utils/lit/tests/Inputs/shtest-format/external_shell/pass.txt b/utils/lit/tests/Inputs/shtest-format/external_shell/pass.txt
new file mode 100644
index 0000000..b80b60b
--- /dev/null
+++ b/utils/lit/tests/Inputs/shtest-format/external_shell/pass.txt
@@ -0,0 +1 @@
+# RUN: true
diff --git a/utils/lit/tests/Inputs/shtest-format/fail.txt b/utils/lit/tests/Inputs/shtest-format/fail.txt
new file mode 100644
index 0000000..49932c3
--- /dev/null
+++ b/utils/lit/tests/Inputs/shtest-format/fail.txt
@@ -0,0 +1 @@
+# RUN: false
diff --git a/utils/lit/tests/Inputs/shtest-format/lit.cfg b/utils/lit/tests/Inputs/shtest-format/lit.cfg
new file mode 100644
index 0000000..78dd1bf
--- /dev/null
+++ b/utils/lit/tests/Inputs/shtest-format/lit.cfg
@@ -0,0 +1,7 @@
+config.name = 'shtest-format'
+config.suffixes = ['.txt']
+config.test_format = lit.formats.ShTest()
+config.test_source_root = None
+config.test_exec_root = None
+config.target_triple = 'x86_64-unknown-unknown'
+config.available_features.add('a-present-feature')
diff --git a/utils/lit/tests/Inputs/shtest-format/no-test-line.txt b/utils/lit/tests/Inputs/shtest-format/no-test-line.txt
new file mode 100644
index 0000000..f2316bd
--- /dev/null
+++ b/utils/lit/tests/Inputs/shtest-format/no-test-line.txt
@@ -0,0 +1 @@
+# Empty!
diff --git a/utils/lit/tests/Inputs/shtest-format/pass.txt b/utils/lit/tests/Inputs/shtest-format/pass.txt
new file mode 100644
index 0000000..b80b60b
--- /dev/null
+++ b/utils/lit/tests/Inputs/shtest-format/pass.txt
@@ -0,0 +1 @@
+# RUN: true
diff --git a/utils/lit/tests/Inputs/shtest-format/requires-missing.txt b/utils/lit/tests/Inputs/shtest-format/requires-missing.txt
new file mode 100644
index 0000000..9e6648d
--- /dev/null
+++ b/utils/lit/tests/Inputs/shtest-format/requires-missing.txt
@@ -0,0 +1,2 @@
+RUN: true
+REQUIRES: a-missing-feature
diff --git a/utils/lit/tests/Inputs/shtest-format/requires-present.txt b/utils/lit/tests/Inputs/shtest-format/requires-present.txt
new file mode 100644
index 0000000..064f707
--- /dev/null
+++ b/utils/lit/tests/Inputs/shtest-format/requires-present.txt
@@ -0,0 +1,2 @@
+RUN: true
+REQUIRES: a-present-feature
diff --git a/utils/lit/tests/Inputs/shtest-format/unsupported_dir/lit.local.cfg b/utils/lit/tests/Inputs/shtest-format/unsupported_dir/lit.local.cfg
new file mode 100644
index 0000000..462e3dc
--- /dev/null
+++ b/utils/lit/tests/Inputs/shtest-format/unsupported_dir/lit.local.cfg
@@ -0,0 +1 @@
+config.unsupported = True
diff --git a/utils/lit/tests/Inputs/shtest-format/unsupported_dir/some-test.txt b/utils/lit/tests/Inputs/shtest-format/unsupported_dir/some-test.txt
new file mode 100644
index 0000000..b80b60b
--- /dev/null
+++ b/utils/lit/tests/Inputs/shtest-format/unsupported_dir/some-test.txt
@@ -0,0 +1 @@
+# RUN: true
diff --git a/utils/lit/tests/Inputs/shtest-format/xfail-feature.txt b/utils/lit/tests/Inputs/shtest-format/xfail-feature.txt
new file mode 100644
index 0000000..bd6241f
--- /dev/null
+++ b/utils/lit/tests/Inputs/shtest-format/xfail-feature.txt
@@ -0,0 +1,2 @@
+# RUN: false
+# XFAIL: a-present-feature
diff --git a/utils/lit/tests/Inputs/shtest-format/xfail-target.txt b/utils/lit/tests/Inputs/shtest-format/xfail-target.txt
new file mode 100644
index 0000000..36760be
--- /dev/null
+++ b/utils/lit/tests/Inputs/shtest-format/xfail-target.txt
@@ -0,0 +1,2 @@
+RUN: false
+XFAIL: x86_64
diff --git a/utils/lit/tests/Inputs/shtest-format/xfail.txt b/utils/lit/tests/Inputs/shtest-format/xfail.txt
new file mode 100644
index 0000000..6814cda
--- /dev/null
+++ b/utils/lit/tests/Inputs/shtest-format/xfail.txt
@@ -0,0 +1,2 @@
+RUN: false
+XFAIL: *
diff --git a/utils/lit/tests/Inputs/shtest-format/xpass.txt b/utils/lit/tests/Inputs/shtest-format/xpass.txt
new file mode 100644
index 0000000..764d217
--- /dev/null
+++ b/utils/lit/tests/Inputs/shtest-format/xpass.txt
@@ -0,0 +1,2 @@
+RUN: true
+XFAIL: x86_64
diff --git a/utils/lit/tests/Inputs/shtest-shell/error-0.txt b/utils/lit/tests/Inputs/shtest-shell/error-0.txt
new file mode 100644
index 0000000..631c8df
--- /dev/null
+++ b/utils/lit/tests/Inputs/shtest-shell/error-0.txt
@@ -0,0 +1,3 @@
+# Check error on an internal shell error (unable to find command).
+#
+# RUN: not-a-real-command
diff --git a/utils/lit/tests/Inputs/shtest-shell/error-1.txt b/utils/lit/tests/Inputs/shtest-shell/error-1.txt
new file mode 100644
index 0000000..e5c8be6
--- /dev/null
+++ b/utils/lit/tests/Inputs/shtest-shell/error-1.txt
@@ -0,0 +1,3 @@
+# Check error on a shell parsing failure.
+#
+# RUN: echo "missing quote
diff --git a/utils/lit/tests/Inputs/shtest-shell/error-2.txt b/utils/lit/tests/Inputs/shtest-shell/error-2.txt
new file mode 100644
index 0000000..a976286
--- /dev/null
+++ b/utils/lit/tests/Inputs/shtest-shell/error-2.txt
@@ -0,0 +1,3 @@
+# Check error on a unsupported redirect.
+#
+# RUN: echo "hello" 3>&1
diff --git a/utils/lit/tests/Inputs/shtest-shell/lit.cfg b/utils/lit/tests/Inputs/shtest-shell/lit.cfg
new file mode 100644
index 0000000..4878b65
--- /dev/null
+++ b/utils/lit/tests/Inputs/shtest-shell/lit.cfg
@@ -0,0 +1,5 @@
+config.name = 'shtest-shell'
+config.suffixes = ['.txt']
+config.test_format = lit.formats.ShTest()
+config.test_source_root = None
+config.test_exec_root = None
diff --git a/utils/lit/tests/Inputs/shtest-shell/redirects.txt b/utils/lit/tests/Inputs/shtest-shell/redirects.txt
new file mode 100644
index 0000000..6be88b6
--- /dev/null
+++ b/utils/lit/tests/Inputs/shtest-shell/redirects.txt
@@ -0,0 +1,41 @@
+# Check stdout redirect (> and >>).
+#
+# RUN: echo "not-present" > %t.stdout-write
+# RUN: echo "is-present" > %t.stdout-write
+# RUN: FileCheck --check-prefix=STDOUT-WRITE < %t.stdout-write %s
+#
+# STDOUT-WRITE-NOT: not-present
+# STDOUT-WRITE: is-present
+#
+# RUN: echo "appended-line" >> %t.stdout-write
+# RUN: FileCheck --check-prefix=STDOUT-APPEND < %t.stdout-write %s
+#
+# STDOUT-APPEND: is-present
+# STDOUT-APPEND: appended-line
+
+
+# Check stderr redirect (2> and 2>>).
+#
+# RUN: echo "not-present" > %t.stderr-write
+# RUN: %S/write-to-stderr.sh 2> %t.stderr-write
+# RUN: FileCheck --check-prefix=STDERR-WRITE < %t.stderr-write %s
+#
+# STDERR-WRITE-NOT: not-present
+# STDERR-WRITE: a line on stderr
+#
+# RUN: %S/write-to-stderr.sh 2>> %t.stderr-write
+# RUN: FileCheck --check-prefix=STDERR-APPEND < %t.stderr-write %s
+#
+# STDERR-APPEND: a line on stderr
+# STDERR-APPEND: a line on stderr
+
+
+# Check combined redirect (&>).
+#
+# RUN: echo "not-present" > %t.combined
+# RUN: %S/write-to-stdout-and-stderr.sh &> %t.combined
+# RUN: FileCheck --check-prefix=COMBINED-WRITE < %t.combined %s
+#
+# COMBINED-WRITE-NOT: not-present
+# COMBINED-WRITE: a line on stdout
+# COMBINED-WRITE: a line on stderr
diff --git a/utils/lit/tests/Inputs/shtest-shell/sequencing-0.txt b/utils/lit/tests/Inputs/shtest-shell/sequencing-0.txt
new file mode 100644
index 0000000..6578db2
--- /dev/null
+++ b/utils/lit/tests/Inputs/shtest-shell/sequencing-0.txt
@@ -0,0 +1,28 @@
+# Check sequencing operations.
+#
+# RUN: echo "first-line" > %t.out && echo "second-line" >> %t.out
+# RUN: FileCheck --check-prefix CHECK-AND < %t.out %s
+#
+# CHECK-AND: first-line
+# CHECK-AND: second-line
+#
+# The false case of && is tested in sequencing-2.txt
+
+
+# RUN: echo "first-line" > %t.out || echo "second-line" >> %t.out
+# RUN: FileCheck --check-prefix CHECK-OR-1 < %t.out %s
+#
+# CHECK-OR-1: first-line
+# CHECK-OR-1-NOT: second-line
+
+# RUN: false || echo "second-line" > %t.out
+# RUN: FileCheck --check-prefix CHECK-OR-2 < %t.out %s
+#
+# CHECK-OR-2: second-line
+
+
+# RUN: echo "first-line" > %t.out; echo "second-line" >> %t.out
+# RUN: FileCheck --check-prefix CHECK-SEQ < %t.out %s
+#
+# CHECK-SEQ: first-line
+# CHECK-SEQ: second-line
diff --git a/utils/lit/tests/Inputs/shtest-shell/sequencing-1.txt b/utils/lit/tests/Inputs/shtest-shell/sequencing-1.txt
new file mode 100644
index 0000000..5a1794c
--- /dev/null
+++ b/utils/lit/tests/Inputs/shtest-shell/sequencing-1.txt
@@ -0,0 +1,2 @@
+# RUN: false && true
+# XFAIL: *
diff --git a/utils/lit/tests/Inputs/shtest-shell/write-to-stderr.sh b/utils/lit/tests/Inputs/shtest-shell/write-to-stderr.sh
new file mode 100755
index 0000000..ead3fd3
--- /dev/null
+++ b/utils/lit/tests/Inputs/shtest-shell/write-to-stderr.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+echo "a line on stderr" 1>&2
diff --git a/utils/lit/tests/Inputs/shtest-shell/write-to-stdout-and-stderr.sh b/utils/lit/tests/Inputs/shtest-shell/write-to-stdout-and-stderr.sh
new file mode 100755
index 0000000..f20de5d
--- /dev/null
+++ b/utils/lit/tests/Inputs/shtest-shell/write-to-stdout-and-stderr.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+echo "a line on stdout"
+echo "a line on stderr" 1>&2
diff --git a/utils/lit/tests/Inputs/unittest-adaptor/lit.cfg b/utils/lit/tests/Inputs/unittest-adaptor/lit.cfg
new file mode 100644
index 0000000..52de709
--- /dev/null
+++ b/utils/lit/tests/Inputs/unittest-adaptor/lit.cfg
@@ -0,0 +1,5 @@
+config.name = 'unittest-adaptor'
+config.suffixes = ['.txt']
+config.test_format = lit.formats.ShTest()
+config.test_source_root = None
+config.test_exec_root = None
diff --git a/utils/lit/tests/Inputs/unittest-adaptor/test-one.txt b/utils/lit/tests/Inputs/unittest-adaptor/test-one.txt
new file mode 100644
index 0000000..b80b60b
--- /dev/null
+++ b/utils/lit/tests/Inputs/unittest-adaptor/test-one.txt
@@ -0,0 +1 @@
+# RUN: true
diff --git a/utils/lit/tests/Inputs/unittest-adaptor/test-two.txt b/utils/lit/tests/Inputs/unittest-adaptor/test-two.txt
new file mode 100644
index 0000000..49932c3
--- /dev/null
+++ b/utils/lit/tests/Inputs/unittest-adaptor/test-two.txt
@@ -0,0 +1 @@
+# RUN: false
diff --git a/utils/lit/tests/discovery.py b/utils/lit/tests/discovery.py
new file mode 100644
index 0000000..54b99d3
--- /dev/null
+++ b/utils/lit/tests/discovery.py
@@ -0,0 +1,25 @@
+# Check the basic discovery process, including a sub-suite.
+#
+# RUN: %{lit} %{inputs}/discovery \
+# RUN: -j 1 --debug --no-execute --show-suites -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
+#
+# CHECK-BASIC-ERR: loading suite config '{{.*}}/tests/Inputs/discovery/lit.cfg'
+# CHECK-BASIC-ERR: loading local config '{{.*}}/tests/Inputs/discovery/subdir/lit.local.cfg'
+# CHECK-BASIC-ERR: loading suite config '{{.*}}/tests/Inputs/discovery/subsuite/lit.cfg'
+#
+# CHECK-BASIC-OUT: -- Test Suites --
+# CHECK-BASIC-OUT: sub-suite - 2 tests
+# CHECK-BASIC-OUT: Source Root:
+# CHECK-BASIC-OUT: Exec Root :
+# CHECK-BASIC-OUT: top-level-suite - 3 tests
+# CHECK-BASIC-OUT: Source Root:
+# CHECK-BASIC-OUT: Exec Root :
+#
+# CHECK-BASIC-OUT: -- Testing: 5 tests, 1 threads --
+# CHECK-BASIC-OUT: PASS: sub-suite :: test-one
+# CHECK-BASIC-OUT: PASS: sub-suite :: test-two
+# CHECK-BASIC-OUT: PASS: top-level-suite :: subdir/test-three
+# CHECK-BASIC-OUT: PASS: top-level-suite :: test-one
+# CHECK-BASIC-OUT: PASS: top-level-suite :: test-two
diff --git a/utils/lit/tests/lit.cfg b/utils/lit/tests/lit.cfg
new file mode 100644
index 0000000..32760ce
--- /dev/null
+++ b/utils/lit/tests/lit.cfg
@@ -0,0 +1,36 @@
+# -*- Python -*-
+
+import os
+
+# Configuration file for the 'lit' test runner.
+
+# name: The name of this test suite.
+config.name = 'lit'
+
+# testFormat: The test format to use to interpret tests.
+config.test_format = lit.formats.ShTest(execute_external=False)
+
+# suffixes: A list of file extensions to treat as test files.
+config.suffixes = ['.py']
+
+# excludes: A list of individual files to exclude.
+config.excludes = ['Inputs']
+
+# test_source_root: The root path where tests are located.
+config.test_source_root = os.path.dirname(__file__)
+config.test_exec_root = config.test_source_root
+
+config.target_triple = None
+
+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')))
+
+# 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):
+ config.environment['COVERAGE_PROCESS_START'] = os.path.join(
+ os.path.dirname(__file__), ".coveragerc")
diff --git a/utils/lit/tests/shell-parsing.py b/utils/lit/tests/shell-parsing.py
new file mode 100644
index 0000000..f644132
--- /dev/null
+++ b/utils/lit/tests/shell-parsing.py
@@ -0,0 +1,3 @@
+# Just run the ShUtil unit tests.
+#
+# RUN: python -m lit.ShUtil
diff --git a/utils/lit/tests/shtest-format.py b/utils/lit/tests/shtest-format.py
new file mode 100644
index 0000000..4b36873
--- /dev/null
+++ b/utils/lit/tests/shtest-format.py
@@ -0,0 +1,43 @@
+# Check the various features of the ShTest format.
+#
+# RUN: not %{lit} -j 1 -v %{inputs}/shtest-format > %t.out
+# RUN: FileCheck < %t.out %s
+#
+# END.
+
+# CHECK: -- Testing:
+
+# CHECK: FAIL: shtest-format :: external_shell/fail.txt
+# CHECK: *** TEST 'shtest-format :: external_shell/fail.txt' FAILED ***
+# CHECK: Command Output (stderr):
+# CHECK: cat: does-not-exist: No such file or directory
+# CHECK: --
+
+# CHECK: PASS: shtest-format :: external_shell/pass.txt
+
+# CHECK: FAIL: shtest-format :: fail.txt
+
+# CHECK: UNRESOLVED: shtest-format :: no-test-line.txt
+# CHECK: PASS: shtest-format :: pass.txt
+# CHECK: UNSUPPORTED: shtest-format :: requires-missing.txt
+# CHECK: PASS: shtest-format :: requires-present.txt
+# CHECK: UNSUPPORTED: shtest-format :: unsupported_dir/some-test.txt
+# CHECK: XFAIL: shtest-format :: xfail-feature.txt
+# CHECK: XFAIL: shtest-format :: xfail-target.txt
+# CHECK: XFAIL: shtest-format :: xfail.txt
+# CHECK: XPASS: shtest-format :: xpass.txt
+# CHECK: Testing Time
+
+# CHECK: Unexpected Passing Tests (1)
+# CHECK: shtest-format :: xpass.txt
+
+# CHECK: Failing Tests (2)
+# CHECK: shtest-format :: external_shell/fail.txt
+# CHECK: shtest-format :: fail.txt
+
+# CHECK: Expected Passes : 3
+# CHECK: Expected Failures : 3
+# CHECK: Unsupported Tests : 2
+# CHECK: Unresolved Tests : 1
+# CHECK: Unexpected Passes : 1
+# CHECK: Unexpected Failures: 2
diff --git a/utils/lit/tests/shtest-shell.py b/utils/lit/tests/shtest-shell.py
new file mode 100644
index 0000000..32479e1
--- /dev/null
+++ b/utils/lit/tests/shtest-shell.py
@@ -0,0 +1,33 @@
+# Check the internal shell handling component of the ShTest format.
+#
+# RUN: not %{lit} -j 1 -v %{inputs}/shtest-shell > %t.out
+# RUN: FileCheck < %t.out %s
+#
+# END.
+
+# CHECK: -- Testing:
+
+# CHECK: FAIL: shtest-shell :: error-0.txt
+# CHECK: *** TEST 'shtest-shell :: error-0.txt' FAILED ***
+# CHECK: Command 0: "not-a-real-command"
+# CHECK: Command 0 Result: 127
+# CHECK: Command 0 Stderr:
+# CHECK: 'not-a-real-command': command not found
+# CHECK: ***
+
+# FIXME: The output here sucks.
+#
+# CHECK: FAIL: shtest-shell :: error-1.txt
+# CHECK: *** TEST 'shtest-shell :: error-1.txt' FAILED ***
+# CHECK: shell parser error on: 'echo "missing quote'
+# CHECK: ***
+
+# CHECK: FAIL: shtest-shell :: error-2.txt
+# CHECK: *** TEST 'shtest-shell :: error-2.txt' FAILED ***
+# CHECK: Unsupported redirect:
+# CHECK: ***
+
+# CHECK: PASS: shtest-shell :: redirects.txt
+# CHECK: PASS: shtest-shell :: sequencing-0.txt
+# CHECK: XFAIL: shtest-shell :: sequencing-1.txt
+# CHECK: Failing Tests (3)
diff --git a/utils/lit/tests/unittest-adaptor.py b/utils/lit/tests/unittest-adaptor.py
new file mode 100644
index 0000000..243dd41
--- /dev/null
+++ b/utils/lit/tests/unittest-adaptor.py
@@ -0,0 +1,18 @@
+# Check the lit adaption to run under unittest.
+#
+# RUN: python %s %{inputs}/unittest-adaptor 2> %t.err
+# RUN: FileCheck < %t.err %s
+#
+# CHECK: unittest-adaptor :: test-one.txt ... ok
+# CHECK: unittest-adaptor :: test-two.txt ... FAIL
+
+import unittest
+import sys
+
+import lit
+import lit.discovery
+
+input_path = sys.argv[1]
+unittest_suite = lit.discovery.load_test_suite([input_path])
+runner = unittest.TextTestRunner(verbosity=2)
+runner.run(unittest_suite)
diff --git a/utils/lit/tests/usage.py b/utils/lit/tests/usage.py
new file mode 100644
index 0000000..e10d613
--- /dev/null
+++ b/utils/lit/tests/usage.py
@@ -0,0 +1,6 @@
+# Basic sanity check that usage works.
+#
+# RUN: %{lit} --help > %t.out
+# RUN: FileCheck < %t.out %s
+#
+# CHECK: Usage: lit.py [options] {file-or-path}
diff --git a/utils/lit/utils/README.txt b/utils/lit/utils/README.txt
new file mode 100644
index 0000000..81862ba
--- /dev/null
+++ b/utils/lit/utils/README.txt
@@ -0,0 +1,2 @@
+Utilities for the project that aren't intended to be part of a source
+distribution.
diff --git a/utils/lit/utils/check-coverage b/utils/lit/utils/check-coverage
new file mode 100755
index 0000000..bb3d17e
--- /dev/null
+++ b/utils/lit/utils/check-coverage
@@ -0,0 +1,50 @@
+#!/bin/sh
+
+prog=$(basename $0)
+
+# Expect to be run from the parent lit directory.
+if [ ! -f setup.py ] || [ ! -d lit ]; then
+ printf 1>&2 "%s: expected to be run from base lit directory\n" "$prog"
+ exit 1
+fi
+
+# Parse command line arguments.
+if [ "$1" == "--generate-html" ]; then
+ GENERATE_HTML=1
+ shift
+fi
+
+# If invoked with no arguments, run all the tests.
+if [ $# == "0" ]; then
+ set -- "tests"
+fi
+
+# Check that the active python has been modified to enable coverage in its
+# sitecustomize.
+if ! python -c \
+ 'import sitecustomize, sys; sys.exit("coverage" not in dir(sitecustomize))' \
+ &> /dev/null; then
+ printf 1>&2 "error: active python does not appear to enable coverage in its 'sitecustomize.py'\n"
+ exit 1
+fi
+
+# First, remove any existing coverage data files.
+rm -f tests/.coverage
+find tests -name .coverage.\* -exec rm {} \;
+
+# Next, run the tests.
+lit -sv --param check-coverage=1 "$@"
+
+# Next, move all the data files from subdirectories up.
+find tests/* -name .coverage.\* -exec mv {} tests \;
+
+# Combine all the data files.
+(cd tests && python -m coverage combine)
+
+# Finally, generate the report.
+(cd tests && python -m coverage report)
+
+# Generate the HTML report, if requested.
+if [ ! -z "$GENERATE_HTML" ]; then
+ (cd tests && python -m coverage html)
+fi
diff --git a/utils/lit/utils/check-sdist b/utils/lit/utils/check-sdist
new file mode 100755
index 0000000..6186446a
--- /dev/null
+++ b/utils/lit/utils/check-sdist
@@ -0,0 +1,44 @@
+#!/bin/sh
+
+if [ $# == 1 ]; then
+ cd $1
+fi
+
+# Create a list of all the files in the source tree, excluding various things we
+# know don't belong.
+echo "Creating current directory contents list."
+find . | \
+ grep -v '^\./.gitignore' | \
+ grep -v '^\./dist' | \
+ grep -v '^\./utils' | \
+ grep -v '^\./venv' | \
+ grep -v '^\./lit.egg-info' | \
+ grep -v '^\./lit/ExampleTests' | \
+ grep -v '/Output' | \
+ grep -v '__pycache__' | \
+ grep -v '.pyc$' | grep -v '~$' | \
+ sort > /tmp/lit_source_files.txt
+
+# Create the source distribution.
+echo "Creating source distribution."
+rm -rf lit.egg-info dist
+python setup.py sdist > /tmp/lit_sdist_log.txt
+
+# Creating list of files in source distribution.
+echo "Creating source distribution file list."
+tar zft dist/lit*.tar.gz | \
+ sed -e 's#lit-[0-9.dev]*/#./#' | \
+ sed -e 's#/$##' | \
+ grep -v '^\./PKG-INFO' | \
+ grep -v '^\./setup.cfg' | \
+ grep -v '^\./lit.egg-info' | \
+ sort > /tmp/lit_sdist_files.txt
+
+# Diff the files.
+echo "Running diff..."
+if (diff /tmp/lit_source_files.txt /tmp/lit_sdist_files.txt); then
+ echo "Diff is clean!"
+else
+ echo "error: there were differences in the source lists!"
+ exit 1
+fi
diff --git a/utils/llvm-build/llvmbuild/main.py b/utils/llvm-build/llvmbuild/main.py
index 27d23d0..87e8819 100644
--- a/utils/llvm-build/llvmbuild/main.py
+++ b/utils/llvm-build/llvmbuild/main.py
@@ -182,7 +182,9 @@ class LLVMProjectInfo(object):
# out easily. If we don't, we should special case the check.
self.ordered_component_infos = []
- components_to_visit = set(self.component_infos)
+ components_to_visit = sorted(
+ set(self.component_infos),
+ key = lambda c: c.name)
while components_to_visit:
visit_component_info(iter(components_to_visit).next(), [], set())
@@ -807,7 +809,7 @@ given by --build-root) at the same SUBPATH""",
# Determine the LLVM source path, if not given.
source_root = opts.source_root
if source_root:
- if not os.path.exists(os.path.join(source_root, 'lib', 'VMCore',
+ if not os.path.exists(os.path.join(source_root, 'lib', 'IR',
'Function.cpp')):
parser.error('invalid LLVM source root: %r' % source_root)
else:
@@ -815,7 +817,7 @@ given by --build-root) at the same SUBPATH""",
llvm_build_path = os.path.dirname(llvmbuild_path)
utils_path = os.path.dirname(llvm_build_path)
source_root = os.path.dirname(utils_path)
- if not os.path.exists(os.path.join(source_root, 'lib', 'VMCore',
+ if not os.path.exists(os.path.join(source_root, 'lib', 'IR',
'Function.cpp')):
parser.error('unable to infer LLVM source root, please specify')
diff --git a/utils/llvm-compilers-check b/utils/llvm-compilers-check
index 623ebc6..3173027 100755
--- a/utils/llvm-compilers-check
+++ b/utils/llvm-compilers-check
@@ -1,11 +1,11 @@
#!/usr/bin/python3
##===- utils/llvmbuild - Build the LLVM project ----------------*-python-*-===##
-#
+#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
-#
+#
##===----------------------------------------------------------------------===##
#
# This script builds many different flavors of the LLVM ecosystem. It
@@ -147,6 +147,8 @@ def add_options(parser):
help=("Do not build dragonegg"))
parser.add_option("--no-install", default=False, action="store_true",
help=("Do not do installs"))
+ parser.add_option("--keep-going", default=False, action="store_true",
+ help=("Keep going after failures"))
return
def check_options(parser, options, valid_builds):
@@ -282,7 +284,7 @@ class Builder(threading.Thread):
for key, value in env.items():
execenv[key] = value
-
+
self.logger.debug("[" + prefix + "] " + "env " + str(env) + " "
+ " ".join(command));
@@ -299,6 +301,11 @@ class Builder(threading.Thread):
+ str(line, "utf-8").rstrip())
line = proc.stdout.readline()
+ (stdoutdata, stderrdata) = proc.communicate()
+ retcode = proc.wait()
+
+ return retcode
+
except:
traceback.print_exc()
@@ -327,6 +334,7 @@ class Builder(threading.Thread):
self.logger.debug("Start Gather")
gather = True
line = proc.stdout.readline()
+
except:
traceback.print_exc()
self.logger.debug(includes)
@@ -353,16 +361,16 @@ class Builder(threading.Thread):
configure_flags = dict(
llvm=dict(debug=["--prefix=" + self.install_prefix,
- "--with-extra-options=-Werror",
+ "--enable-werror",
"--enable-assertions",
"--disable-optimized",
"--with-gcc-toolchain=" + cxxroot],
release=["--prefix=" + self.install_prefix,
- "--with-extra-options=-Werror",
+ "--enable-werror",
"--enable-optimized",
"--with-gcc-toolchain=" + cxxroot],
paranoid=["--prefix=" + self.install_prefix,
- "--with-extra-options=-Werror",
+ "--enable-werror",
"--enable-assertions",
"--enable-expensive-checks",
"--disable-optimized",
@@ -438,7 +446,7 @@ class Builder(threading.Thread):
for component in components:
comp = component[:]
-
+
if (self.options.no_dragonegg):
if (comp == 'dragonegg'):
self.logger.info("Skipping " + component + " in "
@@ -458,43 +466,74 @@ class Builder(threading.Thread):
"").split())
self.logger.info("Configuring " + component + " in " + builddir)
- self.configure(component, srcdir, builddir,
- config_args,
- configure_env[comp_key][build])
-
- self.logger.info("Building " + component + " in " + builddir)
- self.logger.info("Build: make " + str(make_flags[comp_key][build]))
- self.make(component, srcdir, builddir,
- make_flags[comp_key][build],
- make_env[comp_key][build])
-
- if (not self.options.no_install):
- self.logger.info("Installing " + component + " in " + installdir)
- self.make(component, srcdir, builddir,
- make_install_flags[comp_key][build],
- make_install_env[comp_key][build])
-
- self.logger.info("Testing " + component + " in " + builddir)
- self.logger.info("Test: make "
- + str(make_check_flags[comp_key][build]))
- self.make(component, srcdir, builddir,
- make_check_flags[comp_key][build],
- make_check_env[comp_key][build])
-
+ configrc = self.configure(component, srcdir, builddir,
+ config_args,
+ configure_env[comp_key][build])
+
+ if (configrc == None) :
+ self.logger.info("[None] Failed to configure " + component + " in " + installdir)
+
+ if (configrc == 0 or self.options.keep_going) :
+ self.logger.info("Building " + component + " in " + builddir)
+ self.logger.info("Build: make " + str(make_flags[comp_key][build]))
+ buildrc = self.make(component, srcdir, builddir,
+ make_flags[comp_key][build],
+ make_env[comp_key][build])
+
+ if (buildrc == None) :
+ self.logger.info("[None] Failed to build " + component + " in " + installdir)
+
+ if (buildrc == 0 or self.options.keep_going) :
+ self.logger.info("Testing " + component + " in " + builddir)
+ self.logger.info("Test: make "
+ + str(make_check_flags[comp_key][build]))
+ testrc = self.make(component, srcdir, builddir,
+ make_check_flags[comp_key][build],
+ make_check_env[comp_key][build])
+
+ if (testrc == None) :
+ self.logger.info("[None] Failed to test " + component + " in " + installdir)
+
+ if ((testrc == 0 or self.options.keep_going)
+ and not self.options.no_install):
+ self.logger.info("Installing " + component + " in " + installdir)
+ self.make(component, srcdir, builddir,
+ make_install_flags[comp_key][build],
+ make_install_env[comp_key][build])
+ else :
+ self.logger.info("Failed testing " + component + " in " + installdir)
+
+ else :
+ self.logger.info("Failed to build " + component + " in " + installdir)
+
+ else :
+ self.logger.info("Failed to configure " + component + " in " + installdir)
def configure(self, component, srcdir, builddir, flags, env):
+ prefix = self.component_abbrev[component.replace("-", "_")]
+
self.logger.debug("Configure " + str(flags) + " " + str(srcdir) + " -> "
+ str(builddir))
configure_files = dict(
llvm=[(srcdir + "/configure", builddir + "/Makefile")],
- dragonegg=[("","")])
+ dragonegg=[(None,None)])
doconfig = False
for conf, mf in configure_files[component.replace("-", "_")]:
+ if conf is None:
+ # No configure necessary
+ return 0
+
if not os.path.exists(conf):
- return
+ self.logger.info("[" + prefix + "] Configure failed, no configure script " + conf)
+ return -1
+
+ if not os.path.exists(mf):
+ self.logger.info("[" + prefix + "] Configure failed, no makefile " + mf)
+ return -1
+
if os.path.exists(conf) and os.path.exists(mf):
confstat = os.stat(conf)
makestat = os.stat(mf)
@@ -506,16 +545,17 @@ class Builder(threading.Thread):
break
if not doconfig and not self.options.force_configure:
- return
+ return 0
program = srcdir + "/configure"
if not is_executable(program):
- return
+ self.logger.info("[" + prefix + "] Configure failed, cannot execute " + program)
+ return -1
args = [program]
args += ["--verbose"]
args += flags
- self.execute(args, builddir, env, component)
+ return self.execute(args, builddir, env, component)
def make(self, component, srcdir, builddir, flags, env):
program = find_executable("make")
@@ -527,7 +567,7 @@ class Builder(threading.Thread):
args = [program]
args += flags
- self.execute(args, builddir, env, component)
+ return self.execute(args, builddir, env, component)
# Global constants
build_abbrev = dict(debug="dbg", release="opt", paranoid="par")
diff --git a/utils/llvm-lit/llvm-lit.in b/utils/llvm-lit/llvm-lit.in
index 768dc51..87878d5 100644
--- a/utils/llvm-lit/llvm-lit.in
+++ b/utils/llvm-lit/llvm-lit.in
@@ -13,8 +13,7 @@ sys.path.insert(0, os.path.join(llvm_source_root, 'utils', 'lit'))
# Set up some builtin parameters, so that by default the LLVM test suite
# configuration file knows how to find the object tree.
builtin_parameters = {
- 'build_config' : "@CMAKE_CFG_INTDIR@",
- 'build_mode' : "@RUNTIME_BUILD_MODE@",
+ 'build_mode' : "@CMAKE_CFG_INTDIR@",
'llvm_site_config' : os.path.join(llvm_obj_root, 'test', 'lit.site.cfg')
}
diff --git a/utils/llvm.grm b/utils/llvm.grm
index 322036b..d65f075 100644
--- a/utils/llvm.grm
+++ b/utils/llvm.grm
@@ -174,7 +174,9 @@ FuncAttr ::= noreturn
| sspreq
| returns_twice
| nonlazybind
- | address_safety
+ | sanitize_address
+ | sanitize_thread
+ | sanitize_memory
;
OptFuncAttrs ::= + _ | OptFuncAttrs FuncAttr ;
diff --git a/utils/llvm.natvis b/utils/llvm.natvis
new file mode 100644
index 0000000..6b4ef83
--- /dev/null
+++ b/utils/llvm.natvis
@@ -0,0 +1,181 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Visual Studio 2012 Native Debugging Visualizers for LLVM
+
+Put this file into "%USERPROFILE%\Documents\Visual Studio 2012\Visualizers"
+or create a symbolic link so it updates automatically.
+-->
+<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
+ <Type Name="llvm::SmallVector&lt;*,*&gt;">
+ <DisplayString Condition="(($T1*)EndX - ($T1*)BeginX) == 0">empty</DisplayString>
+ <DisplayString Condition="(($T1*)EndX - ($T1*)BeginX) != 0">{{ size={($T1*)EndX - ($T1*)BeginX} }}</DisplayString>
+ <Expand>
+ <Item Name="[size]">($T1*)EndX - ($T1*)BeginX</Item>
+ <Item Name="[capacity]">($T1*)CapacityX - ($T1*)BeginX</Item>
+ <ArrayItems>
+ <Size>($T1*)EndX - ($T1*)BeginX</Size>
+ <ValuePointer>($T1*)BeginX</ValuePointer>
+ </ArrayItems>
+ </Expand>
+ </Type>
+
+ <Type Name="llvm::SmallVectorImpl&lt;*&gt;">
+ <DisplayString Condition="(($T1*)EndX - ($T1*)BeginX) == 0">empty</DisplayString>
+ <DisplayString Condition="(($T1*)EndX - ($T1*)BeginX) != 0">[{($T1*)EndX - ($T1*)BeginX}]</DisplayString>
+ <Expand>
+ <Item Name="[size]">($T1*)EndX - ($T1*)BeginX</Item>
+ <Item Name="[capacity]">($T1*)CapacityX - ($T1*)BeginX</Item>
+ <ArrayItems>
+ <Size>($T1*)EndX - ($T1*)BeginX</Size>
+ <ValuePointer>($T1*)BeginX</ValuePointer>
+ </ArrayItems>
+ </Expand>
+ </Type>
+
+ <Type Name="llvm::SmallString&lt;*&gt;">
+ <DisplayString>{BeginX,s}</DisplayString>
+ <StringView>BeginX,s</StringView>
+ <Expand>
+ <Item Name="[size]">(char*)EndX - (char*)BeginX</Item>
+ <Item Name="[capacity]">(char*)CapacityX - (char*)BeginX</Item>
+ <ArrayItems>
+ <Size>(char*)EndX - (char*)BeginX</Size>
+ <ValuePointer>(char*)BeginX</ValuePointer>
+ </ArrayItems>
+ </Expand>
+ </Type>
+
+ <Type Name="llvm::StringRef">
+ <DisplayString>[{Length}] {Data,s}</DisplayString>
+ <StringView>Data,s</StringView>
+ <Expand>
+ <Item Name="[length]">Length</Item>
+ <ArrayItems>
+ <Size>Length</Size>
+ <ValuePointer>Data</ValuePointer>
+ </ArrayItems>
+ </Expand>
+ </Type>
+
+ <Type Name="llvm::PointerIntPair&lt;*,*,*,*&gt;">
+ <DisplayString>{Value &amp; PointerBitMask} [{(Value &gt;&gt; IntShift) &amp; IntMask}]</DisplayString>
+ <Expand>
+ <Item Name="[ptr]">Value &amp; PointerBitMask</Item>
+ <Item Name="[int]">(Value &gt;&gt; IntShift) &amp; IntMask</Item>
+ </Expand>
+ </Type>
+
+ <Type Name="llvm::PointerUnion&lt;*,*&gt;">
+ <DisplayString Condition="((Val.Value &gt;&gt; Val.IntShift) &amp; Val.IntMask) == 0">[P1] {($T1)(Val.Value &amp; Val.PointerBitMask)}</DisplayString>
+ <DisplayString Condition="((Val.Value &gt;&gt; Val.IntShift) &amp; Val.IntMask) != 0">[P2] {($T2)(Val.Value &amp; Val.PointerBitMask)}</DisplayString>
+ <Expand>
+ <Item Name="[ptr]" Condition="((Val.Value &gt;&gt; Val.IntShift) &amp; Val.IntMask) == 0">($T1)(Val.Value &amp; Val.PointerBitMask)</Item>
+ <Item Name="[ptr]" Condition="((Val.Value &gt;&gt; Val.IntShift) &amp; Val.IntMask) != 0">($T2)(Val.Value &amp; Val.PointerBitMask)</Item>
+ </Expand>
+ </Type>
+
+ <Type Name="llvm::PointerUnion3&lt;*,*,*&gt;">
+ <DisplayString Condition="(Val.Val.Value &amp; 2) != 2 &amp;&amp; (Val.Val.Value &amp; 1) != 1">[P1] {($T1)((Val.Val.Value &gt;&gt; 2) &lt;&lt; 2)}</DisplayString>
+ <DisplayString Condition="(Val.Val.Value &amp; 2) == 2">[P2] {($T2)((Val.Val.Value &gt;&gt; 2) &lt;&lt; 2)}</DisplayString>
+ <DisplayString Condition="(Val.Val.Value &amp; 1) == 1">[P3] {($T3)((Val.Val.Value &gt;&gt; 2) &lt;&lt; 2)}</DisplayString>
+ <Expand>
+ <Item Name="[ptr]" Condition="(Val.Val.Value &amp; 2) != 2 &amp;&amp; (Val.Val.Value &amp; 1) != 1">($T1)((Val.Val.Value &gt;&gt; 2) &lt;&lt; 2)</Item>
+ <Item Name="[ptr]" Condition="(Val.Val.Value &amp; 2) == 2">($T2)((Val.Val.Value &gt;&gt; 2) &lt;&lt; 2)</Item>
+ <Item Name="[ptr]" Condition="(Val.Val.Value &amp; 1) == 1">($T3)((Val.Val.Value &gt;&gt; 2) &lt;&lt; 2)</Item>
+ </Expand>
+ </Type>
+
+ <Type Name="llvm::PointerUnion4&lt;*,*,*,*&gt;">
+ <DisplayString Condition="(Val.Val.Value &amp; 3) != 3 &amp;&amp; (Val.Val.Value &amp; 2) != 2 &amp;&amp; (Val.Val.Value &amp; 1) != 1">[P1] {($T1)((Val.Val.Value &gt;&gt; 2) &lt;&lt; 2)}</DisplayString>
+ <DisplayString Condition="(Val.Val.Value &amp; 3) != 3 &amp;&amp; (Val.Val.Value &amp; 2) == 2">[P2] {($T2)((Val.Val.Value &gt;&gt; 2) &lt;&lt; 2)}</DisplayString>
+ <DisplayString Condition="(Val.Val.Value &amp; 3) != 3 &amp;&amp; (Val.Val.Value &amp; 1) == 1">[P3] {($T3)((Val.Val.Value &gt;&gt; 2) &lt;&lt; 2)}</DisplayString>
+ <DisplayString Condition="(Val.Val.Value &amp; 3) == 3">[P4] {($T4)((Val.Val.Value &gt;&gt; 2) &lt;&lt; 2)}</DisplayString>
+ <Expand>
+ <Item Name="[ptr]" Condition="(Val.Val.Value &amp; 3) != 3 &amp;&amp; (Val.Val.Value &amp; 2) != 2 &amp;&amp; (Val.Val.Value &amp; 1) != 1">($T1)((Val.Val.Value &gt;&gt; 2) &lt;&lt; 2)</Item>
+ <Item Name="[ptr]" Condition="(Val.Val.Value &amp; 3) != 3 &amp;&amp; (Val.Val.Value &amp; 2) == 2">($T2)((Val.Val.Value &gt;&gt; 2) &lt;&lt; 2)</Item>
+ <Item Name="[ptr]" Condition="(Val.Val.Value &amp; 3) != 3 &amp;&amp; (Val.Val.Value &amp; 1) == 1">($T3)((Val.Val.Value &gt;&gt; 2) &lt;&lt; 2)</Item>
+ <Item Name="[ptr]" Condition="(Val.Val.Value &amp; 3) == 3">($T4)((Val.Val.Value &gt;&gt; 2) &lt;&lt; 2)</Item>
+ </Expand>
+ </Type>
+
+ <Type Name="llvm::iplist&lt;*,*&gt;">
+ <DisplayString Condition="Head == 0">{{ empty }}</DisplayString>
+ <DisplayString Condition="Head != 0">{{ head={Head} }}</DisplayString>
+ <Expand>
+ <LinkedListItems>
+ <HeadPointer>Head</HeadPointer>
+ <NextPointer>Next</NextPointer>
+ <ValueNode>this</ValueNode>
+ </LinkedListItems>
+ </Expand>
+ </Type>
+
+ <Type Name="llvm::IntrusiveRefCntPtr&lt;*&gt;">
+ <DisplayString Condition="Obj == 0">empty</DisplayString>
+ <DisplayString Condition="(Obj != 0) &amp;&amp; (Obj-&gt;ref_cnt == 1)">RefPtr [1 ref] {*Obj}</DisplayString>
+ <DisplayString Condition="(Obj != 0) &amp;&amp; (Obj-&gt;ref_cnt != 1)">RefPtr [{Obj-&gt;ref_cnt} refs] {*Obj}</DisplayString>
+ <Expand>
+ <Item Condition="Obj != 0" Name="[refs]">Obj-&gt;ref_cnt</Item>
+ <Item Condition="Obj != 0" Name="[ptr]">Obj</Item>
+ </Expand>
+ </Type>
+
+ <Type Name="llvm::OwningPtr&lt;*&gt;">
+ <DisplayString Condition="Ptr == 0">empty</DisplayString>
+ <DisplayString Condition="Ptr != 0">OwningPtr {*Ptr}</DisplayString>
+ <Expand>
+ <Item Condition="Ptr != 0" Name="[ptr]">Ptr</Item>
+ </Expand>
+ </Type>
+
+ <Type Name="llvm::SmallPtrSet&lt;*,*&gt;">
+ <DisplayString Condition="CurArray == SmallArray">{{ [Small Mode] elements={NumElements}, arraySize={CurArraySize} }}</DisplayString>
+ <DisplayString Condition="CurArray != SmallArray">{{ [Big Mode] elements={NumElements}, arraySize={CurArraySize} }}</DisplayString>
+ <Expand>
+ <Item Name="[NumElements]">NumElements</Item>
+ <Item Name="[CurArraySize]">CurArraySize</Item>
+ <IndexListItems>
+ <Size>CurArraySize + 1</Size>
+ <ValueNode>($T1*)&amp;CurArray[$i]</ValueNode>
+ </IndexListItems>
+ </Expand>
+ </Type>
+
+ <Type Name="llvm::DenseMap&lt;*,*,*&gt;">
+ <DisplayString Condition="NumEntries == 0">empty</DisplayString>
+ <DisplayString Condition="NumEntries != 0">{{ entries={NumEntries}, buckets={NumBuckets} }}</DisplayString>
+ <Expand>
+ <Item Name="[NumEntries]">NumEntries</Item>
+ <Item Name="[NumBuckets]">NumBuckets</Item>
+ <ArrayItems>
+ <Size>NumBuckets</Size>
+ <ValuePointer>Buckets</ValuePointer>
+ </ArrayItems>
+ </Expand>
+ </Type>
+
+ <Type Name="llvm::StringMap&lt;*,*&gt;">
+ <DisplayString>{{ NumBuckets={NumBuckets}, ItemSize={ItemSize} }}</DisplayString>
+ <Expand>
+ <Item Name="[NumBuckets]">NumBuckets</Item>
+ <Item Name="[ItemSize]">ItemSize</Item>
+ <IndexListItems>
+ <Size>NumBuckets</Size>
+ <ValueNode>(llvm::StringMapEntry&lt;$T1&gt;*)TheTable[$i]</ValueNode>
+ </IndexListItems>
+ </Expand>
+ </Type>
+
+ <Type Name="llvm::StringMapEntry&lt;*&gt;">
+ <DisplayString Condition="StrLen == 0">empty</DisplayString>
+ <DisplayString Condition="StrLen != 0">({((llvm::StringMapEntry&lt;$T1&gt;*)this)+1,s}, {second})</DisplayString>
+ <Expand>
+ <Item Name="[key]">((llvm::StringMapEntry&lt;$T1&gt;*)this)+1,s</Item>
+ <Item Name="[value]" Condition="StrLen != 0">second</Item>
+ </Expand>
+ </Type>
+
+ <Type Name="llvm::Triple">
+ <DisplayString>{Data}</DisplayString>
+ </Type>
+</AutoVisualizer>
diff --git a/utils/obj2yaml/CMakeLists.txt b/utils/obj2yaml/CMakeLists.txt
deleted file mode 100644
index d64bf1b..0000000
--- a/utils/obj2yaml/CMakeLists.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-set(LLVM_LINK_COMPONENTS archive object)
-
-add_llvm_utility(obj2yaml
- obj2yaml.cpp coff2yaml.cpp
- )
-
-target_link_libraries(obj2yaml LLVMSupport)
diff --git a/utils/obj2yaml/Makefile b/utils/obj2yaml/Makefile
deleted file mode 100644
index 5b96bdd..0000000
--- a/utils/obj2yaml/Makefile
+++ /dev/null
@@ -1,20 +0,0 @@
-##===- utils/obj2yaml/Makefile ----------------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-LEVEL = ../..
-TOOLNAME = obj2yaml
-USEDLIBS = LLVMObject.a LLVMSupport.a
-
-# This tool has no plugins, optimize startup time.
-TOOL_NO_EXPORTS = 1
-
-# Don't install this utility
-NO_INSTALL = 1
-
-include $(LEVEL)/Makefile.common
diff --git a/utils/obj2yaml/coff2yaml.cpp b/utils/obj2yaml/coff2yaml.cpp
deleted file mode 100644
index c9a7159..0000000
--- a/utils/obj2yaml/coff2yaml.cpp
+++ /dev/null
@@ -1,362 +0,0 @@
-//===------ utils/obj2yaml.cpp - obj2yaml conversion tool -------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "obj2yaml.h"
-
-#include "llvm/Object/COFF.h"
-
-
-template <typename One, typename Two>
-struct pod_pair { // I'd much rather use std::pair, but it's not a POD
- One first;
- Two second;
-};
-
-#define STRING_PAIR(x) {llvm::COFF::x, #x}
-static const pod_pair<llvm::COFF::MachineTypes, const char *>
-MachineTypePairs [] = {
- STRING_PAIR(IMAGE_FILE_MACHINE_UNKNOWN),
- STRING_PAIR(IMAGE_FILE_MACHINE_AM33),
- STRING_PAIR(IMAGE_FILE_MACHINE_AMD64),
- STRING_PAIR(IMAGE_FILE_MACHINE_ARM),
- STRING_PAIR(IMAGE_FILE_MACHINE_ARMV7),
- STRING_PAIR(IMAGE_FILE_MACHINE_EBC),
- STRING_PAIR(IMAGE_FILE_MACHINE_I386),
- STRING_PAIR(IMAGE_FILE_MACHINE_IA64),
- STRING_PAIR(IMAGE_FILE_MACHINE_M32R),
- STRING_PAIR(IMAGE_FILE_MACHINE_MIPS16),
- STRING_PAIR(IMAGE_FILE_MACHINE_MIPSFPU),
- STRING_PAIR(IMAGE_FILE_MACHINE_MIPSFPU16),
- STRING_PAIR(IMAGE_FILE_MACHINE_POWERPC),
- STRING_PAIR(IMAGE_FILE_MACHINE_POWERPCFP),
- STRING_PAIR(IMAGE_FILE_MACHINE_R4000),
- STRING_PAIR(IMAGE_FILE_MACHINE_SH3),
- STRING_PAIR(IMAGE_FILE_MACHINE_SH3DSP),
- STRING_PAIR(IMAGE_FILE_MACHINE_SH4),
- STRING_PAIR(IMAGE_FILE_MACHINE_SH5),
- STRING_PAIR(IMAGE_FILE_MACHINE_THUMB),
- STRING_PAIR(IMAGE_FILE_MACHINE_WCEMIPSV2)
-};
-
-static const pod_pair<llvm::COFF::SectionCharacteristics, const char *>
-SectionCharacteristicsPairs1 [] = {
- STRING_PAIR(IMAGE_SCN_TYPE_NO_PAD),
- STRING_PAIR(IMAGE_SCN_CNT_CODE),
- STRING_PAIR(IMAGE_SCN_CNT_INITIALIZED_DATA),
- STRING_PAIR(IMAGE_SCN_CNT_UNINITIALIZED_DATA),
- STRING_PAIR(IMAGE_SCN_LNK_OTHER),
- STRING_PAIR(IMAGE_SCN_LNK_INFO),
- STRING_PAIR(IMAGE_SCN_LNK_REMOVE),
- STRING_PAIR(IMAGE_SCN_LNK_COMDAT),
- STRING_PAIR(IMAGE_SCN_GPREL),
- STRING_PAIR(IMAGE_SCN_MEM_PURGEABLE),
- STRING_PAIR(IMAGE_SCN_MEM_16BIT),
- STRING_PAIR(IMAGE_SCN_MEM_LOCKED),
- STRING_PAIR(IMAGE_SCN_MEM_PRELOAD)
-};
-
-static const pod_pair<llvm::COFF::SectionCharacteristics, const char *>
-SectionCharacteristicsPairsAlignment [] = {
- STRING_PAIR(IMAGE_SCN_ALIGN_1BYTES),
- STRING_PAIR(IMAGE_SCN_ALIGN_2BYTES),
- STRING_PAIR(IMAGE_SCN_ALIGN_4BYTES),
- STRING_PAIR(IMAGE_SCN_ALIGN_8BYTES),
- STRING_PAIR(IMAGE_SCN_ALIGN_16BYTES),
- STRING_PAIR(IMAGE_SCN_ALIGN_32BYTES),
- STRING_PAIR(IMAGE_SCN_ALIGN_64BYTES),
- STRING_PAIR(IMAGE_SCN_ALIGN_128BYTES),
- STRING_PAIR(IMAGE_SCN_ALIGN_256BYTES),
- STRING_PAIR(IMAGE_SCN_ALIGN_512BYTES),
- STRING_PAIR(IMAGE_SCN_ALIGN_1024BYTES),
- STRING_PAIR(IMAGE_SCN_ALIGN_2048BYTES),
- STRING_PAIR(IMAGE_SCN_ALIGN_4096BYTES),
- STRING_PAIR(IMAGE_SCN_ALIGN_8192BYTES)
-};
-
-static const pod_pair<llvm::COFF::SectionCharacteristics, const char *>
-SectionCharacteristicsPairs2 [] = {
- STRING_PAIR(IMAGE_SCN_LNK_NRELOC_OVFL),
- STRING_PAIR(IMAGE_SCN_MEM_DISCARDABLE),
- STRING_PAIR(IMAGE_SCN_MEM_NOT_CACHED),
- STRING_PAIR(IMAGE_SCN_MEM_NOT_PAGED),
- STRING_PAIR(IMAGE_SCN_MEM_SHARED),
- STRING_PAIR(IMAGE_SCN_MEM_EXECUTE),
- STRING_PAIR(IMAGE_SCN_MEM_READ),
- STRING_PAIR(IMAGE_SCN_MEM_WRITE)
-};
-
-static const pod_pair<llvm::COFF::SymbolBaseType, const char *>
-SymbolBaseTypePairs [] = {
- STRING_PAIR(IMAGE_SYM_TYPE_NULL),
- STRING_PAIR(IMAGE_SYM_TYPE_VOID),
- STRING_PAIR(IMAGE_SYM_TYPE_CHAR),
- STRING_PAIR(IMAGE_SYM_TYPE_SHORT),
- STRING_PAIR(IMAGE_SYM_TYPE_INT),
- STRING_PAIR(IMAGE_SYM_TYPE_LONG),
- STRING_PAIR(IMAGE_SYM_TYPE_FLOAT),
- STRING_PAIR(IMAGE_SYM_TYPE_DOUBLE),
- STRING_PAIR(IMAGE_SYM_TYPE_STRUCT),
- STRING_PAIR(IMAGE_SYM_TYPE_UNION),
- STRING_PAIR(IMAGE_SYM_TYPE_ENUM),
- STRING_PAIR(IMAGE_SYM_TYPE_MOE),
- STRING_PAIR(IMAGE_SYM_TYPE_BYTE),
- STRING_PAIR(IMAGE_SYM_TYPE_WORD),
- STRING_PAIR(IMAGE_SYM_TYPE_UINT),
- STRING_PAIR(IMAGE_SYM_TYPE_DWORD)
-};
-
-static const pod_pair<llvm::COFF::SymbolComplexType, const char *>
-SymbolComplexTypePairs [] = {
- STRING_PAIR(IMAGE_SYM_DTYPE_NULL),
- STRING_PAIR(IMAGE_SYM_DTYPE_POINTER),
- STRING_PAIR(IMAGE_SYM_DTYPE_FUNCTION),
- STRING_PAIR(IMAGE_SYM_DTYPE_ARRAY),
-};
-
-static const pod_pair<llvm::COFF::SymbolStorageClass, const char *>
-SymbolStorageClassPairs [] = {
- STRING_PAIR(IMAGE_SYM_CLASS_END_OF_FUNCTION),
- STRING_PAIR(IMAGE_SYM_CLASS_NULL),
- STRING_PAIR(IMAGE_SYM_CLASS_AUTOMATIC),
- STRING_PAIR(IMAGE_SYM_CLASS_EXTERNAL),
- STRING_PAIR(IMAGE_SYM_CLASS_STATIC),
- STRING_PAIR(IMAGE_SYM_CLASS_REGISTER),
- STRING_PAIR(IMAGE_SYM_CLASS_EXTERNAL_DEF),
- STRING_PAIR(IMAGE_SYM_CLASS_LABEL),
- STRING_PAIR(IMAGE_SYM_CLASS_UNDEFINED_LABEL),
- STRING_PAIR(IMAGE_SYM_CLASS_MEMBER_OF_STRUCT),
- STRING_PAIR(IMAGE_SYM_CLASS_ARGUMENT),
- STRING_PAIR(IMAGE_SYM_CLASS_STRUCT_TAG),
- STRING_PAIR(IMAGE_SYM_CLASS_MEMBER_OF_UNION),
- STRING_PAIR(IMAGE_SYM_CLASS_UNION_TAG),
- STRING_PAIR(IMAGE_SYM_CLASS_TYPE_DEFINITION),
- STRING_PAIR(IMAGE_SYM_CLASS_UNDEFINED_STATIC),
- STRING_PAIR(IMAGE_SYM_CLASS_ENUM_TAG),
- STRING_PAIR(IMAGE_SYM_CLASS_MEMBER_OF_ENUM),
- STRING_PAIR(IMAGE_SYM_CLASS_REGISTER_PARAM),
- STRING_PAIR(IMAGE_SYM_CLASS_BIT_FIELD),
- STRING_PAIR(IMAGE_SYM_CLASS_BLOCK),
- STRING_PAIR(IMAGE_SYM_CLASS_FUNCTION),
- STRING_PAIR(IMAGE_SYM_CLASS_END_OF_STRUCT),
- STRING_PAIR(IMAGE_SYM_CLASS_FILE),
- STRING_PAIR(IMAGE_SYM_CLASS_SECTION),
- STRING_PAIR(IMAGE_SYM_CLASS_WEAK_EXTERNAL),
- STRING_PAIR(IMAGE_SYM_CLASS_CLR_TOKEN),
-};
-
-static const pod_pair<llvm::COFF::RelocationTypeX86, const char *>
-RelocationTypeX86Pairs [] = {
- STRING_PAIR(IMAGE_REL_I386_ABSOLUTE),
- STRING_PAIR(IMAGE_REL_I386_DIR16),
- STRING_PAIR(IMAGE_REL_I386_REL16),
- STRING_PAIR(IMAGE_REL_I386_DIR32),
- STRING_PAIR(IMAGE_REL_I386_DIR32NB),
- STRING_PAIR(IMAGE_REL_I386_SEG12),
- STRING_PAIR(IMAGE_REL_I386_SECTION),
- STRING_PAIR(IMAGE_REL_I386_SECREL),
- STRING_PAIR(IMAGE_REL_I386_TOKEN),
- STRING_PAIR(IMAGE_REL_I386_SECREL7),
- STRING_PAIR(IMAGE_REL_I386_REL32),
- STRING_PAIR(IMAGE_REL_AMD64_ABSOLUTE),
- STRING_PAIR(IMAGE_REL_AMD64_ADDR64),
- STRING_PAIR(IMAGE_REL_AMD64_ADDR32),
- STRING_PAIR(IMAGE_REL_AMD64_ADDR32NB),
- STRING_PAIR(IMAGE_REL_AMD64_REL32),
- STRING_PAIR(IMAGE_REL_AMD64_REL32_1),
- STRING_PAIR(IMAGE_REL_AMD64_REL32_2),
- STRING_PAIR(IMAGE_REL_AMD64_REL32_3),
- STRING_PAIR(IMAGE_REL_AMD64_REL32_4),
- STRING_PAIR(IMAGE_REL_AMD64_REL32_5),
- STRING_PAIR(IMAGE_REL_AMD64_SECTION),
- STRING_PAIR(IMAGE_REL_AMD64_SECREL),
- STRING_PAIR(IMAGE_REL_AMD64_SECREL7),
- STRING_PAIR(IMAGE_REL_AMD64_TOKEN),
- STRING_PAIR(IMAGE_REL_AMD64_SREL32),
- STRING_PAIR(IMAGE_REL_AMD64_PAIR),
- STRING_PAIR(IMAGE_REL_AMD64_SSPAN32)
-};
-
-static const pod_pair<llvm::COFF::RelocationTypesARM, const char *>
-RelocationTypesARMPairs [] = {
- STRING_PAIR(IMAGE_REL_ARM_ABSOLUTE),
- STRING_PAIR(IMAGE_REL_ARM_ADDR32),
- STRING_PAIR(IMAGE_REL_ARM_ADDR32NB),
- STRING_PAIR(IMAGE_REL_ARM_BRANCH24),
- STRING_PAIR(IMAGE_REL_ARM_BRANCH11),
- STRING_PAIR(IMAGE_REL_ARM_TOKEN),
- STRING_PAIR(IMAGE_REL_ARM_BLX24),
- STRING_PAIR(IMAGE_REL_ARM_BLX11),
- STRING_PAIR(IMAGE_REL_ARM_SECTION),
- STRING_PAIR(IMAGE_REL_ARM_SECREL),
- STRING_PAIR(IMAGE_REL_ARM_MOV32A),
- STRING_PAIR(IMAGE_REL_ARM_MOV32T),
- STRING_PAIR(IMAGE_REL_ARM_BRANCH20T),
- STRING_PAIR(IMAGE_REL_ARM_BRANCH24T),
- STRING_PAIR(IMAGE_REL_ARM_BLX23T)
-};
-#undef STRING_PAIR
-
-
-static const char endl = '\n';
-
-namespace yaml { // COFF-specific yaml-writing specific routines
-
-static llvm::raw_ostream &writeName(llvm::raw_ostream &Out,
- const char *Name, std::size_t NameSize) {
- for (std::size_t i = 0; i < NameSize; ++i) {
- if (!Name[i]) break;
- Out << Name[i];
- }
- return Out;
-}
-
-// Given an array of pod_pair<enum, const char *>, write all enums that match
-template <typename T, std::size_t N>
-static llvm::raw_ostream &writeBitMask(llvm::raw_ostream &Out,
- const pod_pair<T, const char *> (&Arr)[N], unsigned long Val) {
- for (std::size_t i = 0; i < N; ++i)
- if (Val & Arr[i].first)
- Out << Arr[i].second << ", ";
- return Out;
-}
-
-} // end of yaml namespace
-
-// Given an array of pod_pair<enum, const char *>, look up a value
-template <typename T, std::size_t N>
-const char *nameLookup(const pod_pair<T, const char *> (&Arr)[N],
- unsigned long Val, const char *NotFound = NULL) {
- T n = static_cast<T>(Val);
- for (std::size_t i = 0; i < N; ++i)
- if (n == Arr[i].first)
- return Arr[i].second;
- return NotFound;
-}
-
-
-static llvm::raw_ostream &yamlCOFFHeader(
- const llvm::object::coff_file_header *Header,llvm::raw_ostream &Out) {
-
- Out << "header: !Header" << endl;
- Out << " Machine: ";
- Out << nameLookup(MachineTypePairs, Header->Machine, "# Unknown_MachineTypes")
- << " # (";
- return yaml::writeHexNumber(Out, Header->Machine) << ")" << endl << endl;
-}
-
-
-static llvm::raw_ostream &yamlCOFFSections(llvm::object::COFFObjectFile &Obj,
- std::size_t NumSections, llvm::raw_ostream &Out) {
- llvm::error_code ec;
- Out << "sections:" << endl;
- for (llvm::object::section_iterator iter = Obj.begin_sections();
- iter != Obj.end_sections(); iter.increment(ec)) {
- const llvm::object::coff_section *sect = Obj.getCOFFSection(iter);
-
- Out << " - !Section" << endl;
- Out << " Name: ";
- yaml::writeName(Out, sect->Name, sizeof(sect->Name)) << endl;
-
- Out << " Characteristics: [";
- yaml::writeBitMask(Out, SectionCharacteristicsPairs1, sect->Characteristics);
- Out << nameLookup(SectionCharacteristicsPairsAlignment,
- sect->Characteristics & 0x00F00000, "# Unrecognized_IMAGE_SCN_ALIGN")
- << ", ";
- yaml::writeBitMask(Out, SectionCharacteristicsPairs2, sect->Characteristics);
- Out << "] # ";
- yaml::writeHexNumber(Out, sect->Characteristics) << endl;
-
- llvm::ArrayRef<uint8_t> sectionData;
- Obj.getSectionContents(sect, sectionData);
- Out << " SectionData: ";
- yaml::writeHexStream(Out, sectionData) << endl;
- if (iter->begin_relocations() != iter->end_relocations())
- Out << " Relocations:\n";
- for (llvm::object::relocation_iterator rIter = iter->begin_relocations();
- rIter != iter->end_relocations(); rIter.increment(ec)) {
- const llvm::object::coff_relocation *reloc = Obj.getCOFFRelocation(rIter);
-
- Out << " - !Relocation" << endl;
- Out << " VirtualAddress: " ;
- yaml::writeHexNumber(Out, reloc->VirtualAddress) << endl;
- Out << " SymbolTableIndex: " << reloc->SymbolTableIndex << endl;
- Out << " Type: "
- << nameLookup(RelocationTypeX86Pairs, reloc->Type) << endl;
- // TODO: Use the correct reloc type for the machine.
- Out << endl;
- }
-
- }
- return Out;
-}
-
-static llvm::raw_ostream& yamlCOFFSymbols(llvm::object::COFFObjectFile &Obj,
- std::size_t NumSymbols, llvm::raw_ostream &Out) {
- llvm::error_code ec;
- Out << "symbols:" << endl;
- for (llvm::object::symbol_iterator iter = Obj.begin_symbols();
- iter != Obj.end_symbols(); iter.increment(ec)) {
- // Gather all the info that we need
- llvm::StringRef str;
- const llvm::object::coff_symbol *symbol = Obj.getCOFFSymbol(iter);
- Obj.getSymbolName(symbol, str);
- std::size_t simpleType = symbol->getBaseType();
- std::size_t complexType = symbol->getComplexType();
- std::size_t storageClass = symbol->StorageClass;
-
- Out << " - !Symbol" << endl;
- Out << " Name: " << str << endl;
-
- Out << " Value: " << symbol->Value << endl;
- Out << " SectionNumber: " << symbol->SectionNumber << endl;
-
- Out << " SimpleType: "
- << nameLookup(SymbolBaseTypePairs, simpleType,
- "# Unknown_SymbolBaseType")
- << " # (" << simpleType << ")" << endl;
-
- Out << " ComplexType: "
- << nameLookup(SymbolComplexTypePairs, complexType,
- "# Unknown_SymbolComplexType")
- << " # (" << complexType << ")" << endl;
-
- Out << " StorageClass: "
- << nameLookup(SymbolStorageClassPairs, storageClass,
- "# Unknown_StorageClass")
- << " # (" << (int) storageClass << ")" << endl;
-
- if (symbol->NumberOfAuxSymbols > 0) {
- llvm::ArrayRef<uint8_t> aux = Obj.getSymbolAuxData(symbol);
- Out << " NumberOfAuxSymbols: "
- << (int) symbol->NumberOfAuxSymbols << endl;
- Out << " AuxillaryData: ";
- yaml::writeHexStream(Out, aux);
- }
-
- Out << endl;
- }
-
- return Out;
-}
-
-
-llvm::error_code coff2yaml(llvm::raw_ostream &Out, llvm::MemoryBuffer *TheObj) {
- llvm::error_code ec;
- llvm::object::COFFObjectFile obj(TheObj, ec);
- if (!ec) {
- const llvm::object::coff_file_header *hd;
- ec = obj.getHeader(hd);
- if (!ec) {
- yamlCOFFHeader(hd, Out);
- yamlCOFFSections(obj, hd->NumberOfSections, Out);
- yamlCOFFSymbols(obj, hd->NumberOfSymbols, Out);
- }
- }
- return ec;
-}
diff --git a/utils/obj2yaml/obj2yaml.cpp b/utils/obj2yaml/obj2yaml.cpp
deleted file mode 100644
index ff253fa..0000000
--- a/utils/obj2yaml/obj2yaml.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-//===------ utils/obj2yaml.cpp - obj2yaml conversion tool -------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "obj2yaml.h"
-
-#include "llvm/ADT/OwningPtr.h"
-
-#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/ManagedStatic.h"
-#include "llvm/Support/PrettyStackTrace.h"
-#include "llvm/Support/Signals.h"
-
-#include "llvm/Object/Archive.h"
-#include "llvm/Object/COFF.h"
-
-const char endl = '\n';
-
-namespace yaml { // generic yaml-writing specific routines
-
-unsigned char printable(unsigned char Ch) {
- return Ch >= ' ' && Ch <= '~' ? Ch : '.';
-}
-
-llvm::raw_ostream &writeHexStream(llvm::raw_ostream &Out,
- const llvm::ArrayRef<uint8_t> arr) {
- const char *hex = "0123456789ABCDEF";
- Out << " !hex \"";
-
- typedef llvm::ArrayRef<uint8_t>::const_iterator iter_t;
- const iter_t end = arr.end();
- for (iter_t iter = arr.begin(); iter != end; ++iter)
- Out << hex[(*iter >> 4) & 0x0F] << hex[(*iter & 0x0F)];
-
- Out << "\" # |";
- for (iter_t iter = arr.begin(); iter != end; ++iter)
- Out << printable(*iter);
- Out << "|" << endl;
-
- return Out;
- }
-
-llvm::raw_ostream &writeHexNumber(llvm::raw_ostream &Out, unsigned long long N) {
- if (N >= 10)
- Out << "0x";
- Out.write_hex(N);
- return Out;
-}
-
-}
-
-
-using namespace llvm;
-enum ObjectFileType { coff };
-
-cl::opt<ObjectFileType> InputFormat(
- cl::desc("Choose input format"),
- cl::values(
- clEnumVal(coff, "process COFF object files"),
- clEnumValEnd));
-
-cl::opt<std::string> InputFilename(cl::Positional, cl::desc("<input file>"), cl::init("-"));
-
-int main(int argc, char * argv[]) {
- cl::ParseCommandLineOptions(argc, argv);
- sys::PrintStackTraceOnErrorSignal();
- PrettyStackTraceProgram X(argc, argv);
- llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
-
-// Process the input file
- OwningPtr<MemoryBuffer> buf;
-
-// TODO: If this is an archive, then burst it and dump each entry
- if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFilename, buf))
- llvm::errs() << "Error: '" << ec.message() << "' opening file '"
- << InputFilename << "'" << endl;
- else {
- ec = coff2yaml(llvm::outs(), buf.take());
- if (ec)
- llvm::errs() << "Error: " << ec.message() << " dumping COFF file" << endl;
- }
-
- return 0;
-}
diff --git a/utils/obj2yaml/obj2yaml.h b/utils/obj2yaml/obj2yaml.h
deleted file mode 100644
index 2a23b49..0000000
--- a/utils/obj2yaml/obj2yaml.h
+++ /dev/null
@@ -1,35 +0,0 @@
-//===------ utils/obj2yaml.hpp - obj2yaml conversion tool -------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-// This file declares some helper routines, and also the format-specific
-// writers. To add a new format, add the declaration here, and, in a separate
-// source file, implement it.
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_UTILS_OBJ2YAML_H
-#define LLVM_UTILS_OBJ2YAML_H
-
-#include "llvm/ADT/ArrayRef.h"
-
-#include "llvm/Support/system_error.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/MemoryBuffer.h"
-
-namespace yaml { // routines for writing YAML
-// Write a hex stream:
-// <Prefix> !hex: "<hex digits>" #|<ASCII chars>\n
- llvm::raw_ostream &writeHexStream
- (llvm::raw_ostream &Out, const llvm::ArrayRef<uint8_t> arr);
-
-// Writes a number in hex; prefix it by 0x if it is >= 10
- llvm::raw_ostream &writeHexNumber
- (llvm::raw_ostream &Out, unsigned long long N);
-}
-
-llvm::error_code coff2yaml(llvm::raw_ostream &Out, llvm::MemoryBuffer *TheObj);
-
-#endif
diff --git a/utils/sort_includes.py b/utils/sort_includes.py
new file mode 100755
index 0000000..fef9755
--- /dev/null
+++ b/utils/sort_includes.py
@@ -0,0 +1,87 @@
+#!/usr/bin/env python
+
+"""Script to sort the top-most block of #include lines.
+
+Assumes the LLVM coding conventions.
+
+Currently, this script only bothers sorting the llvm/... headers. Patches
+welcome for more functionality, and sorting other header groups.
+"""
+
+import argparse
+import os
+
+def sort_includes(f):
+ """Sort the #include lines of a specific file."""
+
+ # Skip files which are under INPUTS trees or test trees.
+ if 'INPUTS/' in f.name or 'test/' in f.name:
+ return
+
+ ext = os.path.splitext(f.name)[1]
+ if ext not in ['.cpp', '.c', '.h', '.inc', '.def']:
+ return
+
+ lines = f.readlines()
+ look_for_api_header = ext in ['.cpp', '.c']
+ found_headers = False
+ headers_begin = 0
+ headers_end = 0
+ api_headers = []
+ local_headers = []
+ project_headers = []
+ system_headers = []
+ for (i, l) in enumerate(lines):
+ if l.strip() == '':
+ continue
+ if l.startswith('#include'):
+ if not found_headers:
+ headers_begin = i
+ found_headers = True
+ headers_end = i
+ header = l[len('#include'):].lstrip()
+ if look_for_api_header and header.startswith('"'):
+ api_headers.append(header)
+ look_for_api_header = False
+ continue
+ if header.startswith('<') or header.startswith('"gtest/'):
+ system_headers.append(header)
+ continue
+ if (header.startswith('"llvm/') or header.startswith('"llvm-c/') or
+ header.startswith('"clang/') or header.startswith('"clang-c/')):
+ project_headers.append(header)
+ continue
+ local_headers.append(header)
+ continue
+
+ # Only allow comments and #defines prior to any includes. If either are
+ # mixed with includes, the order might be sensitive.
+ if found_headers:
+ break
+ if l.startswith('//') or l.startswith('#define') or l.startswith('#ifndef'):
+ continue
+ break
+ if not found_headers:
+ return
+
+ local_headers = sorted(set(local_headers))
+ project_headers = sorted(set(project_headers))
+ system_headers = sorted(set(system_headers))
+ headers = api_headers + local_headers + project_headers + system_headers
+ header_lines = ['#include ' + h for h in headers]
+ lines = lines[:headers_begin] + header_lines + lines[headers_end + 1:]
+
+ f.seek(0)
+ f.truncate()
+ f.writelines(lines)
+
+def main():
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument('files', nargs='+', type=argparse.FileType('r+'),
+ help='the source files to sort includes within')
+ args = parser.parse_args()
+ for f in args.files:
+ sort_includes(f)
+
+if __name__ == '__main__':
+ main()
diff --git a/utils/testgen/mc-bundling-x86-gen.py b/utils/testgen/mc-bundling-x86-gen.py
new file mode 100644
index 0000000..5c1c6c4
--- /dev/null
+++ b/utils/testgen/mc-bundling-x86-gen.py
@@ -0,0 +1,103 @@
+
+#!/usr/bin/python
+
+# Auto-generates an exhaustive and repetitive test for correct bundle-locked
+# alignment on x86.
+# For every possible offset in an aligned bundle, a bundle-locked group of every
+# size in the inclusive range [1, bundle_size] is inserted. An appropriate CHECK
+# is added to verify that NOP padding occurred (or did not occur) as expected.
+# Run with --align-to-end to generate a similar test with align_to_end for each
+# .bundle_lock directive.
+
+# This script runs with Python 2.7 and 3.2+
+
+from __future__ import print_function
+import argparse
+
+BUNDLE_SIZE_POW2 = 4
+BUNDLE_SIZE = 2 ** BUNDLE_SIZE_POW2
+
+PREAMBLE = '''
+# RUN: llvm-mc -filetype=obj -triple i386-pc-linux-gnu %s -o - \\
+# RUN: | llvm-objdump -triple i386 -disassemble -no-show-raw-insn - | FileCheck %s
+
+# !!! This test is auto-generated from utils/testgen/mc-bundling-x86-gen.py !!!
+# It tests that bundle-aligned grouping works correctly in MC. Read the
+# source of the script for more details.
+
+ .text
+ .bundle_align_mode {0}
+'''.format(BUNDLE_SIZE_POW2).lstrip()
+
+ALIGNTO = ' .align {0}, 0x90'
+NOPFILL = ' .fill {0}, 1, 0x90'
+
+def print_bundle_locked_sequence(len, align_to_end=False):
+ print(' .bundle_lock{0}'.format(' align_to_end' if align_to_end else ''))
+ print(' .rept {0}'.format(len))
+ print(' inc %eax')
+ print(' .endr')
+ print(' .bundle_unlock')
+
+def generate(align_to_end=False):
+ print(PREAMBLE)
+
+ ntest = 0
+ for instlen in range(1, BUNDLE_SIZE + 1):
+ for offset in range(0, BUNDLE_SIZE):
+ # Spread out all the instructions to not worry about cross-bundle
+ # interference.
+ print(ALIGNTO.format(2 * BUNDLE_SIZE))
+ print('INSTRLEN_{0}_OFFSET_{1}:'.format(instlen, offset))
+ if offset > 0:
+ print(NOPFILL.format(offset))
+ print_bundle_locked_sequence(instlen, align_to_end)
+
+ # Now generate an appropriate CHECK line
+ base_offset = ntest * 2 * BUNDLE_SIZE
+ inst_orig_offset = base_offset + offset # had it not been padded...
+
+ def print_check(adjusted_offset=None, nop_split_offset=None):
+ if adjusted_offset is not None:
+ print('# CHECK: {0:x}: nop'.format(inst_orig_offset))
+ if nop_split_offset is not None:
+ print('# CHECK: {0:x}: nop'.format(nop_split_offset))
+ print('# CHECK: {0:x}: incl'.format(adjusted_offset))
+ else:
+ print('# CHECK: {0:x}: incl'.format(inst_orig_offset))
+
+ if align_to_end:
+ if offset + instlen == BUNDLE_SIZE:
+ # No padding needed
+ print_check()
+ elif offset + instlen < BUNDLE_SIZE:
+ # Pad to end at nearest bundle boundary
+ offset_to_end = base_offset + (BUNDLE_SIZE - instlen)
+ print_check(offset_to_end)
+ else: # offset + instlen > BUNDLE_SIZE
+ # Pad to end at next bundle boundary, splitting the nop sequence
+ # at the nearest bundle boundary
+ offset_to_nearest_bundle = base_offset + BUNDLE_SIZE
+ offset_to_end = base_offset + (BUNDLE_SIZE * 2 - instlen)
+ if offset_to_nearest_bundle == offset_to_end:
+ offset_to_nearest_bundle = None
+ print_check(offset_to_end, offset_to_nearest_bundle)
+ else:
+ if offset + instlen > BUNDLE_SIZE:
+ # Padding needed
+ aligned_offset = (inst_orig_offset + instlen) & ~(BUNDLE_SIZE - 1)
+ print_check(aligned_offset)
+ else:
+ # No padding needed
+ print_check()
+
+ print()
+ ntest += 1
+
+if __name__ == '__main__':
+ argparser = argparse.ArgumentParser()
+ argparser.add_argument('--align-to-end',
+ action='store_true',
+ help='generate .bundle_lock with align_to_end option')
+ args = argparser.parse_args()
+ generate(align_to_end=args.align_to_end)
diff --git a/utils/textmate/README b/utils/textmate/README
new file mode 100644
index 0000000..b013525
--- /dev/null
+++ b/utils/textmate/README
@@ -0,0 +1,8 @@
+This directory contains a "bundle" for doing syntax highlighting of TableGen
+files for the TextMate editor for OS X. The highlighting follows that done
+by the TextMate "C" bundle. Currently, keywords, comments, and strings are
+highlighted.
+
+To install this bundle, copy it to the per user area:
+ cp -R utils/textmate/TableGen.tmbundle \
+ ~/Library/Application\ Support/TextMate/Bundles/TableGen.tmbundle
diff --git a/utils/textmate/TableGen.tmbundle/Syntaxes/TableGen.tmLanguage b/utils/textmate/TableGen.tmbundle/Syntaxes/TableGen.tmLanguage
new file mode 100644
index 0000000..f3cf2d6
--- /dev/null
+++ b/utils/textmate/TableGen.tmbundle/Syntaxes/TableGen.tmLanguage
@@ -0,0 +1,132 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>fileTypes</key>
+ <array><string>td</string></array>
+ <key>foldingStartMarker</key>
+ <string>/\*\*|\{\s*$</string>
+ <key>foldingStopMarker</key>
+ <string>\*\*/|^\s*\}</string>
+ <key>name</key>
+ <string>TableGen</string>
+ <key>patterns</key>
+ <array>
+ <dict>
+ <key>include</key>
+ <string>#comments</string>
+ </dict>
+ <dict>
+ <key>match</key>
+ <string>\b(def|let|in|code|dag|string|list|bits|bit|field|include|defm|foreach|class|multiclass|int)\b</string>
+ <key>name</key>
+ <string>keyword.control.tablegen</string>
+ </dict>
+ <dict>
+ <key>begin</key>
+ <string>"</string>
+ <key>end</key>
+ <string>"</string>
+ <key>name</key>
+ <string>string.quoted.double.untitled</string>
+ <key>patterns</key>
+ <array>
+ <dict>
+ <key>match</key>
+ <string>\\.</string>
+ <key>name</key>
+ <string>constant.character.escape.tablegen</string>
+ </dict>
+ </array>
+ </dict>
+ </array>
+ <key>repository</key>
+ <dict>
+ <key>comments</key>
+ <dict>
+ <key>patterns</key>
+ <array>
+ <dict>
+ <key>captures</key>
+ <dict>
+ <key>1</key>
+ <dict>
+ <key>name</key>
+ <string>meta.toc-list.banner.block.tablegen</string>
+ </dict>
+ </dict>
+ <key>match</key>
+ <string>^/\* =(\s*.*?)\s*= \*/$\n?</string>
+ <key>name</key>
+ <string>comment.block.tablegen</string>
+ </dict>
+ <dict>
+ <key>begin</key>
+ <string>/\*</string>
+ <key>captures</key>
+ <dict>
+ <key>0</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.comment.tablegen</string>
+ </dict>
+ </dict>
+ <key>end</key>
+ <string>\*/</string>
+ <key>name</key>
+ <string>comment.block.tablegen</string>
+ </dict>
+ <dict>
+ <key>match</key>
+ <string>\*/.*\n</string>
+ <key>name</key>
+ <string>invalid.illegal.stray-comment-end.tablegen</string>
+ </dict>
+ <dict>
+ <key>captures</key>
+ <dict>
+ <key>1</key>
+ <dict>
+ <key>name</key>
+ <string>meta.toc-list.banner.line.tablegen</string>
+ </dict>
+ </dict>
+ <key>match</key>
+ <string>^// =(\s*.*?)\s*=\s*$\n?</string>
+ <key>name</key>
+ <string>comment.line.banner.tablegen</string>
+ </dict>
+ <dict>
+ <key>begin</key>
+ <string>//</string>
+ <key>beginCaptures</key>
+ <dict>
+ <key>0</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.comment.tablegen</string>
+ </dict>
+ </dict>
+ <key>end</key>
+ <string>$\n?</string>
+ <key>name</key>
+ <string>comment.line.double-slash.tablegen</string>
+ <key>patterns</key>
+ <array>
+ <dict>
+ <key>match</key>
+ <string>(?&gt;\\\s*\n)</string>
+ <key>name</key>
+ <string>punctuation.separator.continuation.tablegen</string>
+ </dict>
+ </array>
+ </dict>
+ </array>
+ </dict>
+ </dict>
+ <key>scopeName</key>
+ <string>source.tablegen</string>
+ <key>uuid</key>
+ <string>3A090BFC-E74B-4993-8DAE-7CCF6D238A32</string>
+</dict>
+</plist>
diff --git a/utils/textmate/TableGen.tmbundle/info.plist b/utils/textmate/TableGen.tmbundle/info.plist
new file mode 100644
index 0000000..c2f680a
--- /dev/null
+++ b/utils/textmate/TableGen.tmbundle/info.plist
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>name</key>
+ <string>TableGen</string>
+ <key>ordering</key>
+ <array/>
+ <key>uuid</key>
+ <string>96925448-7219-41E9-A7F0-8D5B70E9B877</string>
+</dict>
+</plist>
diff --git a/utils/unittest/UnitTestMain/TestMain.cpp b/utils/unittest/UnitTestMain/TestMain.cpp
index b35bae5..ce32b73 100644
--- a/utils/unittest/UnitTestMain/TestMain.cpp
+++ b/utils/unittest/UnitTestMain/TestMain.cpp
@@ -8,6 +8,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/Config/config.h"
+#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Signals.h"
#include "gtest/gtest.h"
@@ -22,6 +23,7 @@
int main(int argc, char **argv) {
llvm::sys::PrintStackTraceOnErrorSignal();
testing::InitGoogleTest(&argc, argv);
+ llvm::cl::ParseCommandLineOptions(argc, argv);
# if defined(LLVM_ON_WIN32)
// Disable all of the possible ways Windows conspires to make automated
diff --git a/utils/unittest/googletest/Makefile b/utils/unittest/googletest/Makefile
index 22c8f36..bf73670 100644
--- a/utils/unittest/googletest/Makefile
+++ b/utils/unittest/googletest/Makefile
@@ -36,4 +36,6 @@ endif
NO_INSTALL = 1
+SOURCES = $(filter-out gtest-all.cc, $(notdir $(wildcard $(PROJ_SRC_DIR)/*.cc)))
+
include $(LEVEL)/Makefile.common
diff --git a/utils/unittest/googletest/README.LLVM b/utils/unittest/googletest/README.LLVM
index 51340e9..3565a32 100644
--- a/utils/unittest/googletest/README.LLVM
+++ b/utils/unittest/googletest/README.LLVM
@@ -19,9 +19,10 @@ $ rmdir src
$ 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-all.cc gtest_main.cc
+$ rm -f gtest_main.cc
$ mv COPYING LICENSE.TXT
diff --git a/utils/unittest/googletest/gtest-all.cc b/utils/unittest/googletest/gtest-all.cc
new file mode 100644
index 0000000..97753e5
--- /dev/null
+++ b/utils/unittest/googletest/gtest-all.cc
@@ -0,0 +1,48 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: mheule@google.com (Markus Heule)
+//
+// Google C++ Testing Framework (Google Test)
+//
+// Sometimes it's desirable to build Google Test by compiling a single file.
+// This file serves this purpose.
+
+// This line ensures that gtest.h can be compiled on its own, even
+// when it's fused.
+#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"
diff --git a/utils/unittest/googletest/gtest-filepath.cc b/utils/unittest/googletest/gtest-filepath.cc
index bc61009..ad1bab8 100644
--- a/utils/unittest/googletest/gtest-filepath.cc
+++ b/utils/unittest/googletest/gtest-filepath.cc
@@ -69,7 +69,6 @@ namespace internal {
// of them.
const char kPathSeparator = '\\';
const char kAlternatePathSeparator = '/';
-const char kPathSeparatorString[] = "\\";
const char kAlternatePathSeparatorString[] = "/";
# if GTEST_OS_WINDOWS_MOBILE
// Windows CE doesn't have a current directory. You should not use
@@ -83,7 +82,6 @@ const char kCurrentDirectoryString[] = ".\\";
# endif // GTEST_OS_WINDOWS_MOBILE
#else
const char kPathSeparator = '/';
-const char kPathSeparatorString[] = "/";
const char kCurrentDirectoryString[] = "./";
#endif // GTEST_OS_WINDOWS
diff --git a/utils/unittest/googletest/gtest-printers.cc b/utils/unittest/googletest/gtest-printers.cc
index ed63c7b..205a394 100644
--- a/utils/unittest/googletest/gtest-printers.cc
+++ b/utils/unittest/googletest/gtest-printers.cc
@@ -127,7 +127,7 @@ namespace internal {
// Depending on the value of a char (or wchar_t), we print it in one
// of three formats:
// - as is if it's a printable ASCII (e.g. 'a', '2', ' '),
-// - as a hexidecimal escape sequence (e.g. '\x7F'), or
+// - as a hexadecimal escape sequence (e.g. '\x7F'), or
// - as a special escape sequence (e.g. '\r', '\n').
enum CharFormat {
kAsIs,
@@ -230,7 +230,7 @@ void PrintCharAndCodeTo(Char c, ostream* os) {
return;
*os << " (" << String::Format("%d", c).c_str();
- // For more convenience, we print c's code again in hexidecimal,
+ // For more convenience, we print c's code again in hexadecimal,
// unless c was already printed in the form '\x##' or the code is in
// [1, 9].
if (format == kHexEscape || (1 <= c && c <= 9)) {
diff --git a/utils/unittest/googletest/include/gtest/internal/gtest-internal.h b/utils/unittest/googletest/include/gtest/internal/gtest-internal.h
index f8a5cc9..a94bf28 100644
--- a/utils/unittest/googletest/include/gtest/internal/gtest-internal.h
+++ b/utils/unittest/googletest/include/gtest/internal/gtest-internal.h
@@ -56,7 +56,9 @@
#include "gtest/internal/gtest-filepath.h"
#include "gtest/internal/gtest-type-util.h"
+#if !GTEST_NO_LLVM_RAW_OSTREAM
#include "llvm/Support/raw_os_ostream.h"
+#endif
// Due to C++ preprocessor weirdness, we need double indirection to
// concatenate two tokens when one of them is __LINE__. Writing
@@ -100,6 +102,7 @@
// std::ostream with an implicit conversion to raw_ostream& and stream
// to that. This causes the compiler to prefer std::ostream overloads
// but still find raw_ostream& overloads.
+#if !GTEST_NO_LLVM_RAW_OSTREAM
namespace llvm {
class convertible_fwd_ostream : public std::ostream {
raw_os_ostream ros_;
@@ -115,6 +118,12 @@ inline void GTestStreamToHelper(std::ostream* os, const T& val) {
llvm::convertible_fwd_ostream cos(*os);
cos << val;
}
+#else
+template <typename T>
+inline void GTestStreamToHelper(std::ostream* os, const T& val) {
+ *os << val;
+}
+#endif
class ProtocolMessage;
namespace proto2 { class Message; }
diff --git a/utils/valgrind/x86_64-pc-linux-gnu.supp b/utils/valgrind/x86_64-pc-linux-gnu.supp
index fc863b8..c8e5cd0 100644
--- a/utils/valgrind/x86_64-pc-linux-gnu.supp
+++ b/utils/valgrind/x86_64-pc-linux-gnu.supp
@@ -33,6 +33,12 @@
}
{
+ We don't care of cmp
+ Memcheck:Cond
+ obj:/usr/bin/cmp
+}
+
+{
We don't care if grep leaks
Memcheck:Leak
obj:/bin/grep
diff --git a/utils/vim/llvm.vim b/utils/vim/llvm.vim
index c16274b..abd24e5 100644
--- a/utils/vim/llvm.vim
+++ b/utils/vim/llvm.vim
@@ -1,7 +1,7 @@
" Vim syntax file
" Language: llvm
" Maintainer: The LLVM team, http://llvm.org/
-" Version: $Revision: 166305 $
+" Version: $Revision: 176075 $
if version < 600
syntax clear
@@ -14,50 +14,48 @@ syn case match
" Types.
" Types also include struct, array, vector, etc. but these don't
" benefit as much from having dedicated highlighting rules.
-syn keyword llvmType void float double half
-syn keyword llvmType x86_fp80 fp128 ppc_fp128
+syn keyword llvmType void half float double x86_fp80 fp128 ppc_fp128
+syn keyword llvmType label metadata x86_mmx
syn keyword llvmType type label opaque
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 fadd sub fsub mul fmul
-syn keyword llvmStatement sdiv udiv fdiv srem urem frem
-syn keyword llvmStatement and or xor
-syn keyword llvmStatement icmp fcmp
-syn keyword llvmStatement eq ne ugt uge ult ule sgt sge slt sle
-syn keyword llvmStatement oeq ogt oge olt ole one ord ueq ugt uge
-syn keyword llvmStatement ult ule une uno
-syn keyword llvmStatement nuw nsw exact inbounds
-syn keyword llvmStatement phi call select shl lshr ashr va_arg
-syn keyword llvmStatement trunc zext sext
-syn keyword llvmStatement fptrunc fpext fptoui fptosi uitofp sitofp
-syn keyword llvmStatement ptrtoint inttoptr bitcast
-syn keyword llvmStatement ret br indirectbr switch invoke unwind unreachable
-syn keyword llvmStatement malloc alloca free load store getelementptr
-syn keyword llvmStatement extractelement insertelement shufflevector
-syn keyword llvmStatement extractvalue insertvalue
+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
" Keywords.
-syn keyword llvmKeyword define declare global constant
-syn keyword llvmKeyword internal external private
-syn keyword llvmKeyword linkonce linkonce_odr weak weak_odr appending
-syn keyword llvmKeyword common extern_weak
-syn keyword llvmKeyword thread_local dllimport dllexport
-syn keyword llvmKeyword hidden protected default
-syn keyword llvmKeyword except deplibs
-syn keyword llvmKeyword volatile fastcc coldcc cc ccc
-syn keyword llvmKeyword x86_stdcallcc x86_fastcallcc
-syn keyword llvmKeyword ptx_kernel ptx_device
-syn keyword llvmKeyword signext zeroext inreg sret nounwind noreturn
-syn keyword llvmKeyword nocapture byval nest readnone readonly noalias uwtable
-syn keyword llvmKeyword inlinehint noinline alwaysinline optsize ssp sspreq
-syn keyword llvmKeyword noredzone noimplicitfloat naked alignstack
-syn keyword llvmKeyword module asm align tail to
-syn keyword llvmKeyword addrspace section alias sideeffect c gc
-syn keyword llvmKeyword target datalayout triple
-syn keyword llvmKeyword blockaddress
+syn keyword llvmKeyword acq_rel acquire sanitize_address addrspace alias align
+syn keyword llvmKeyword alignstack alwaysinline appending arm_aapcs_vfpcc
+syn keyword llvmKeyword arm_aapcscc arm_apcscc asm atomic available_externally
+syn keyword llvmKeyword blockaddress byval c catch cc ccc cleanup coldcc common
+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 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 ptx_device ptx_kernel readnone readonly release
+syn keyword llvmKeyword returns_twice section seq_cst sideeffect signext
+syn keyword llvmKeyword singlethread spir_func spir_kernel sret ssp sspreq
+syn keyword llvmKeyword sspstrong tail target thread_local to triple
+syn keyword llvmKeyword unnamed_addr unordered uwtable volatile weak weak_odr
+syn keyword llvmKeyword x86_fastcallcc x86_stdcallcc x86_thiscallcc zeroext
+syn keyword llvmKeyword sanitize_thread sanitize_memory
" Obsolete keywords.
syn keyword llvmError getresult begin end
diff --git a/utils/vim/vimrc b/utils/vim/vimrc
index 3f863d6..c35eb0e 100644
--- a/utils/vim/vimrc
+++ b/utils/vim/vimrc
@@ -1,5 +1,5 @@
" LLVM coding guidelines conformance for VIM
-" $Revision: 117415 $
+" $Revision: 176235 $
"
" Maintainer: The LLVM Team, http://llvm.org
" WARNING: Read before you source in all these commands and macros! Some
@@ -85,6 +85,13 @@ augroup filetype
au! BufRead,BufNewFile *.td set filetype=tablegen
augroup END
+" Enable syntax highlighting for reStructuredText files. To use, copy
+" rest.vim (http://www.vim.org/scripts/script.php?script_id=973)
+" to ~/.vim/syntax .
+augroup filetype
+ au! BufRead,BufNewFile *.rst set filetype=rest
+augroup END
+
" Additional vim features to optionally uncomment.
"set showcmd
"set showmatch
diff --git a/utils/wciia.py b/utils/wciia.py
new file mode 100755
index 0000000..c838819
--- /dev/null
+++ b/utils/wciia.py
@@ -0,0 +1,125 @@
+#!/usr/bin/env python
+
+"""
+wciia - Whose Code Is It Anyway
+
+Determines code owner of the file/folder relative to the llvm source root.
+Code owner is determined from the content of the CODE_OWNERS.TXT
+by parsing the D: field
+
+usage:
+
+utils/wciia.py path
+
+limitations:
+- must be run from llvm source root
+- very simplistic algorithm
+- only handles * as a wildcard
+- not very user friendly
+- does not handle the proposed F: field
+
+"""
+
+import os
+
+code_owners = {}
+
+def process_files_and_folders(owner):
+ filesfolders = owner['filesfolders']
+ # paths must be in ( ... ) so strip them
+ lpar = filesfolders.find('(')
+ rpar = filesfolders.rfind(')')
+ if rpar <= lpar:
+ # give up
+ return
+ paths = filesfolders[lpar+1:rpar]
+ # split paths
+ owner['paths'] = []
+ for path in paths.split():
+ owner['paths'].append(path)
+
+def process_code_owner(owner):
+ if 'filesfolders' in owner:
+ filesfolders = owner['filesfolders']
+ else:
+# print "F: field missing, using D: field"
+ owner['filesfolders'] = owner['description']
+ process_files_and_folders(owner)
+ code_owners[owner['name']] = owner
+
+# process CODE_OWNERS.TXT first
+code_owners_file = open("CODE_OWNERS.TXT", "r").readlines()
+code_owner = {}
+for line in code_owners_file:
+ for word in line.split():
+ if word == "N:":
+ name = line[2:].strip()
+ if code_owner:
+ process_code_owner(code_owner)
+ code_owner = {}
+ # reset the values
+ code_owner['name'] = name
+ if word == "E:":
+ email = line[2:].strip()
+ code_owner['email'] = email
+ if word == "D:":
+ description = line[2:].strip()
+ code_owner['description'] = description
+ if word == "F:":
+ filesfolders = line[2:].strip()
+ code_owner['filesfolders'].append(filesfolders)
+
+def find_owners(fpath):
+ onames = []
+ lmatch = -1
+ # very simplistic way of findning the best match
+ for name in code_owners:
+ owner = code_owners[name]
+ if 'paths' in owner:
+ for path in owner['paths']:
+# print "searching (" + path + ")"
+ # try exact match
+ if fpath == path:
+ return name
+ # see if path ends with a *
+ rstar = path.rfind('*')
+ if rstar>0:
+ # try the longest match,
+ rpos = -1
+ if len(fpath) < len(path):
+ rpos = path.find(fpath)
+ if rpos == 0:
+ onames.append(name)
+ onames.append('Chris Lattner')
+ return onames
+
+# now lest try to find the owner of the file or folder
+import sys
+
+if len(sys.argv) < 2:
+ print "usage " + sys.argv[0] + " file_or_folder"
+ exit(-1)
+
+# the path we are checking
+path = str(sys.argv[1])
+
+# check if this is real path
+if not os.path.exists(path):
+ print "path (" + path + ") does not exist"
+ exit(-1)
+
+owners_name = find_owners(path)
+
+# be gramatically correct
+print "The owner(s) of the (" + path + ") is(are) : " + str(owners_name)
+
+exit(0)
+
+# bottom up walk of the current .
+# not yet used
+root = "."
+for dir,subdirList,fileList in os.walk( root , topdown=False ) :
+ print "dir :" , dir
+ for fname in fileList :
+ print "-" , fname
+ print
diff --git a/utils/yaml-bench/YAMLBench.cpp b/utils/yaml-bench/YAMLBench.cpp
index e5ee52a..eef4a72 100644
--- a/utils/yaml-bench/YAMLBench.cpp
+++ b/utils/yaml-bench/YAMLBench.cpp
@@ -17,11 +17,11 @@
#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/SourceMgr.h"
-#include "llvm/Support/system_error.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/YAMLParser.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/system_error.h"
using namespace llvm;
diff --git a/utils/yaml2obj/yaml2obj.cpp b/utils/yaml2obj/yaml2obj.cpp
index 4fc620f..17b65ae 100644
--- a/utils/yaml2obj/yaml2obj.cpp
+++ b/utils/yaml2obj/yaml2obj.cpp
@@ -25,12 +25,11 @@
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/PrettyStackTrace.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/YAMLTraits.h"
+#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/system_error.h"
-#include "llvm/Support/YAMLParser.h"
-
#include <vector>
using namespace llvm;
@@ -112,553 +111,140 @@ static bool hexStringToByteArray(StringRef Str, ContainerOut &Out) {
return true;
}
+// The structure of the yaml files is not an exact 1:1 match to COFF. In order
+// to use yaml::IO, we use these structures which are closer to the source.
+namespace COFFYAML {
+ struct Relocation {
+ uint32_t VirtualAddress;
+ uint32_t SymbolTableIndex;
+ COFF::RelocationTypeX86 Type;
+ };
+
+ struct Section {
+ std::vector<COFF::SectionCharacteristics> Characteristics;
+ StringRef SectionData;
+ std::vector<Relocation> Relocations;
+ StringRef Name;
+ };
+
+ struct Header {
+ COFF::MachineTypes Machine;
+ std::vector<COFF::Characteristics> Characteristics;
+ };
+
+ struct Symbol {
+ COFF::SymbolBaseType SimpleType;
+ uint8_t NumberOfAuxSymbols;
+ StringRef Name;
+ COFF::SymbolStorageClass StorageClass;
+ StringRef AuxillaryData;
+ COFF::SymbolComplexType ComplexType;
+ uint32_t Value;
+ uint16_t SectionNumber;
+ };
+
+ struct Object {
+ Header HeaderData;
+ std::vector<Section> Sections;
+ std::vector<Symbol> Symbols;
+ };
+}
+
/// This parses a yaml stream that represents a COFF object file.
/// See docs/yaml2obj for the yaml scheema.
struct COFFParser {
- COFFParser(yaml::Stream &Input) : YS(Input) {
+ COFFParser(COFFYAML::Object &Obj) : Obj(Obj) {
std::memset(&Header, 0, sizeof(Header));
// A COFF string table always starts with a 4 byte size field. Offsets into
// it include this size, so allocate it now.
StringTable.append(4, 0);
}
- bool parseHeader(yaml::Node *HeaderN) {
- yaml::MappingNode *MN = dyn_cast<yaml::MappingNode>(HeaderN);
- if (!MN) {
- YS.printError(HeaderN, "header's value must be a mapping node");
- return false;
+ void parseHeader() {
+ Header.Machine = Obj.HeaderData.Machine;
+
+ const std::vector<COFF::Characteristics> &Characteristics =
+ Obj.HeaderData.Characteristics;
+ for (std::vector<COFF::Characteristics>::const_iterator I =
+ Characteristics.begin(), E = Characteristics.end(); I != E; ++I) {
+ uint16_t Characteristic = *I;
+ Header.Characteristics |= Characteristic;
}
- for (yaml::MappingNode::iterator i = MN->begin(), e = MN->end();
- i != e; ++i) {
- yaml::ScalarNode *Key = dyn_cast<yaml::ScalarNode>(i->getKey());
- if (!Key) {
- YS.printError(i->getKey(), "Keys must be scalar values");
- return false;
- }
- SmallString<32> Storage;
- StringRef KeyValue = Key->getValue(Storage);
- if (KeyValue == "Characteristics") {
- if (!parseHeaderCharacteristics(i->getValue()))
- return false;
+ }
+
+ bool parseSections() {
+ for (std::vector<COFFYAML::Section>::iterator i = Obj.Sections.begin(),
+ e = Obj.Sections.end(); i != e; ++i) {
+ const COFFYAML::Section &YamlSection = *i;
+ Section Sec;
+ std::memset(&Sec.Header, 0, sizeof(Sec.Header));
+
+ // If the name is less than 8 bytes, store it in place, otherwise
+ // store it in the string table.
+ StringRef Name = YamlSection.Name;
+ std::fill_n(Sec.Header.Name, unsigned(COFF::NameSize), 0);
+ if (Name.size() <= COFF::NameSize) {
+ std::copy(Name.begin(), Name.end(), Sec.Header.Name);
} else {
- yaml::ScalarNode *Value = dyn_cast<yaml::ScalarNode>(i->getValue());
- if (!Value) {
- YS.printError(Value,
- Twine(KeyValue) + " must be a scalar value");
- return false;
- }
- if (KeyValue == "Machine") {
- uint16_t Machine = COFF::MT_Invalid;
- if (!getAs(Value, Machine)) {
- // It's not a raw number, try matching the string.
- StringRef ValueValue = Value->getValue(Storage);
- Machine = StringSwitch<COFF::MachineTypes>(ValueValue)
- .Case( "IMAGE_FILE_MACHINE_UNKNOWN"
- , COFF::IMAGE_FILE_MACHINE_UNKNOWN)
- .Case( "IMAGE_FILE_MACHINE_AM33"
- , COFF::IMAGE_FILE_MACHINE_AM33)
- .Case( "IMAGE_FILE_MACHINE_AMD64"
- , COFF::IMAGE_FILE_MACHINE_AMD64)
- .Case( "IMAGE_FILE_MACHINE_ARM"
- , COFF::IMAGE_FILE_MACHINE_ARM)
- .Case( "IMAGE_FILE_MACHINE_ARMV7"
- , COFF::IMAGE_FILE_MACHINE_ARMV7)
- .Case( "IMAGE_FILE_MACHINE_EBC"
- , COFF::IMAGE_FILE_MACHINE_EBC)
- .Case( "IMAGE_FILE_MACHINE_I386"
- , COFF::IMAGE_FILE_MACHINE_I386)
- .Case( "IMAGE_FILE_MACHINE_IA64"
- , COFF::IMAGE_FILE_MACHINE_IA64)
- .Case( "IMAGE_FILE_MACHINE_M32R"
- , COFF::IMAGE_FILE_MACHINE_M32R)
- .Case( "IMAGE_FILE_MACHINE_MIPS16"
- , COFF::IMAGE_FILE_MACHINE_MIPS16)
- .Case( "IMAGE_FILE_MACHINE_MIPSFPU"
- , COFF::IMAGE_FILE_MACHINE_MIPSFPU)
- .Case( "IMAGE_FILE_MACHINE_MIPSFPU16"
- , COFF::IMAGE_FILE_MACHINE_MIPSFPU16)
- .Case( "IMAGE_FILE_MACHINE_POWERPC"
- , COFF::IMAGE_FILE_MACHINE_POWERPC)
- .Case( "IMAGE_FILE_MACHINE_POWERPCFP"
- , COFF::IMAGE_FILE_MACHINE_POWERPCFP)
- .Case( "IMAGE_FILE_MACHINE_R4000"
- , COFF::IMAGE_FILE_MACHINE_R4000)
- .Case( "IMAGE_FILE_MACHINE_SH3"
- , COFF::IMAGE_FILE_MACHINE_SH3)
- .Case( "IMAGE_FILE_MACHINE_SH3DSP"
- , COFF::IMAGE_FILE_MACHINE_SH3DSP)
- .Case( "IMAGE_FILE_MACHINE_SH4"
- , COFF::IMAGE_FILE_MACHINE_SH4)
- .Case( "IMAGE_FILE_MACHINE_SH5"
- , COFF::IMAGE_FILE_MACHINE_SH5)
- .Case( "IMAGE_FILE_MACHINE_THUMB"
- , COFF::IMAGE_FILE_MACHINE_THUMB)
- .Case( "IMAGE_FILE_MACHINE_WCEMIPSV2"
- , COFF::IMAGE_FILE_MACHINE_WCEMIPSV2)
- .Default(COFF::MT_Invalid);
- if (Machine == COFF::MT_Invalid) {
- YS.printError(Value, "Invalid value for Machine");
- return false;
- }
- }
- Header.Machine = Machine;
- } else if (KeyValue == "NumberOfSections") {
- if (!getAs(Value, Header.NumberOfSections)) {
- YS.printError(Value, "Invalid value for NumberOfSections");
- return false;
- }
- } else if (KeyValue == "TimeDateStamp") {
- if (!getAs(Value, Header.TimeDateStamp)) {
- YS.printError(Value, "Invalid value for TimeDateStamp");
- return false;
- }
- } else if (KeyValue == "PointerToSymbolTable") {
- if (!getAs(Value, Header.PointerToSymbolTable)) {
- YS.printError(Value, "Invalid value for PointerToSymbolTable");
- return false;
- }
- } else if (KeyValue == "NumberOfSymbols") {
- if (!getAs(Value, Header.NumberOfSymbols)) {
- YS.printError(Value, "Invalid value for NumberOfSymbols");
- return false;
- }
- } else if (KeyValue == "SizeOfOptionalHeader") {
- if (!getAs(Value, Header.SizeOfOptionalHeader)) {
- YS.printError(Value, "Invalid value for SizeOfOptionalHeader");
- return false;
- }
- } else {
- YS.printError(Key, "Unrecognized key in header");
+ // Add string to the string table and format the index for output.
+ unsigned Index = getStringIndex(Name);
+ std::string str = utostr(Index);
+ if (str.size() > 7) {
+ errs() << "String table got too large";
return false;
}
+ Sec.Header.Name[0] = '/';
+ std::copy(str.begin(), str.end(), Sec.Header.Name + 1);
}
- }
- return true;
- }
- bool parseHeaderCharacteristics(yaml::Node *Characteristics) {
- yaml::ScalarNode *Value = dyn_cast<yaml::ScalarNode>(Characteristics);
- yaml::SequenceNode *SeqValue
- = dyn_cast<yaml::SequenceNode>(Characteristics);
- if (!Value && !SeqValue) {
- YS.printError(Characteristics,
- "Characteristics must either be a number or sequence");
- return false;
- }
- if (Value) {
- if (!getAs(Value, Header.Characteristics)) {
- YS.printError(Value, "Invalid value for Characteristics");
- return false;
- }
- } else {
- for (yaml::SequenceNode::iterator ci = SeqValue->begin(),
- ce = SeqValue->end();
- ci != ce; ++ci) {
- yaml::ScalarNode *CharValue = dyn_cast<yaml::ScalarNode>(&*ci);
- if (!CharValue) {
- YS.printError(CharValue,
- "Characteristics must be scalar values");
- return false;
- }
- SmallString<32> Storage;
- StringRef Char = CharValue->getValue(Storage);
- uint16_t Characteristic = StringSwitch<COFF::Characteristics>(Char)
- .Case( "IMAGE_FILE_RELOCS_STRIPPED"
- , COFF::IMAGE_FILE_RELOCS_STRIPPED)
- .Case( "IMAGE_FILE_EXECUTABLE_IMAGE"
- , COFF::IMAGE_FILE_EXECUTABLE_IMAGE)
- .Case( "IMAGE_FILE_LINE_NUMS_STRIPPED"
- , COFF::IMAGE_FILE_LINE_NUMS_STRIPPED)
- .Case( "IMAGE_FILE_LOCAL_SYMS_STRIPPED"
- , COFF::IMAGE_FILE_LOCAL_SYMS_STRIPPED)
- .Case( "IMAGE_FILE_AGGRESSIVE_WS_TRIM"
- , COFF::IMAGE_FILE_AGGRESSIVE_WS_TRIM)
- .Case( "IMAGE_FILE_LARGE_ADDRESS_AWARE"
- , COFF::IMAGE_FILE_LARGE_ADDRESS_AWARE)
- .Case( "IMAGE_FILE_BYTES_REVERSED_LO"
- , COFF::IMAGE_FILE_BYTES_REVERSED_LO)
- .Case( "IMAGE_FILE_32BIT_MACHINE"
- , COFF::IMAGE_FILE_32BIT_MACHINE)
- .Case( "IMAGE_FILE_DEBUG_STRIPPED"
- , COFF::IMAGE_FILE_DEBUG_STRIPPED)
- .Case( "IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP"
- , COFF::IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP)
- .Case( "IMAGE_FILE_SYSTEM"
- , COFF::IMAGE_FILE_SYSTEM)
- .Case( "IMAGE_FILE_DLL"
- , COFF::IMAGE_FILE_DLL)
- .Case( "IMAGE_FILE_UP_SYSTEM_ONLY"
- , COFF::IMAGE_FILE_UP_SYSTEM_ONLY)
- .Default(COFF::C_Invalid);
- if (Characteristic == COFF::C_Invalid) {
- // TODO: Typo-correct.
- YS.printError(CharValue,
- "Invalid value for Characteristic");
- return false;
- }
- Header.Characteristics |= Characteristic;
+ for (std::vector<COFF::SectionCharacteristics>::const_iterator i =
+ YamlSection.Characteristics.begin(),
+ e = YamlSection.Characteristics.end();
+ i != e; ++i) {
+ uint32_t Characteristic = *i;
+ Sec.Header.Characteristics |= Characteristic;
}
- }
- return true;
- }
- bool parseSections(yaml::Node *SectionsN) {
- yaml::SequenceNode *SN = dyn_cast<yaml::SequenceNode>(SectionsN);
- if (!SN) {
- YS.printError(SectionsN, "Sections must be a sequence");
- return false;
- }
- for (yaml::SequenceNode::iterator i = SN->begin(), e = SN->end();
- i != e; ++i) {
- Section Sec;
- std::memset(&Sec.Header, 0, sizeof(Sec.Header));
- yaml::MappingNode *SecMap = dyn_cast<yaml::MappingNode>(&*i);
- if (!SecMap) {
- YS.printError(&*i, "Section entry must be a map");
+ StringRef Data = YamlSection.SectionData;
+ if (!hexStringToByteArray(Data, Sec.Data)) {
+ errs() << "SectionData must be a collection of pairs of hex bytes";
return false;
}
- for (yaml::MappingNode::iterator si = SecMap->begin(), se = SecMap->end();
- si != se; ++si) {
- yaml::ScalarNode *Key = dyn_cast<yaml::ScalarNode>(si->getKey());
- if (!Key) {
- YS.printError(si->getKey(), "Keys must be scalar values");
- return false;
- }
- SmallString<32> Storage;
- StringRef KeyValue = Key->getValue(Storage);
-
- yaml::ScalarNode *Value = dyn_cast<yaml::ScalarNode>(si->getValue());
- if (KeyValue == "Name") {
- // If the name is less than 8 bytes, store it in place, otherwise
- // store it in the string table.
- StringRef Name = Value->getValue(Storage);
- std::fill_n(Sec.Header.Name, unsigned(COFF::NameSize), 0);
- if (Name.size() <= COFF::NameSize) {
- std::copy(Name.begin(), Name.end(), Sec.Header.Name);
- } else {
- // Add string to the string table and format the index for output.
- unsigned Index = getStringIndex(Name);
- std::string str = utostr(Index);
- if (str.size() > 7) {
- YS.printError(Value, "String table got too large");
- return false;
- }
- Sec.Header.Name[0] = '/';
- std::copy(str.begin(), str.end(), Sec.Header.Name + 1);
- }
- } else if (KeyValue == "VirtualSize") {
- if (!getAs(Value, Sec.Header.VirtualSize)) {
- YS.printError(Value, "Invalid value for VirtualSize");
- return false;
- }
- } else if (KeyValue == "VirtualAddress") {
- if (!getAs(Value, Sec.Header.VirtualAddress)) {
- YS.printError(Value, "Invalid value for VirtualAddress");
- return false;
- }
- } else if (KeyValue == "SizeOfRawData") {
- if (!getAs(Value, Sec.Header.SizeOfRawData)) {
- YS.printError(Value, "Invalid value for SizeOfRawData");
- return false;
- }
- } else if (KeyValue == "PointerToRawData") {
- if (!getAs(Value, Sec.Header.PointerToRawData)) {
- YS.printError(Value, "Invalid value for PointerToRawData");
- return false;
- }
- } else if (KeyValue == "PointerToRelocations") {
- if (!getAs(Value, Sec.Header.PointerToRelocations)) {
- YS.printError(Value, "Invalid value for PointerToRelocations");
- return false;
- }
- } else if (KeyValue == "PointerToLineNumbers") {
- if (!getAs(Value, Sec.Header.PointerToLineNumbers)) {
- YS.printError(Value, "Invalid value for PointerToLineNumbers");
- return false;
- }
- } else if (KeyValue == "NumberOfRelocations") {
- if (!getAs(Value, Sec.Header.NumberOfRelocations)) {
- YS.printError(Value, "Invalid value for NumberOfRelocations");
- return false;
- }
- } else if (KeyValue == "NumberOfLineNumbers") {
- if (!getAs(Value, Sec.Header.NumberOfLineNumbers)) {
- YS.printError(Value, "Invalid value for NumberOfLineNumbers");
- return false;
- }
- } else if (KeyValue == "Characteristics") {
- yaml::SequenceNode *SeqValue
- = dyn_cast<yaml::SequenceNode>(si->getValue());
- if (!Value && !SeqValue) {
- YS.printError(si->getValue(),
- "Characteristics must either be a number or sequence");
- return false;
- }
- if (Value) {
- if (!getAs(Value, Sec.Header.Characteristics)) {
- YS.printError(Value, "Invalid value for Characteristics");
- return false;
- }
- } else {
- for (yaml::SequenceNode::iterator ci = SeqValue->begin(),
- ce = SeqValue->end();
- ci != ce; ++ci) {
- yaml::ScalarNode *CharValue = dyn_cast<yaml::ScalarNode>(&*ci);
- if (!CharValue) {
- YS.printError(CharValue, "Invalid value for Characteristics");
- return false;
- }
- StringRef Char = CharValue->getValue(Storage);
- uint32_t Characteristic =
- StringSwitch<COFF::SectionCharacteristics>(Char)
- .Case( "IMAGE_SCN_TYPE_NO_PAD"
- , COFF::IMAGE_SCN_TYPE_NO_PAD)
- .Case( "IMAGE_SCN_CNT_CODE"
- , COFF::IMAGE_SCN_CNT_CODE)
- .Case( "IMAGE_SCN_CNT_INITIALIZED_DATA"
- , COFF::IMAGE_SCN_CNT_INITIALIZED_DATA)
- .Case( "IMAGE_SCN_CNT_UNINITIALIZED_DATA"
- , COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA)
- .Case( "IMAGE_SCN_LNK_OTHER"
- , COFF::IMAGE_SCN_LNK_OTHER)
- .Case( "IMAGE_SCN_LNK_INFO"
- , COFF::IMAGE_SCN_LNK_INFO)
- .Case( "IMAGE_SCN_LNK_REMOVE"
- , COFF::IMAGE_SCN_LNK_REMOVE)
- .Case( "IMAGE_SCN_LNK_COMDAT"
- , COFF::IMAGE_SCN_LNK_COMDAT)
- .Case( "IMAGE_SCN_GPREL"
- , COFF::IMAGE_SCN_GPREL)
- .Case( "IMAGE_SCN_MEM_PURGEABLE"
- , COFF::IMAGE_SCN_MEM_PURGEABLE)
- .Case( "IMAGE_SCN_MEM_16BIT"
- , COFF::IMAGE_SCN_MEM_16BIT)
- .Case( "IMAGE_SCN_MEM_LOCKED"
- , COFF::IMAGE_SCN_MEM_LOCKED)
- .Case( "IMAGE_SCN_MEM_PRELOAD"
- , COFF::IMAGE_SCN_MEM_PRELOAD)
- .Case( "IMAGE_SCN_ALIGN_1BYTES"
- , COFF::IMAGE_SCN_ALIGN_1BYTES)
- .Case( "IMAGE_SCN_ALIGN_2BYTES"
- , COFF::IMAGE_SCN_ALIGN_2BYTES)
- .Case( "IMAGE_SCN_ALIGN_4BYTES"
- , COFF::IMAGE_SCN_ALIGN_4BYTES)
- .Case( "IMAGE_SCN_ALIGN_8BYTES"
- , COFF::IMAGE_SCN_ALIGN_8BYTES)
- .Case( "IMAGE_SCN_ALIGN_16BYTES"
- , COFF::IMAGE_SCN_ALIGN_16BYTES)
- .Case( "IMAGE_SCN_ALIGN_32BYTES"
- , COFF::IMAGE_SCN_ALIGN_32BYTES)
- .Case( "IMAGE_SCN_ALIGN_64BYTES"
- , COFF::IMAGE_SCN_ALIGN_64BYTES)
- .Case( "IMAGE_SCN_ALIGN_128BYTES"
- , COFF::IMAGE_SCN_ALIGN_128BYTES)
- .Case( "IMAGE_SCN_ALIGN_256BYTES"
- , COFF::IMAGE_SCN_ALIGN_256BYTES)
- .Case( "IMAGE_SCN_ALIGN_512BYTES"
- , COFF::IMAGE_SCN_ALIGN_512BYTES)
- .Case( "IMAGE_SCN_ALIGN_1024BYTES"
- , COFF::IMAGE_SCN_ALIGN_1024BYTES)
- .Case( "IMAGE_SCN_ALIGN_2048BYTES"
- , COFF::IMAGE_SCN_ALIGN_2048BYTES)
- .Case( "IMAGE_SCN_ALIGN_4096BYTES"
- , COFF::IMAGE_SCN_ALIGN_4096BYTES)
- .Case( "IMAGE_SCN_ALIGN_8192BYTES"
- , COFF::IMAGE_SCN_ALIGN_8192BYTES)
- .Case( "IMAGE_SCN_LNK_NRELOC_OVFL"
- , COFF::IMAGE_SCN_LNK_NRELOC_OVFL)
- .Case( "IMAGE_SCN_MEM_DISCARDABLE"
- , COFF::IMAGE_SCN_MEM_DISCARDABLE)
- .Case( "IMAGE_SCN_MEM_NOT_CACHED"
- , COFF::IMAGE_SCN_MEM_NOT_CACHED)
- .Case( "IMAGE_SCN_MEM_NOT_PAGED"
- , COFF::IMAGE_SCN_MEM_NOT_PAGED)
- .Case( "IMAGE_SCN_MEM_SHARED"
- , COFF::IMAGE_SCN_MEM_SHARED)
- .Case( "IMAGE_SCN_MEM_EXECUTE"
- , COFF::IMAGE_SCN_MEM_EXECUTE)
- .Case( "IMAGE_SCN_MEM_READ"
- , COFF::IMAGE_SCN_MEM_READ)
- .Case( "IMAGE_SCN_MEM_WRITE"
- , COFF::IMAGE_SCN_MEM_WRITE)
- .Default(COFF::SC_Invalid);
- if (Characteristic == COFF::SC_Invalid) {
- YS.printError(CharValue, "Invalid value for Characteristic");
- return false;
- }
- Sec.Header.Characteristics |= Characteristic;
- }
- }
- } else if (KeyValue == "SectionData") {
- yaml::ScalarNode *Value = dyn_cast<yaml::ScalarNode>(si->getValue());
- SmallString<32> Storage;
- StringRef Data = Value->getValue(Storage);
- if (!hexStringToByteArray(Data, Sec.Data)) {
- YS.printError(Value, "SectionData must be a collection of pairs of"
- "hex bytes");
- return false;
- }
- } else
- si->skip();
- }
Sections.push_back(Sec);
}
return true;
}
- bool parseSymbols(yaml::Node *SymbolsN) {
- yaml::SequenceNode *SN = dyn_cast<yaml::SequenceNode>(SymbolsN);
- if (!SN) {
- YS.printError(SymbolsN, "Symbols must be a sequence");
- return false;
- }
- for (yaml::SequenceNode::iterator i = SN->begin(), e = SN->end();
- i != e; ++i) {
+ bool parseSymbols() {
+ for (std::vector<COFFYAML::Symbol>::iterator i = Obj.Symbols.begin(),
+ e = Obj.Symbols.end(); i != e; ++i) {
+ COFFYAML::Symbol YamlSymbol = *i;
Symbol Sym;
std::memset(&Sym.Header, 0, sizeof(Sym.Header));
- yaml::MappingNode *SymMap = dyn_cast<yaml::MappingNode>(&*i);
- if (!SymMap) {
- YS.printError(&*i, "Symbol must be a map");
- return false;
+
+ // If the name is less than 8 bytes, store it in place, otherwise
+ // store it in the string table.
+ StringRef Name = YamlSymbol.Name;
+ std::fill_n(Sym.Header.Name, unsigned(COFF::NameSize), 0);
+ if (Name.size() <= COFF::NameSize) {
+ std::copy(Name.begin(), Name.end(), Sym.Header.Name);
+ } else {
+ // Add string to the string table and format the index for output.
+ unsigned Index = getStringIndex(Name);
+ *reinterpret_cast<support::aligned_ulittle32_t*>(
+ Sym.Header.Name + 4) = Index;
}
- for (yaml::MappingNode::iterator si = SymMap->begin(), se = SymMap->end();
- si != se; ++si) {
- yaml::ScalarNode *Key = dyn_cast<yaml::ScalarNode>(si->getKey());
- if (!Key) {
- YS.printError(si->getKey(), "Keys must be scalar values");
- return false;
- }
- SmallString<32> Storage;
- StringRef KeyValue = Key->getValue(Storage);
- yaml::ScalarNode *Value = dyn_cast<yaml::ScalarNode>(si->getValue());
- if (!Value) {
- YS.printError(si->getValue(), "Must be a scalar value");
- return false;
- }
- if (KeyValue == "Name") {
- // If the name is less than 8 bytes, store it in place, otherwise
- // store it in the string table.
- StringRef Name = Value->getValue(Storage);
- std::fill_n(Sym.Header.Name, unsigned(COFF::NameSize), 0);
- if (Name.size() <= COFF::NameSize) {
- std::copy(Name.begin(), Name.end(), Sym.Header.Name);
- } else {
- // Add string to the string table and format the index for output.
- unsigned Index = getStringIndex(Name);
- *reinterpret_cast<support::aligned_ulittle32_t*>(
- Sym.Header.Name + 4) = Index;
- }
- } else if (KeyValue == "Value") {
- if (!getAs(Value, Sym.Header.Value)) {
- YS.printError(Value, "Invalid value for Value");
- return false;
- }
- } else if (KeyValue == "SimpleType") {
- Sym.Header.Type |= StringSwitch<COFF::SymbolBaseType>(
- Value->getValue(Storage))
- .Case("IMAGE_SYM_TYPE_NULL", COFF::IMAGE_SYM_TYPE_NULL)
- .Case("IMAGE_SYM_TYPE_VOID", COFF::IMAGE_SYM_TYPE_VOID)
- .Case("IMAGE_SYM_TYPE_CHAR", COFF::IMAGE_SYM_TYPE_CHAR)
- .Case("IMAGE_SYM_TYPE_SHORT", COFF::IMAGE_SYM_TYPE_SHORT)
- .Case("IMAGE_SYM_TYPE_INT", COFF::IMAGE_SYM_TYPE_INT)
- .Case("IMAGE_SYM_TYPE_LONG", COFF::IMAGE_SYM_TYPE_LONG)
- .Case("IMAGE_SYM_TYPE_FLOAT", COFF::IMAGE_SYM_TYPE_FLOAT)
- .Case("IMAGE_SYM_TYPE_DOUBLE", COFF::IMAGE_SYM_TYPE_DOUBLE)
- .Case("IMAGE_SYM_TYPE_STRUCT", COFF::IMAGE_SYM_TYPE_STRUCT)
- .Case("IMAGE_SYM_TYPE_UNION", COFF::IMAGE_SYM_TYPE_UNION)
- .Case("IMAGE_SYM_TYPE_ENUM", COFF::IMAGE_SYM_TYPE_ENUM)
- .Case("IMAGE_SYM_TYPE_MOE", COFF::IMAGE_SYM_TYPE_MOE)
- .Case("IMAGE_SYM_TYPE_BYTE", COFF::IMAGE_SYM_TYPE_BYTE)
- .Case("IMAGE_SYM_TYPE_WORD", COFF::IMAGE_SYM_TYPE_WORD)
- .Case("IMAGE_SYM_TYPE_UINT", COFF::IMAGE_SYM_TYPE_UINT)
- .Case("IMAGE_SYM_TYPE_DWORD", COFF::IMAGE_SYM_TYPE_DWORD)
- .Default(COFF::IMAGE_SYM_TYPE_NULL);
- } else if (KeyValue == "ComplexType") {
- Sym.Header.Type |= StringSwitch<COFF::SymbolComplexType>(
- Value->getValue(Storage))
- .Case("IMAGE_SYM_DTYPE_NULL", COFF::IMAGE_SYM_DTYPE_NULL)
- .Case("IMAGE_SYM_DTYPE_POINTER", COFF::IMAGE_SYM_DTYPE_POINTER)
- .Case("IMAGE_SYM_DTYPE_FUNCTION", COFF::IMAGE_SYM_DTYPE_FUNCTION)
- .Case("IMAGE_SYM_DTYPE_ARRAY", COFF::IMAGE_SYM_DTYPE_ARRAY)
- .Default(COFF::IMAGE_SYM_DTYPE_NULL)
- << COFF::SCT_COMPLEX_TYPE_SHIFT;
- } else if (KeyValue == "StorageClass") {
- Sym.Header.StorageClass = StringSwitch<COFF::SymbolStorageClass>(
- Value->getValue(Storage))
- .Case( "IMAGE_SYM_CLASS_END_OF_FUNCTION"
- , COFF::IMAGE_SYM_CLASS_END_OF_FUNCTION)
- .Case( "IMAGE_SYM_CLASS_NULL"
- , COFF::IMAGE_SYM_CLASS_NULL)
- .Case( "IMAGE_SYM_CLASS_AUTOMATIC"
- , COFF::IMAGE_SYM_CLASS_AUTOMATIC)
- .Case( "IMAGE_SYM_CLASS_EXTERNAL"
- , COFF::IMAGE_SYM_CLASS_EXTERNAL)
- .Case( "IMAGE_SYM_CLASS_STATIC"
- , COFF::IMAGE_SYM_CLASS_STATIC)
- .Case( "IMAGE_SYM_CLASS_REGISTER"
- , COFF::IMAGE_SYM_CLASS_REGISTER)
- .Case( "IMAGE_SYM_CLASS_EXTERNAL_DEF"
- , COFF::IMAGE_SYM_CLASS_EXTERNAL_DEF)
- .Case( "IMAGE_SYM_CLASS_LABEL"
- , COFF::IMAGE_SYM_CLASS_LABEL)
- .Case( "IMAGE_SYM_CLASS_UNDEFINED_LABEL"
- , COFF::IMAGE_SYM_CLASS_UNDEFINED_LABEL)
- .Case( "IMAGE_SYM_CLASS_MEMBER_OF_STRUCT"
- , COFF::IMAGE_SYM_CLASS_MEMBER_OF_STRUCT)
- .Case( "IMAGE_SYM_CLASS_ARGUMENT"
- , COFF::IMAGE_SYM_CLASS_ARGUMENT)
- .Case( "IMAGE_SYM_CLASS_STRUCT_TAG"
- , COFF::IMAGE_SYM_CLASS_STRUCT_TAG)
- .Case( "IMAGE_SYM_CLASS_MEMBER_OF_UNION"
- , COFF::IMAGE_SYM_CLASS_MEMBER_OF_UNION)
- .Case( "IMAGE_SYM_CLASS_UNION_TAG"
- , COFF::IMAGE_SYM_CLASS_UNION_TAG)
- .Case( "IMAGE_SYM_CLASS_TYPE_DEFINITION"
- , COFF::IMAGE_SYM_CLASS_TYPE_DEFINITION)
- .Case( "IMAGE_SYM_CLASS_UNDEFINED_STATIC"
- , COFF::IMAGE_SYM_CLASS_UNDEFINED_STATIC)
- .Case( "IMAGE_SYM_CLASS_ENUM_TAG"
- , COFF::IMAGE_SYM_CLASS_ENUM_TAG)
- .Case( "IMAGE_SYM_CLASS_MEMBER_OF_ENUM"
- , COFF::IMAGE_SYM_CLASS_MEMBER_OF_ENUM)
- .Case( "IMAGE_SYM_CLASS_REGISTER_PARAM"
- , COFF::IMAGE_SYM_CLASS_REGISTER_PARAM)
- .Case( "IMAGE_SYM_CLASS_BIT_FIELD"
- , COFF::IMAGE_SYM_CLASS_BIT_FIELD)
- .Case( "IMAGE_SYM_CLASS_BLOCK"
- , COFF::IMAGE_SYM_CLASS_BLOCK)
- .Case( "IMAGE_SYM_CLASS_FUNCTION"
- , COFF::IMAGE_SYM_CLASS_FUNCTION)
- .Case( "IMAGE_SYM_CLASS_END_OF_STRUCT"
- , COFF::IMAGE_SYM_CLASS_END_OF_STRUCT)
- .Case( "IMAGE_SYM_CLASS_FILE"
- , COFF::IMAGE_SYM_CLASS_FILE)
- .Case( "IMAGE_SYM_CLASS_SECTION"
- , COFF::IMAGE_SYM_CLASS_SECTION)
- .Case( "IMAGE_SYM_CLASS_WEAK_EXTERNAL"
- , COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL)
- .Case( "IMAGE_SYM_CLASS_CLR_TOKEN"
- , COFF::IMAGE_SYM_CLASS_CLR_TOKEN)
- .Default(COFF::SSC_Invalid);
- if (Sym.Header.StorageClass == COFF::SSC_Invalid) {
- YS.printError(Value, "Invalid value for StorageClass");
- return false;
- }
- } else if (KeyValue == "SectionNumber") {
- if (!getAs(Value, Sym.Header.SectionNumber)) {
- YS.printError(Value, "Invalid value for SectionNumber");
- return false;
- }
- } else if (KeyValue == "AuxillaryData") {
- StringRef Data = Value->getValue(Storage);
- if (!hexStringToByteArray(Data, Sym.AuxSymbols)) {
- YS.printError(Value, "AuxillaryData must be a collection of pairs"
- "of hex bytes");
- return false;
- }
- } else
- si->skip();
+ Sym.Header.Value = YamlSymbol.Value;
+ Sym.Header.Type |= YamlSymbol.SimpleType;
+ Sym.Header.Type |= YamlSymbol.ComplexType << COFF::SCT_COMPLEX_TYPE_SHIFT;
+ Sym.Header.StorageClass = YamlSymbol.StorageClass;
+ Sym.Header.SectionNumber = YamlSymbol.SectionNumber;
+
+ StringRef Data = YamlSymbol.AuxillaryData;
+ if (!hexStringToByteArray(Data, Sym.AuxSymbols)) {
+ errs() << "AuxillaryData must be a collection of pairs of hex bytes";
+ return false;
}
Symbols.push_back(Sym);
}
@@ -666,33 +252,12 @@ struct COFFParser {
}
bool parse() {
- yaml::Document &D = *YS.begin();
- yaml::MappingNode *Root = dyn_cast<yaml::MappingNode>(D.getRoot());
- if (!Root) {
- YS.printError(D.getRoot(), "Root node must be a map");
+ parseHeader();
+ if (!parseSections())
return false;
- }
- for (yaml::MappingNode::iterator i = Root->begin(), e = Root->end();
- i != e; ++i) {
- yaml::ScalarNode *Key = dyn_cast<yaml::ScalarNode>(i->getKey());
- if (!Key) {
- YS.printError(i->getKey(), "Keys must be scalar values");
- return false;
- }
- SmallString<32> Storage;
- StringRef KeyValue = Key->getValue(Storage);
- if (KeyValue == "header") {
- if (!parseHeader(i->getValue()))
- return false;
- } else if (KeyValue == "sections") {
- if (!parseSections(i->getValue()))
- return false;
- } else if (KeyValue == "symbols") {
- if (!parseSymbols(i->getValue()))
- return false;
- }
- }
- return !YS.failed();
+ if (!parseSymbols())
+ return false;
+ return true;
}
unsigned getStringIndex(StringRef Str) {
@@ -707,7 +272,7 @@ struct COFFParser {
return i->second;
}
- yaml::Stream &YS;
+ COFFYAML::Object &Obj;
COFF::header Header;
struct Section {
@@ -791,7 +356,8 @@ template <typename value_type>
raw_ostream &operator <<( raw_ostream &OS
, const binary_le_impl<value_type> &BLE) {
char Buffer[sizeof(BLE.Value)];
- support::endian::write_le<value_type, support::unaligned>(Buffer, BLE.Value);
+ support::endian::write<value_type, support::little, support::unaligned>(
+ Buffer, BLE.Value);
OS.write(Buffer, sizeof(BLE.Value));
return OS;
}
@@ -854,6 +420,260 @@ void writeCOFF(COFFParser &CP, raw_ostream &OS) {
OS.write(&CP.StringTable[0], CP.StringTable.size());
}
+LLVM_YAML_IS_SEQUENCE_VECTOR(COFFYAML::Relocation)
+LLVM_YAML_IS_SEQUENCE_VECTOR(COFF::SectionCharacteristics)
+LLVM_YAML_IS_SEQUENCE_VECTOR(COFF::Characteristics)
+LLVM_YAML_IS_SEQUENCE_VECTOR(COFFYAML::Section)
+LLVM_YAML_IS_SEQUENCE_VECTOR(COFFYAML::Symbol)
+
+namespace llvm {
+namespace yaml {
+#define ECase(X) IO.enumCase(Value, #X, COFF::X);
+
+template <>
+struct ScalarEnumerationTraits<COFF::SymbolComplexType> {
+ static void enumeration(IO &IO, COFF::SymbolComplexType &Value) {
+ ECase(IMAGE_SYM_DTYPE_NULL);
+ ECase(IMAGE_SYM_DTYPE_POINTER);
+ ECase(IMAGE_SYM_DTYPE_FUNCTION);
+ ECase(IMAGE_SYM_DTYPE_ARRAY);
+ }
+};
+
+// FIXME: We cannot use ScalarBitSetTraits because of
+// IMAGE_SYM_CLASS_END_OF_FUNCTION which is -1.
+template <>
+struct ScalarEnumerationTraits<COFF::SymbolStorageClass> {
+ static void enumeration(IO &IO, COFF::SymbolStorageClass &Value) {
+ ECase(IMAGE_SYM_CLASS_END_OF_FUNCTION);
+ ECase(IMAGE_SYM_CLASS_NULL);
+ ECase(IMAGE_SYM_CLASS_AUTOMATIC);
+ ECase(IMAGE_SYM_CLASS_EXTERNAL);
+ ECase(IMAGE_SYM_CLASS_STATIC);
+ ECase(IMAGE_SYM_CLASS_REGISTER);
+ ECase(IMAGE_SYM_CLASS_EXTERNAL_DEF);
+ ECase(IMAGE_SYM_CLASS_LABEL);
+ ECase(IMAGE_SYM_CLASS_UNDEFINED_LABEL);
+ ECase(IMAGE_SYM_CLASS_MEMBER_OF_STRUCT);
+ ECase(IMAGE_SYM_CLASS_ARGUMENT);
+ ECase(IMAGE_SYM_CLASS_STRUCT_TAG);
+ ECase(IMAGE_SYM_CLASS_MEMBER_OF_UNION);
+ ECase(IMAGE_SYM_CLASS_UNION_TAG);
+ ECase(IMAGE_SYM_CLASS_TYPE_DEFINITION);
+ ECase(IMAGE_SYM_CLASS_UNDEFINED_STATIC);
+ ECase(IMAGE_SYM_CLASS_ENUM_TAG);
+ ECase(IMAGE_SYM_CLASS_MEMBER_OF_ENUM);
+ ECase(IMAGE_SYM_CLASS_REGISTER_PARAM);
+ ECase(IMAGE_SYM_CLASS_BIT_FIELD);
+ ECase(IMAGE_SYM_CLASS_BLOCK);
+ ECase(IMAGE_SYM_CLASS_FUNCTION);
+ ECase(IMAGE_SYM_CLASS_END_OF_STRUCT);
+ ECase(IMAGE_SYM_CLASS_FILE);
+ ECase(IMAGE_SYM_CLASS_SECTION);
+ ECase(IMAGE_SYM_CLASS_WEAK_EXTERNAL);
+ ECase(IMAGE_SYM_CLASS_CLR_TOKEN);
+ }
+};
+
+template <>
+struct ScalarEnumerationTraits<COFF::SymbolBaseType> {
+ static void enumeration(IO &IO, COFF::SymbolBaseType &Value) {
+ ECase(IMAGE_SYM_TYPE_NULL);
+ ECase(IMAGE_SYM_TYPE_VOID);
+ ECase(IMAGE_SYM_TYPE_CHAR);
+ ECase(IMAGE_SYM_TYPE_SHORT);
+ ECase(IMAGE_SYM_TYPE_INT);
+ ECase(IMAGE_SYM_TYPE_LONG);
+ ECase(IMAGE_SYM_TYPE_FLOAT);
+ ECase(IMAGE_SYM_TYPE_DOUBLE);
+ ECase(IMAGE_SYM_TYPE_STRUCT);
+ ECase(IMAGE_SYM_TYPE_UNION);
+ ECase(IMAGE_SYM_TYPE_ENUM);
+ ECase(IMAGE_SYM_TYPE_MOE);
+ ECase(IMAGE_SYM_TYPE_BYTE);
+ ECase(IMAGE_SYM_TYPE_WORD);
+ ECase(IMAGE_SYM_TYPE_UINT);
+ ECase(IMAGE_SYM_TYPE_DWORD);
+ }
+};
+
+template <>
+struct ScalarEnumerationTraits<COFF::MachineTypes> {
+ static void enumeration(IO &IO, COFF::MachineTypes &Value) {
+ ECase(IMAGE_FILE_MACHINE_UNKNOWN);
+ ECase(IMAGE_FILE_MACHINE_AM33);
+ ECase(IMAGE_FILE_MACHINE_AMD64);
+ ECase(IMAGE_FILE_MACHINE_ARM);
+ ECase(IMAGE_FILE_MACHINE_ARMV7);
+ ECase(IMAGE_FILE_MACHINE_EBC);
+ ECase(IMAGE_FILE_MACHINE_I386);
+ ECase(IMAGE_FILE_MACHINE_IA64);
+ ECase(IMAGE_FILE_MACHINE_M32R);
+ ECase(IMAGE_FILE_MACHINE_MIPS16);
+ ECase(IMAGE_FILE_MACHINE_MIPSFPU);
+ ECase(IMAGE_FILE_MACHINE_MIPSFPU16);
+ ECase(IMAGE_FILE_MACHINE_POWERPC);
+ ECase(IMAGE_FILE_MACHINE_POWERPCFP);
+ ECase(IMAGE_FILE_MACHINE_R4000);
+ ECase(IMAGE_FILE_MACHINE_SH3);
+ ECase(IMAGE_FILE_MACHINE_SH3DSP);
+ ECase(IMAGE_FILE_MACHINE_SH4);
+ ECase(IMAGE_FILE_MACHINE_SH5);
+ ECase(IMAGE_FILE_MACHINE_THUMB);
+ ECase(IMAGE_FILE_MACHINE_WCEMIPSV2);
+ }
+};
+
+template <>
+struct ScalarEnumerationTraits<COFF::Characteristics> {
+ static void enumeration(IO &IO, COFF::Characteristics &Value) {
+ ECase(IMAGE_FILE_RELOCS_STRIPPED);
+ ECase(IMAGE_FILE_EXECUTABLE_IMAGE);
+ ECase(IMAGE_FILE_LINE_NUMS_STRIPPED);
+ ECase(IMAGE_FILE_LOCAL_SYMS_STRIPPED);
+ ECase(IMAGE_FILE_AGGRESSIVE_WS_TRIM);
+ ECase(IMAGE_FILE_LARGE_ADDRESS_AWARE);
+ ECase(IMAGE_FILE_BYTES_REVERSED_LO);
+ ECase(IMAGE_FILE_32BIT_MACHINE);
+ ECase(IMAGE_FILE_DEBUG_STRIPPED);
+ ECase(IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP);
+ ECase(IMAGE_FILE_NET_RUN_FROM_SWAP);
+ ECase(IMAGE_FILE_SYSTEM);
+ ECase(IMAGE_FILE_DLL);
+ ECase(IMAGE_FILE_UP_SYSTEM_ONLY);
+ ECase(IMAGE_FILE_BYTES_REVERSED_HI);
+ }
+};
+
+template <>
+struct ScalarEnumerationTraits<COFF::SectionCharacteristics> {
+ static void enumeration(IO &IO, COFF::SectionCharacteristics &Value) {
+ ECase(IMAGE_SCN_TYPE_NO_PAD);
+ ECase(IMAGE_SCN_CNT_CODE);
+ ECase(IMAGE_SCN_CNT_INITIALIZED_DATA);
+ ECase(IMAGE_SCN_CNT_UNINITIALIZED_DATA);
+ ECase(IMAGE_SCN_LNK_OTHER);
+ ECase(IMAGE_SCN_LNK_INFO);
+ ECase(IMAGE_SCN_LNK_REMOVE);
+ ECase(IMAGE_SCN_LNK_COMDAT);
+ ECase(IMAGE_SCN_GPREL);
+ ECase(IMAGE_SCN_MEM_PURGEABLE);
+ ECase(IMAGE_SCN_MEM_16BIT);
+ ECase(IMAGE_SCN_MEM_LOCKED);
+ ECase(IMAGE_SCN_MEM_PRELOAD);
+ ECase(IMAGE_SCN_ALIGN_1BYTES);
+ ECase(IMAGE_SCN_ALIGN_2BYTES);
+ ECase(IMAGE_SCN_ALIGN_4BYTES);
+ ECase(IMAGE_SCN_ALIGN_8BYTES);
+ ECase(IMAGE_SCN_ALIGN_16BYTES);
+ ECase(IMAGE_SCN_ALIGN_32BYTES);
+ ECase(IMAGE_SCN_ALIGN_64BYTES);
+ ECase(IMAGE_SCN_ALIGN_128BYTES);
+ ECase(IMAGE_SCN_ALIGN_256BYTES);
+ ECase(IMAGE_SCN_ALIGN_512BYTES);
+ ECase(IMAGE_SCN_ALIGN_1024BYTES);
+ ECase(IMAGE_SCN_ALIGN_2048BYTES);
+ ECase(IMAGE_SCN_ALIGN_4096BYTES);
+ ECase(IMAGE_SCN_ALIGN_8192BYTES);
+ ECase(IMAGE_SCN_LNK_NRELOC_OVFL);
+ ECase(IMAGE_SCN_MEM_DISCARDABLE);
+ ECase(IMAGE_SCN_MEM_NOT_CACHED);
+ ECase(IMAGE_SCN_MEM_NOT_PAGED);
+ ECase(IMAGE_SCN_MEM_SHARED);
+ ECase(IMAGE_SCN_MEM_EXECUTE);
+ ECase(IMAGE_SCN_MEM_READ);
+ ECase(IMAGE_SCN_MEM_WRITE);
+ }
+};
+
+template <>
+struct ScalarEnumerationTraits<COFF::RelocationTypeX86> {
+ static void enumeration(IO &IO, COFF::RelocationTypeX86 &Value) {
+ ECase(IMAGE_REL_I386_ABSOLUTE);
+ ECase(IMAGE_REL_I386_DIR16);
+ ECase(IMAGE_REL_I386_REL16);
+ ECase(IMAGE_REL_I386_DIR32);
+ ECase(IMAGE_REL_I386_DIR32NB);
+ ECase(IMAGE_REL_I386_SEG12);
+ ECase(IMAGE_REL_I386_SECTION);
+ ECase(IMAGE_REL_I386_SECREL);
+ ECase(IMAGE_REL_I386_TOKEN);
+ ECase(IMAGE_REL_I386_SECREL7);
+ ECase(IMAGE_REL_I386_REL32);
+ ECase(IMAGE_REL_AMD64_ABSOLUTE);
+ ECase(IMAGE_REL_AMD64_ADDR64);
+ ECase(IMAGE_REL_AMD64_ADDR32);
+ ECase(IMAGE_REL_AMD64_ADDR32NB);
+ ECase(IMAGE_REL_AMD64_REL32);
+ ECase(IMAGE_REL_AMD64_REL32_1);
+ ECase(IMAGE_REL_AMD64_REL32_2);
+ ECase(IMAGE_REL_AMD64_REL32_3);
+ ECase(IMAGE_REL_AMD64_REL32_4);
+ ECase(IMAGE_REL_AMD64_REL32_5);
+ ECase(IMAGE_REL_AMD64_SECTION);
+ ECase(IMAGE_REL_AMD64_SECREL);
+ ECase(IMAGE_REL_AMD64_SECREL7);
+ ECase(IMAGE_REL_AMD64_TOKEN);
+ ECase(IMAGE_REL_AMD64_SREL32);
+ ECase(IMAGE_REL_AMD64_PAIR);
+ ECase(IMAGE_REL_AMD64_SSPAN32);
+ }
+};
+
+#undef ECase
+
+template <>
+struct MappingTraits<COFFYAML::Symbol> {
+ static void mapping(IO &IO, COFFYAML::Symbol &S) {
+ IO.mapRequired("SimpleType", S.SimpleType);
+ IO.mapOptional("NumberOfAuxSymbols", S.NumberOfAuxSymbols);
+ IO.mapRequired("Name", S.Name);
+ IO.mapRequired("StorageClass", S.StorageClass);
+ IO.mapOptional("AuxillaryData", S.AuxillaryData); // FIXME: typo
+ IO.mapRequired("ComplexType", S.ComplexType);
+ IO.mapRequired("Value", S.Value);
+ IO.mapRequired("SectionNumber", S.SectionNumber);
+ }
+};
+
+template <>
+struct MappingTraits<COFFYAML::Header> {
+ static void mapping(IO &IO, COFFYAML::Header &H) {
+ IO.mapRequired("Machine", H.Machine);
+ IO.mapOptional("Characteristics", H.Characteristics);
+ }
+};
+
+template <>
+struct MappingTraits<COFFYAML::Relocation> {
+ static void mapping(IO &IO, COFFYAML::Relocation &Rel) {
+ IO.mapRequired("Type", Rel.Type);
+ IO.mapRequired("VirtualAddress", Rel.VirtualAddress);
+ IO.mapRequired("SymbolTableIndex", Rel.SymbolTableIndex);
+ }
+};
+
+template <>
+struct MappingTraits<COFFYAML::Section> {
+ static void mapping(IO &IO, COFFYAML::Section &Sec) {
+ IO.mapOptional("Relocations", Sec.Relocations);
+ IO.mapRequired("SectionData", Sec.SectionData);
+ IO.mapRequired("Characteristics", Sec.Characteristics);
+ IO.mapRequired("Name", Sec.Name);
+ }
+};
+
+template <>
+struct MappingTraits<COFFYAML::Object> {
+ static void mapping(IO &IO, COFFYAML::Object &Obj) {
+ IO.mapRequired("sections", Obj.Sections);
+ IO.mapRequired("header", Obj.HeaderData);
+ IO.mapRequired("symbols", Obj.Symbols);
+ }
+};
+} // end namespace yaml
+} // end namespace llvm
+
int main(int argc, char **argv) {
cl::ParseCommandLineOptions(argc, argv);
sys::PrintStackTraceOnErrorSignal();
@@ -864,13 +684,20 @@ int main(int argc, char **argv) {
if (MemoryBuffer::getFileOrSTDIN(Input, Buf))
return 1;
- SourceMgr SM;
- yaml::Stream S(Buf->getBuffer(), SM);
- COFFParser CP(S);
+ yaml::Input YIn(Buf->getBuffer());
+ COFFYAML::Object Doc;
+ YIn >> Doc;
+ if (YIn.error()) {
+ errs() << "yaml2obj: Failed to parse YAML file!\n";
+ return 1;
+ }
+
+ COFFParser CP(Doc);
if (!CP.parse()) {
errs() << "yaml2obj: Failed to parse YAML file!\n";
return 1;
}
+
if (!layoutCOFF(CP)) {
errs() << "yaml2obj: Failed to layout COFF file!\n";
return 1;
OpenPOWER on IntegriCloud