aboutsummaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2012-08-15 19:34:23 +0000
committerDimitry Andric <dim@FreeBSD.org>2012-08-15 19:34:23 +0000
commit58b69754af0cbff56b1cfce9be9392e4451f6628 (patch)
treeeacfc83d988e4b9d11114387ae7dc41243f2a363 /utils
parent0378662f5bd3dbe8305a485b0282bceb8b52f465 (diff)
downloadsrc-58b69754af0cbff56b1cfce9be9392e4451f6628.tar.gz
src-58b69754af0cbff56b1cfce9be9392e4451f6628.zip
Notes
Diffstat (limited to 'utils')
-rwxr-xr-xutils/GetRepositoryPath2
-rwxr-xr-xutils/GetSourceVersion2
-rw-r--r--utils/Makefile2
-rw-r--r--utils/TableGen/AsmMatcherEmitter.cpp458
-rw-r--r--utils/TableGen/AsmMatcherEmitter.h31
-rw-r--r--utils/TableGen/AsmWriterEmitter.cpp46
-rw-r--r--utils/TableGen/AsmWriterEmitter.h54
-rw-r--r--utils/TableGen/CMakeLists.txt2
-rw-r--r--utils/TableGen/CallingConvEmitter.cpp28
-rw-r--r--utils/TableGen/CallingConvEmitter.h36
-rw-r--r--utils/TableGen/CodeEmitterGen.cpp37
-rw-r--r--utils/TableGen/CodeEmitterGen.h49
-rw-r--r--utils/TableGen/CodeGenDAGPatterns.cpp43
-rw-r--r--utils/TableGen/CodeGenInstruction.cpp28
-rw-r--r--utils/TableGen/CodeGenInstruction.h4
-rw-r--r--utils/TableGen/CodeGenIntrinsics.h5
-rw-r--r--utils/TableGen/CodeGenRegisters.cpp629
-rw-r--r--utils/TableGen/CodeGenRegisters.h194
-rw-r--r--utils/TableGen/CodeGenSchedule.cpp151
-rw-r--r--utils/TableGen/CodeGenSchedule.h172
-rw-r--r--utils/TableGen/CodeGenTarget.cpp21
-rw-r--r--utils/TableGen/CodeGenTarget.h8
-rw-r--r--utils/TableGen/DAGISelEmitter.cpp28
-rw-r--r--utils/TableGen/DAGISelEmitter.h37
-rw-r--r--utils/TableGen/DAGISelMatcher.h2
-rw-r--r--utils/TableGen/DAGISelMatcherEmitter.cpp4
-rw-r--r--utils/TableGen/DAGISelMatcherGen.cpp7
-rw-r--r--utils/TableGen/DFAPacketizerEmitter.cpp125
-rw-r--r--utils/TableGen/DFAPacketizerEmitter.h52
-rw-r--r--utils/TableGen/DisassemblerEmitter.cpp47
-rw-r--r--utils/TableGen/DisassemblerEmitter.h28
-rw-r--r--utils/TableGen/EDEmitter.cpp340
-rw-r--r--utils/TableGen/EDEmitter.h34
-rw-r--r--utils/TableGen/FastISelEmitter.cpp39
-rw-r--r--utils/TableGen/FastISelEmitter.h39
-rw-r--r--utils/TableGen/FixedLenDecoderEmitter.cpp85
-rw-r--r--utils/TableGen/FixedLenDecoderEmitter.h79
-rw-r--r--utils/TableGen/InstrInfoEmitter.cpp72
-rw-r--r--utils/TableGen/InstrInfoEmitter.h62
-rw-r--r--utils/TableGen/IntrinsicEmitter.cpp635
-rw-r--r--utils/TableGen/IntrinsicEmitter.h61
-rw-r--r--utils/TableGen/PseudoLoweringEmitter.cpp63
-rw-r--r--utils/TableGen/PseudoLoweringEmitter.h65
-rw-r--r--utils/TableGen/RegisterInfoEmitter.cpp626
-rw-r--r--utils/TableGen/RegisterInfoEmitter.h64
-rw-r--r--utils/TableGen/SequenceToOffsetTable.h2
-rw-r--r--utils/TableGen/SetTheory.cpp20
-rw-r--r--utils/TableGen/StringMatcher.cpp149
-rw-r--r--utils/TableGen/StringMatcher.h54
-rw-r--r--utils/TableGen/StringToOffsetTable.h1
-rw-r--r--utils/TableGen/SubtargetEmitter.cpp370
-rw-r--r--utils/TableGen/SubtargetEmitter.h72
-rw-r--r--utils/TableGen/TableGen.cpp51
-rw-r--r--utils/TableGen/TableGenBackends.h78
-rw-r--r--utils/TableGen/X86DisassemblerShared.h1
-rw-r--r--utils/TableGen/X86DisassemblerTables.cpp237
-rw-r--r--utils/TableGen/X86DisassemblerTables.h50
-rw-r--r--utils/TableGen/X86RecognizableInstr.cpp241
-rw-r--r--utils/TableGen/X86RecognizableInstr.h2
-rwxr-xr-xutils/UpdateCMakeLists.pl3
-rwxr-xr-xutils/buildit/build_llvm2
-rwxr-xr-xutils/findmisopt3
-rw-r--r--utils/lit/lit/TestRunner.py72
-rw-r--r--utils/llvm-build/llvmbuild/main.py2
-rw-r--r--utils/llvm-lit/llvm-lit.in5
-rw-r--r--utils/llvm.grm1
-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/release/test-release.sh2
-rwxr-xr-xutils/test_debuginfo.pl4
-rw-r--r--utils/unittest/CMakeLists.txt6
-rw-r--r--utils/unittest/googletest/gtest.cc2
-rw-r--r--utils/unittest/googletest/include/gtest/internal/gtest-internal-inl.h1
-rw-r--r--utils/unittest/googletest/include/gtest/internal/gtest-internal.h3
-rw-r--r--utils/vim/llvm.vim4
-rw-r--r--utils/yaml2obj/CMakeLists.txt5
-rw-r--r--utils/yaml2obj/Makefile20
-rw-r--r--utils/yaml2obj/yaml2obj.cpp879
81 files changed, 4680 insertions, 2771 deletions
diff --git a/utils/GetRepositoryPath b/utils/GetRepositoryPath
index 326231c9e5d4..f3b0cc56e255 100755
--- a/utils/GetRepositoryPath
+++ b/utils/GetRepositoryPath
@@ -16,7 +16,7 @@ fi
cd $1
if [ -d .svn ]; then
svn info | grep 'URL:' | cut -d: -f2-
-elif [ -d .git/svn ]; then
+elif [ -f .git/svn/.metadata ]; then
git svn info | grep 'URL:' | cut -d: -f2-
elif [ -d .git ]; then
git remote -v | grep 'fetch' | awk '{ print $2 }'
diff --git a/utils/GetSourceVersion b/utils/GetSourceVersion
index cbed7daf5b61..b57a6aa2f3af 100755
--- a/utils/GetSourceVersion
+++ b/utils/GetSourceVersion
@@ -16,7 +16,7 @@ fi
cd $1
if [ -d .svn ]; then
svnversion | sed -e "s#\([0-9]*\)[A-Z]*#\1#"
-elif [ -d .git/svn ]; then
+elif [ -f .git/svn/.metadata ]; then
git svn info | grep 'Revision:' | cut -d: -f2-
elif [ -d .git ]; then
git log -1 --pretty=format:%H
diff --git a/utils/Makefile b/utils/Makefile
index ecb30bed7c63..7a3c17d0325a 100644
--- a/utils/Makefile
+++ b/utils/Makefile
@@ -9,7 +9,7 @@
LEVEL = ..
PARALLEL_DIRS := FileCheck FileUpdate TableGen PerfectShuffle \
- count fpcmp llvm-lit not unittest
+ count fpcmp llvm-lit not unittest yaml2obj
EXTRA_DIST := check-each-file codegen-diff countloc.sh \
DSAclean.py DSAextract.py emacs findsym.pl GenLibDeps.pl \
diff --git a/utils/TableGen/AsmMatcherEmitter.cpp b/utils/TableGen/AsmMatcherEmitter.cpp
index dc92a6c218e9..026d47f4bd77 100644
--- a/utils/TableGen/AsmMatcherEmitter.cpp
+++ b/utils/TableGen/AsmMatcherEmitter.cpp
@@ -96,9 +96,7 @@
//
//===----------------------------------------------------------------------===//
-#include "AsmMatcherEmitter.h"
#include "CodeGenTarget.h"
-#include "StringMatcher.h"
#include "StringToOffsetTable.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/PointerUnion.h"
@@ -111,6 +109,9 @@
#include "llvm/Support/ErrorHandling.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
+#include "llvm/TableGen/StringMatcher.h"
+#include "llvm/TableGen/TableGenBackend.h"
+#include <cassert>
#include <map>
#include <set>
using namespace llvm;
@@ -123,6 +124,14 @@ namespace {
class AsmMatcherInfo;
struct SubtargetFeatureInfo;
+class AsmMatcherEmitter {
+ RecordKeeper &Records;
+public:
+ AsmMatcherEmitter(RecordKeeper &R) : Records(R) {}
+
+ void run(raw_ostream &o);
+};
+
/// ClassInfo - Helper class for storing the information about a particular
/// class of operands which can be matched.
struct ClassInfo {
@@ -177,6 +186,8 @@ struct ClassInfo {
/// For register classes, the records for all the registers in this class.
std::set<Record*> Registers;
+ /// For custom match classes, he diagnostic kind for when the predicate fails.
+ std::string DiagnosticType;
public:
/// isRegisterClass() - Check if this is a register class.
bool isRegisterClass() const {
@@ -385,7 +396,7 @@ struct MatchableInfo {
/// ResOperands - This is the operand list that should be built for the result
/// MCInst.
- std::vector<ResOperand> ResOperands;
+ SmallVector<ResOperand, 8> ResOperands;
/// AsmString - The assembly string for this instruction (with variants
/// removed), e.g. "movsx $src, $dst".
@@ -399,7 +410,7 @@ struct MatchableInfo {
/// annotated with a class and where in the OperandList they were defined.
/// This directly corresponds to the tokenized AsmString after the mnemonic is
/// removed.
- SmallVector<AsmOperand, 4> AsmOperands;
+ SmallVector<AsmOperand, 8> AsmOperands;
/// Predicates - The required subtarget features to match this instruction.
SmallVector<SubtargetFeatureInfo*, 4> RequiredFeatures;
@@ -419,13 +430,17 @@ struct MatchableInfo {
AsmString(Alias->AsmString) {
}
- void Initialize(const AsmMatcherInfo &Info,
+ // Two-operand aliases clone from the main matchable, but mark the second
+ // operand as a tied operand of the first for purposes of the assembler.
+ void formTwoOperandAlias(StringRef Constraint);
+
+ void initialize(const AsmMatcherInfo &Info,
SmallPtrSet<Record*, 16> &SingletonRegisters,
int AsmVariantNo, std::string &RegisterPrefix);
- /// Validate - Return true if this matchable is a valid thing to match against
+ /// validate - Return true if this matchable is a valid thing to match against
/// and perform a bunch of validity checking.
- bool Validate(StringRef CommentDelimiter, bool Hack) const;
+ bool validate(StringRef CommentDelimiter, bool Hack) const;
/// extractSingletonRegisterForAsmOperand - Extract singleton register,
/// if present, from specified token.
@@ -433,9 +448,9 @@ struct MatchableInfo {
extractSingletonRegisterForAsmOperand(unsigned i, const AsmMatcherInfo &Info,
std::string &RegisterPrefix);
- /// FindAsmOperand - Find the AsmOperand with the specified name and
+ /// findAsmOperand - Find the AsmOperand with the specified name and
/// suboperand index.
- int FindAsmOperand(StringRef N, int SubOpIdx) const {
+ int findAsmOperand(StringRef N, int SubOpIdx) const {
for (unsigned i = 0, e = AsmOperands.size(); i != e; ++i)
if (N == AsmOperands[i].SrcOpName &&
SubOpIdx == AsmOperands[i].SubOpIdx)
@@ -443,17 +458,17 @@ struct MatchableInfo {
return -1;
}
- /// FindAsmOperandNamed - Find the first AsmOperand with the specified name.
+ /// findAsmOperandNamed - Find the first AsmOperand with the specified name.
/// This does not check the suboperand index.
- int FindAsmOperandNamed(StringRef N) const {
+ int findAsmOperandNamed(StringRef N) const {
for (unsigned i = 0, e = AsmOperands.size(); i != e; ++i)
if (N == AsmOperands[i].SrcOpName)
return i;
return -1;
}
- void BuildInstructionResultOperands();
- void BuildAliasResultOperands();
+ void buildInstructionResultOperands();
+ void buildAliasResultOperands();
/// operator< - Compare two matchables.
bool operator<(const MatchableInfo &RHS) const {
@@ -465,7 +480,7 @@ struct MatchableInfo {
return AsmOperands.size() < RHS.AsmOperands.size();
// Compare lexicographically by operand. The matcher validates that other
- // orderings wouldn't be ambiguous using \see CouldMatchAmbiguouslyWith().
+ // orderings wouldn't be ambiguous using \see couldMatchAmbiguouslyWith().
for (unsigned i = 0, e = AsmOperands.size(); i != e; ++i) {
if (*AsmOperands[i].Class < *RHS.AsmOperands[i].Class)
return true;
@@ -476,10 +491,10 @@ struct MatchableInfo {
return false;
}
- /// CouldMatchAmbiguouslyWith - Check whether this matchable could
+ /// couldMatchAmbiguouslyWith - Check whether this matchable could
/// ambiguously match the same set of operands as \arg RHS (without being a
/// strictly superior match).
- bool CouldMatchAmbiguouslyWith(const MatchableInfo &RHS) {
+ bool couldMatchAmbiguouslyWith(const MatchableInfo &RHS) {
// The primary comparator is the instruction mnemonic.
if (Mnemonic != RHS.Mnemonic)
return false;
@@ -518,7 +533,7 @@ struct MatchableInfo {
void dump();
private:
- void TokenizeAsmString(const AsmMatcherInfo &Info);
+ void tokenizeAsmString(const AsmMatcherInfo &Info);
};
/// SubtargetFeatureInfo - Helper class for storing information on a subtarget
@@ -543,7 +558,7 @@ struct OperandMatchEntry {
MatchableInfo* MI;
ClassInfo *CI;
- static OperandMatchEntry Create(MatchableInfo* mi, ClassInfo *ci,
+ static OperandMatchEntry create(MatchableInfo* mi, ClassInfo *ci,
unsigned opMask) {
OperandMatchEntry X;
X.OperandMask = opMask;
@@ -580,6 +595,9 @@ public:
/// Map of Predicate records to their subtarget information.
std::map<Record*, SubtargetFeatureInfo*> SubtargetFeatures;
+ /// Map of AsmOperandClass records to their class information.
+ std::map<Record*, ClassInfo*> AsmOperandClasses;
+
private:
/// Map of token to class information which has already been constructed.
std::map<std::string, ClassInfo*> TokenClasses;
@@ -587,9 +605,6 @@ private:
/// Map of RegisterClass records to their class information.
std::map<Record*, ClassInfo*> RegisterClassClasses;
- /// Map of AsmOperandClass records to their class information.
- std::map<Record*, ClassInfo*> AsmOperandClasses;
-
private:
/// getTokenClass - Lookup or create the class for the given token.
ClassInfo *getTokenClass(StringRef Token);
@@ -599,17 +614,17 @@ private:
int SubOpIdx);
ClassInfo *getOperandClass(Record *Rec, int SubOpIdx);
- /// BuildRegisterClasses - Build the ClassInfo* instances for register
+ /// buildRegisterClasses - Build the ClassInfo* instances for register
/// classes.
- void BuildRegisterClasses(SmallPtrSet<Record*, 16> &SingletonRegisters);
+ void buildRegisterClasses(SmallPtrSet<Record*, 16> &SingletonRegisters);
- /// BuildOperandClasses - Build the ClassInfo* instances for user defined
+ /// buildOperandClasses - Build the ClassInfo* instances for user defined
/// operand classes.
- void BuildOperandClasses();
+ void buildOperandClasses();
- void BuildInstructionOperandReference(MatchableInfo *II, StringRef OpName,
+ void buildInstructionOperandReference(MatchableInfo *II, StringRef OpName,
unsigned AsmOpIdx);
- void BuildAliasOperandReference(MatchableInfo *II, StringRef OpName,
+ void buildAliasOperandReference(MatchableInfo *II, StringRef OpName,
MatchableInfo::AsmOperand &Op);
public:
@@ -617,12 +632,12 @@ public:
CodeGenTarget &Target,
RecordKeeper &Records);
- /// BuildInfo - Construct the various tables used during matching.
- void BuildInfo();
+ /// buildInfo - Construct the various tables used during matching.
+ void buildInfo();
- /// BuildOperandMatchInfo - Build the necessary information to handle user
+ /// buildOperandMatchInfo - Build the necessary information to handle user
/// defined operand parsing methods.
- void BuildOperandMatchInfo();
+ void buildOperandMatchInfo();
/// getSubtargetFeature - Lookup or create the subtarget feature info for the
/// given operand.
@@ -638,7 +653,7 @@ public:
}
};
-}
+} // End anonymous namespace
void MatchableInfo::dump() {
errs() << TheDef->getName() << " -- " << "flattened:\"" << AsmString <<"\"\n";
@@ -650,14 +665,86 @@ void MatchableInfo::dump() {
}
}
-void MatchableInfo::Initialize(const AsmMatcherInfo &Info,
+static std::pair<StringRef, StringRef>
+parseTwoOperandConstraint(StringRef S, SMLoc Loc) {
+ // Split via the '='.
+ std::pair<StringRef, StringRef> Ops = S.split('=');
+ if (Ops.second == "")
+ throw TGError(Loc, "missing '=' in two-operand alias constraint");
+ // Trim whitespace and the leading '$' on the operand names.
+ size_t start = Ops.first.find_first_of('$');
+ if (start == std::string::npos)
+ throw TGError(Loc, "expected '$' prefix on asm operand name");
+ Ops.first = Ops.first.slice(start + 1, std::string::npos);
+ size_t end = Ops.first.find_last_of(" \t");
+ Ops.first = Ops.first.slice(0, end);
+ // Now the second operand.
+ start = Ops.second.find_first_of('$');
+ if (start == std::string::npos)
+ throw TGError(Loc, "expected '$' prefix on asm operand name");
+ Ops.second = Ops.second.slice(start + 1, std::string::npos);
+ end = Ops.second.find_last_of(" \t");
+ Ops.first = Ops.first.slice(0, end);
+ return Ops;
+}
+
+void MatchableInfo::formTwoOperandAlias(StringRef Constraint) {
+ // Figure out which operands are aliased and mark them as tied.
+ std::pair<StringRef, StringRef> Ops =
+ parseTwoOperandConstraint(Constraint, TheDef->getLoc());
+
+ // Find the AsmOperands that refer to the operands we're aliasing.
+ int SrcAsmOperand = findAsmOperandNamed(Ops.first);
+ int DstAsmOperand = findAsmOperandNamed(Ops.second);
+ if (SrcAsmOperand == -1)
+ throw TGError(TheDef->getLoc(),
+ "unknown source two-operand alias operand '" +
+ Ops.first.str() + "'.");
+ if (DstAsmOperand == -1)
+ throw TGError(TheDef->getLoc(),
+ "unknown destination two-operand alias operand '" +
+ Ops.second.str() + "'.");
+
+ // Find the ResOperand that refers to the operand we're aliasing away
+ // and update it to refer to the combined operand instead.
+ for (unsigned i = 0, e = ResOperands.size(); i != e; ++i) {
+ ResOperand &Op = ResOperands[i];
+ if (Op.Kind == ResOperand::RenderAsmOperand &&
+ Op.AsmOperandNum == (unsigned)SrcAsmOperand) {
+ Op.AsmOperandNum = DstAsmOperand;
+ break;
+ }
+ }
+ // Remove the AsmOperand for the alias operand.
+ AsmOperands.erase(AsmOperands.begin() + SrcAsmOperand);
+ // Adjust the ResOperand references to any AsmOperands that followed
+ // the one we just deleted.
+ for (unsigned i = 0, e = ResOperands.size(); i != e; ++i) {
+ ResOperand &Op = ResOperands[i];
+ switch(Op.Kind) {
+ default:
+ // Nothing to do for operands that don't reference AsmOperands.
+ break;
+ case ResOperand::RenderAsmOperand:
+ if (Op.AsmOperandNum > (unsigned)SrcAsmOperand)
+ --Op.AsmOperandNum;
+ break;
+ case ResOperand::TiedOperand:
+ if (Op.TiedOperandNum > (unsigned)SrcAsmOperand)
+ --Op.TiedOperandNum;
+ break;
+ }
+ }
+}
+
+void MatchableInfo::initialize(const AsmMatcherInfo &Info,
SmallPtrSet<Record*, 16> &SingletonRegisters,
int AsmVariantNo, std::string &RegisterPrefix) {
AsmVariantID = AsmVariantNo;
AsmString =
CodeGenInstruction::FlattenAsmStringVariants(AsmString, AsmVariantNo);
- TokenizeAsmString(Info);
+ tokenizeAsmString(Info);
// Compute the require features.
std::vector<Record*> Predicates =TheDef->getValueAsListOfDefs("Predicates");
@@ -674,8 +761,8 @@ void MatchableInfo::Initialize(const AsmMatcherInfo &Info,
}
}
-/// TokenizeAsmString - Tokenize a simplified assembly string.
-void MatchableInfo::TokenizeAsmString(const AsmMatcherInfo &Info) {
+/// tokenizeAsmString - Tokenize a simplified assembly string.
+void MatchableInfo::tokenizeAsmString(const AsmMatcherInfo &Info) {
StringRef String = AsmString;
unsigned Prev = 0;
bool InTok = true;
@@ -749,6 +836,9 @@ void MatchableInfo::TokenizeAsmString(const AsmMatcherInfo &Info) {
throw TGError(TheDef->getLoc(),
"Instruction '" + TheDef->getName() + "' has no tokens");
Mnemonic = AsmOperands[0].Token;
+ if (Mnemonic.empty())
+ throw TGError(TheDef->getLoc(),
+ "Missing instruction mnemonic");
// FIXME : Check and raise an error if it is a register.
if (Mnemonic[0] == '$')
throw TGError(TheDef->getLoc(),
@@ -758,7 +848,7 @@ void MatchableInfo::TokenizeAsmString(const AsmMatcherInfo &Info) {
AsmOperands.erase(AsmOperands.begin());
}
-bool MatchableInfo::Validate(StringRef CommentDelimiter, bool Hack) const {
+bool MatchableInfo::validate(StringRef CommentDelimiter, bool Hack) const {
// Reject matchables with no .s string.
if (AsmString.empty())
throw TGError(TheDef->getLoc(), "instruction with empty asm string");
@@ -872,6 +962,7 @@ ClassInfo *AsmMatcherInfo::getTokenClass(StringRef Token) {
Entry->PredicateMethod = "<invalid>";
Entry->RenderMethod = "<invalid>";
Entry->ParserMethod = "";
+ Entry->DiagnosticType = "";
Classes.push_back(Entry);
}
@@ -929,7 +1020,7 @@ AsmMatcherInfo::getOperandClass(Record *Rec, int SubOpIdx) {
}
void AsmMatcherInfo::
-BuildRegisterClasses(SmallPtrSet<Record*, 16> &SingletonRegisters) {
+buildRegisterClasses(SmallPtrSet<Record*, 16> &SingletonRegisters) {
const std::vector<CodeGenRegister*> &Registers =
Target.getRegBank().getRegisters();
ArrayRef<CodeGenRegisterClass*> RegClassList =
@@ -997,6 +1088,8 @@ BuildRegisterClasses(SmallPtrSet<Record*, 16> &SingletonRegisters) {
CI->PredicateMethod = ""; // unused
CI->RenderMethod = "addRegOperands";
CI->Registers = *it;
+ // FIXME: diagnostic type.
+ CI->DiagnosticType = "";
Classes.push_back(CI);
RegisterSetClasses.insert(std::make_pair(*it, CI));
}
@@ -1054,7 +1147,7 @@ BuildRegisterClasses(SmallPtrSet<Record*, 16> &SingletonRegisters) {
}
}
-void AsmMatcherInfo::BuildOperandClasses() {
+void AsmMatcherInfo::buildOperandClasses() {
std::vector<Record*> AsmOperands =
Records.getAllDerivedDefinitions("AsmOperandClass");
@@ -1112,6 +1205,12 @@ void AsmMatcherInfo::BuildOperandClasses() {
if (StringInit *SI = dynamic_cast<StringInit*>(PRMName))
CI->ParserMethod = SI->getValue();
+ // Get the diagnostic type or leave it as empty.
+ // Get the parse method name or leave it as empty.
+ Init *DiagnosticType = (*it)->getValueInit("DiagnosticType");
+ if (StringInit *SI = dynamic_cast<StringInit*>(DiagnosticType))
+ CI->DiagnosticType = SI->getValue();
+
AsmOperandClasses[*it] = CI;
Classes.push_back(CI);
}
@@ -1123,11 +1222,11 @@ AsmMatcherInfo::AsmMatcherInfo(Record *asmParser,
: Records(records), AsmParser(asmParser), Target(target) {
}
-/// BuildOperandMatchInfo - Build the necessary information to handle user
+/// buildOperandMatchInfo - Build the necessary information to handle user
/// defined operand parsing methods.
-void AsmMatcherInfo::BuildOperandMatchInfo() {
+void AsmMatcherInfo::buildOperandMatchInfo() {
- /// Map containing a mask with all operands indicies that can be found for
+ /// Map containing a mask with all operands indices that can be found for
/// that class inside a instruction.
std::map<ClassInfo*, unsigned> OpClassMask;
@@ -1152,12 +1251,12 @@ void AsmMatcherInfo::BuildOperandMatchInfo() {
iie = OpClassMask.end(); iit != iie; ++iit) {
unsigned OpMask = iit->second;
ClassInfo *CI = iit->first;
- OperandMatchInfo.push_back(OperandMatchEntry::Create(&II, CI, OpMask));
+ OperandMatchInfo.push_back(OperandMatchEntry::create(&II, CI, OpMask));
}
}
}
-void AsmMatcherInfo::BuildInfo() {
+void AsmMatcherInfo::buildInfo() {
// Build information about all of the AssemblerPredicates.
std::vector<Record*> AllPredicates =
Records.getAllDerivedDefinitions("Predicate");
@@ -1222,11 +1321,11 @@ void AsmMatcherInfo::BuildInfo() {
OwningPtr<MatchableInfo> II(new MatchableInfo(CGI));
- II->Initialize(*this, SingletonRegisters, AsmVariantNo, RegisterPrefix);
+ II->initialize(*this, SingletonRegisters, AsmVariantNo, RegisterPrefix);
// Ignore instructions which shouldn't be matched and diagnose invalid
// instruction definitions with an error.
- if (!II->Validate(CommentDelimiter, true))
+ if (!II->validate(CommentDelimiter, true))
continue;
// Ignore "Int_*" and "*_Int" instructions, which are internal aliases.
@@ -1255,29 +1354,30 @@ void AsmMatcherInfo::BuildInfo() {
OwningPtr<MatchableInfo> II(new MatchableInfo(Alias));
- II->Initialize(*this, SingletonRegisters, AsmVariantNo, RegisterPrefix);
+ II->initialize(*this, SingletonRegisters, AsmVariantNo, RegisterPrefix);
// Validate the alias definitions.
- II->Validate(CommentDelimiter, false);
+ II->validate(CommentDelimiter, false);
Matchables.push_back(II.take());
}
}
// Build info for the register classes.
- BuildRegisterClasses(SingletonRegisters);
+ buildRegisterClasses(SingletonRegisters);
// Build info for the user defined assembly operand classes.
- BuildOperandClasses();
+ buildOperandClasses();
// Build the information about matchables, now that we have fully formed
// classes.
+ std::vector<MatchableInfo*> NewMatchables;
for (std::vector<MatchableInfo*>::iterator it = Matchables.begin(),
ie = Matchables.end(); it != ie; ++it) {
MatchableInfo *II = *it;
// Parse the tokens after the mnemonic.
- // Note: BuildInstructionOperandReference may insert new AsmOperands, so
+ // Note: buildInstructionOperandReference may insert new AsmOperands, so
// don't precompute the loop bound.
for (unsigned i = 0; i != II->AsmOperands.size(); ++i) {
MatchableInfo::AsmOperand &Op = II->AsmOperands[i];
@@ -1310,16 +1410,34 @@ void AsmMatcherInfo::BuildInfo() {
OperandName = Token.substr(1);
if (II->DefRec.is<const CodeGenInstruction*>())
- BuildInstructionOperandReference(II, OperandName, i);
+ buildInstructionOperandReference(II, OperandName, i);
else
- BuildAliasOperandReference(II, OperandName, Op);
+ buildAliasOperandReference(II, OperandName, Op);
}
- if (II->DefRec.is<const CodeGenInstruction*>())
- II->BuildInstructionResultOperands();
- else
- II->BuildAliasResultOperands();
+ if (II->DefRec.is<const CodeGenInstruction*>()) {
+ II->buildInstructionResultOperands();
+ // If the instruction has a two-operand alias, build up the
+ // matchable here. We'll add them in bulk at the end to avoid
+ // confusing this loop.
+ std::string Constraint =
+ II->TheDef->getValueAsString("TwoOperandAliasConstraint");
+ if (Constraint != "") {
+ // Start by making a copy of the original matchable.
+ OwningPtr<MatchableInfo> AliasII(new MatchableInfo(*II));
+
+ // Adjust it to be a two-operand alias.
+ AliasII->formTwoOperandAlias(Constraint);
+
+ // Add the alias to the matchables list.
+ NewMatchables.push_back(AliasII.take());
+ }
+ } else
+ II->buildAliasResultOperands();
}
+ if (!NewMatchables.empty())
+ Matchables.insert(Matchables.end(), NewMatchables.begin(),
+ NewMatchables.end());
// Process token alias definitions and set up the associated superclass
// information.
@@ -1339,10 +1457,10 @@ void AsmMatcherInfo::BuildInfo() {
std::sort(Classes.begin(), Classes.end(), less_ptr<ClassInfo>());
}
-/// BuildInstructionOperandReference - The specified operand is a reference to a
+/// buildInstructionOperandReference - The specified operand is a reference to a
/// named operand such as $src. Resolve the Class and OperandInfo pointers.
void AsmMatcherInfo::
-BuildInstructionOperandReference(MatchableInfo *II,
+buildInstructionOperandReference(MatchableInfo *II,
StringRef OperandName,
unsigned AsmOpIdx) {
const CodeGenInstruction &CGI = *II->DefRec.get<const CodeGenInstruction*>();
@@ -1399,10 +1517,10 @@ BuildInstructionOperandReference(MatchableInfo *II,
Op->SrcOpName = OperandName;
}
-/// BuildAliasOperandReference - When parsing an operand reference out of the
+/// buildAliasOperandReference - When parsing an operand reference out of the
/// matching string (e.g. "movsx $src, $dst"), determine what the class of the
/// operand reference is by looking it up in the result pattern definition.
-void AsmMatcherInfo::BuildAliasOperandReference(MatchableInfo *II,
+void AsmMatcherInfo::buildAliasOperandReference(MatchableInfo *II,
StringRef OperandName,
MatchableInfo::AsmOperand &Op) {
const CodeGenInstAlias &CGA = *II->DefRec.get<const CodeGenInstAlias*>();
@@ -1427,7 +1545,7 @@ void AsmMatcherInfo::BuildAliasOperandReference(MatchableInfo *II,
OperandName.str() + "'");
}
-void MatchableInfo::BuildInstructionResultOperands() {
+void MatchableInfo::buildInstructionResultOperands() {
const CodeGenInstruction *ResultInst = getResultInst();
// Loop over all operands of the result instruction, determining how to
@@ -1443,7 +1561,7 @@ void MatchableInfo::BuildInstructionResultOperands() {
}
// Find out what operand from the asmparser this MCInst operand comes from.
- int SrcOperand = FindAsmOperandNamed(OpInfo.Name);
+ int SrcOperand = findAsmOperandNamed(OpInfo.Name);
if (OpInfo.Name.empty() || SrcOperand == -1)
throw TGError(TheDef->getLoc(), "Instruction '" +
TheDef->getName() + "' has operand '" + OpInfo.Name +
@@ -1466,7 +1584,7 @@ void MatchableInfo::BuildInstructionResultOperands() {
}
}
-void MatchableInfo::BuildAliasResultOperands() {
+void MatchableInfo::buildAliasResultOperands() {
const CodeGenInstAlias &CGA = *DefRec.get<const CodeGenInstAlias*>();
const CodeGenInstruction *ResultInst = getResultInst();
@@ -1495,7 +1613,7 @@ void MatchableInfo::BuildAliasResultOperands() {
switch (CGA.ResultOperands[AliasOpNo].Kind) {
case CodeGenInstAlias::ResultOperand::K_Record: {
StringRef Name = CGA.ResultOperands[AliasOpNo].getName();
- int SrcOperand = FindAsmOperand(Name, SubIdx);
+ int SrcOperand = findAsmOperand(Name, SubIdx);
if (SrcOperand == -1)
throw TGError(TheDef->getLoc(), "Instruction '" +
TheDef->getName() + "' has operand '" + OpName +
@@ -1520,7 +1638,7 @@ void MatchableInfo::BuildAliasResultOperands() {
}
}
-static void EmitConvertToMCInst(CodeGenTarget &Target, StringRef ClassName,
+static void emitConvertToMCInst(CodeGenTarget &Target, StringRef ClassName,
std::vector<MatchableInfo*> &Infos,
raw_ostream &OS) {
// Write the convert function to a separate stream, so we can drop it after
@@ -1661,8 +1779,8 @@ static void EmitConvertToMCInst(CodeGenTarget &Target, StringRef ClassName,
OS << CvtOS.str();
}
-/// EmitMatchClassEnumeration - Emit the enumeration for match class kinds.
-static void EmitMatchClassEnumeration(CodeGenTarget &Target,
+/// emitMatchClassEnumeration - Emit the enumeration for match class kinds.
+static void emitMatchClassEnumeration(CodeGenTarget &Target,
std::vector<ClassInfo*> &Infos,
raw_ostream &OS) {
OS << "namespace {\n\n";
@@ -1692,37 +1810,24 @@ static void EmitMatchClassEnumeration(CodeGenTarget &Target,
OS << "}\n\n";
}
-/// EmitValidateOperandClass - Emit the function to validate an operand class.
-static void EmitValidateOperandClass(AsmMatcherInfo &Info,
+/// emitValidateOperandClass - Emit the function to validate an operand class.
+static void emitValidateOperandClass(AsmMatcherInfo &Info,
raw_ostream &OS) {
- OS << "static bool validateOperandClass(MCParsedAsmOperand *GOp, "
+ OS << "static unsigned validateOperandClass(MCParsedAsmOperand *GOp, "
<< "MatchClassKind Kind) {\n";
OS << " " << Info.Target.getName() << "Operand &Operand = *("
<< Info.Target.getName() << "Operand*)GOp;\n";
// The InvalidMatchClass is not to match any operand.
OS << " if (Kind == InvalidMatchClass)\n";
- OS << " return false;\n\n";
+ OS << " return MCTargetAsmParser::Match_InvalidOperand;\n\n";
// Check for Token operands first.
+ // FIXME: Use a more specific diagnostic type.
OS << " if (Operand.isToken())\n";
- OS << " return isSubclass(matchTokenString(Operand.getToken()), Kind);"
- << "\n\n";
-
- // Check for register operands, including sub-classes.
- OS << " if (Operand.isReg()) {\n";
- OS << " MatchClassKind OpKind;\n";
- OS << " switch (Operand.getReg()) {\n";
- OS << " default: OpKind = InvalidMatchClass; break;\n";
- for (std::map<Record*, ClassInfo*>::iterator
- it = Info.RegisterClasses.begin(), ie = Info.RegisterClasses.end();
- it != ie; ++it)
- OS << " case " << Info.Target.getName() << "::"
- << it->first->getName() << ": OpKind = " << it->second->Name
- << "; break;\n";
- OS << " }\n";
- OS << " return isSubclass(OpKind, Kind);\n";
- OS << " }\n\n";
+ OS << " return isSubclass(matchTokenString(Operand.getToken()), Kind) ?\n"
+ << " MCTargetAsmParser::Match_Success :\n"
+ << " MCTargetAsmParser::Match_InvalidOperand;\n\n";
// Check the user classes. We don't care what order since we're only
// actually matching against one of them.
@@ -1734,18 +1839,39 @@ static void EmitValidateOperandClass(AsmMatcherInfo &Info,
continue;
OS << " // '" << CI.ClassName << "' class\n";
- OS << " if (Kind == " << CI.Name
- << " && Operand." << CI.PredicateMethod << "()) {\n";
- OS << " return true;\n";
+ OS << " if (Kind == " << CI.Name << ") {\n";
+ OS << " if (Operand." << CI.PredicateMethod << "())\n";
+ OS << " return MCTargetAsmParser::Match_Success;\n";
+ if (!CI.DiagnosticType.empty())
+ OS << " return " << Info.Target.getName() << "AsmParser::Match_"
+ << CI.DiagnosticType << ";\n";
OS << " }\n\n";
}
- OS << " return false;\n";
+ // Check for register operands, including sub-classes.
+ OS << " if (Operand.isReg()) {\n";
+ OS << " MatchClassKind OpKind;\n";
+ OS << " switch (Operand.getReg()) {\n";
+ OS << " default: OpKind = InvalidMatchClass; break;\n";
+ for (std::map<Record*, ClassInfo*>::iterator
+ it = Info.RegisterClasses.begin(), ie = Info.RegisterClasses.end();
+ it != ie; ++it)
+ OS << " case " << Info.Target.getName() << "::"
+ << it->first->getName() << ": OpKind = " << it->second->Name
+ << "; break;\n";
+ OS << " }\n";
+ OS << " return isSubclass(OpKind, Kind) ? "
+ << "MCTargetAsmParser::Match_Success :\n "
+ << " MCTargetAsmParser::Match_InvalidOperand;\n }\n\n";
+
+ // Generic fallthrough match failure case for operands that don't have
+ // specialized diagnostic types.
+ OS << " return MCTargetAsmParser::Match_InvalidOperand;\n";
OS << "}\n\n";
}
-/// EmitIsSubclass - Emit the subclass predicate function.
-static void EmitIsSubclass(CodeGenTarget &Target,
+/// emitIsSubclass - Emit the subclass predicate function.
+static void emitIsSubclass(CodeGenTarget &Target,
std::vector<ClassInfo*> &Infos,
raw_ostream &OS) {
OS << "/// isSubclass - Compute whether \\arg A is a subclass of \\arg B.\n";
@@ -1789,9 +1915,9 @@ static void EmitIsSubclass(CodeGenTarget &Target,
OS << "}\n\n";
}
-/// EmitMatchTokenString - Emit the function to match a token string to the
+/// emitMatchTokenString - Emit the function to match a token string to the
/// appropriate match class value.
-static void EmitMatchTokenString(CodeGenTarget &Target,
+static void emitMatchTokenString(CodeGenTarget &Target,
std::vector<ClassInfo*> &Infos,
raw_ostream &OS) {
// Construct the match list.
@@ -1813,9 +1939,9 @@ static void EmitMatchTokenString(CodeGenTarget &Target,
OS << "}\n\n";
}
-/// EmitMatchRegisterName - Emit the function to match a string to the target
+/// emitMatchRegisterName - Emit the function to match a string to the target
/// specific register enum.
-static void EmitMatchRegisterName(CodeGenTarget &Target, Record *AsmParser,
+static void emitMatchRegisterName(CodeGenTarget &Target, Record *AsmParser,
raw_ostream &OS) {
// Construct the match list.
std::vector<StringMatcher::StringPair> Matches;
@@ -1839,9 +1965,9 @@ static void EmitMatchRegisterName(CodeGenTarget &Target, Record *AsmParser,
OS << "}\n\n";
}
-/// EmitSubtargetFeatureFlagEnumeration - Emit the subtarget feature flag
+/// emitSubtargetFeatureFlagEnumeration - Emit the subtarget feature flag
/// definitions.
-static void EmitSubtargetFeatureFlagEnumeration(AsmMatcherInfo &Info,
+static void emitSubtargetFeatureFlagEnumeration(AsmMatcherInfo &Info,
raw_ostream &OS) {
OS << "// Flags for subtarget features that participate in "
<< "instruction matching.\n";
@@ -1856,9 +1982,48 @@ static void EmitSubtargetFeatureFlagEnumeration(AsmMatcherInfo &Info,
OS << "};\n\n";
}
-/// EmitComputeAvailableFeatures - Emit the function to compute the list of
+/// emitOperandDiagnosticTypes - Emit the operand matching diagnostic types.
+static void emitOperandDiagnosticTypes(AsmMatcherInfo &Info, raw_ostream &OS) {
+ // Get the set of diagnostic types from all of the operand classes.
+ std::set<StringRef> Types;
+ for (std::map<Record*, ClassInfo*>::const_iterator
+ I = Info.AsmOperandClasses.begin(),
+ E = Info.AsmOperandClasses.end(); I != E; ++I) {
+ if (!I->second->DiagnosticType.empty())
+ Types.insert(I->second->DiagnosticType);
+ }
+
+ if (Types.empty()) return;
+
+ // Now emit the enum entries.
+ for (std::set<StringRef>::const_iterator I = Types.begin(), E = Types.end();
+ I != E; ++I)
+ OS << " Match_" << *I << ",\n";
+ OS << " END_OPERAND_DIAGNOSTIC_TYPES\n";
+}
+
+/// emitGetSubtargetFeatureName - Emit the helper function to get the
+/// user-level name for a subtarget feature.
+static void emitGetSubtargetFeatureName(AsmMatcherInfo &Info, raw_ostream &OS) {
+ OS << "// User-level names for subtarget features that participate in\n"
+ << "// instruction matching.\n"
+ << "static const char *getSubtargetFeatureName(unsigned Val) {\n"
+ << " switch(Val) {\n";
+ for (std::map<Record*, SubtargetFeatureInfo*>::const_iterator
+ it = Info.SubtargetFeatures.begin(),
+ ie = Info.SubtargetFeatures.end(); it != ie; ++it) {
+ SubtargetFeatureInfo &SFI = *it->second;
+ // FIXME: Totally just a placeholder name to get the algorithm working.
+ OS << " case " << SFI.getEnumName() << ": return \""
+ << SFI.TheDef->getValueAsString("PredicateName") << "\";\n";
+ }
+ OS << " default: return \"(unknown)\";\n";
+ OS << " }\n}\n\n";
+}
+
+/// emitComputeAvailableFeatures - Emit the function to compute the list of
/// available features given a subtarget.
-static void EmitComputeAvailableFeatures(AsmMatcherInfo &Info,
+static void emitComputeAvailableFeatures(AsmMatcherInfo &Info,
raw_ostream &OS) {
std::string ClassName =
Info.AsmParser->getValueAsString("AsmParserClassName");
@@ -1933,9 +2098,9 @@ static std::string GetAliasRequiredFeatures(Record *R,
return Result;
}
-/// EmitMnemonicAliases - If the target has any MnemonicAlias<> definitions,
+/// emitMnemonicAliases - If the target has any MnemonicAlias<> definitions,
/// emit a function for them and return true, otherwise return false.
-static bool EmitMnemonicAliases(raw_ostream &OS, const AsmMatcherInfo &Info) {
+static bool emitMnemonicAliases(raw_ostream &OS, const AsmMatcherInfo &Info) {
// Ignore aliases when match-prefix is set.
if (!MatchPrefix.empty())
return false;
@@ -2023,7 +2188,7 @@ static const char *getMinimalTypeForRange(uint64_t Range) {
return "uint8_t";
}
-static void EmitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target,
+static void emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target,
const AsmMatcherInfo &Info, StringRef ClassName) {
// Emit the static custom operand parsing table;
OS << "namespace {\n";
@@ -2193,7 +2358,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
// Compute the information on the instructions to match.
AsmMatcherInfo Info(AsmParser, Target, Records);
- Info.BuildInfo();
+ Info.buildInfo();
// Sort the instruction table using the partial order on classes. We use
// stable_sort to ensure that ambiguous instructions are still
@@ -2216,7 +2381,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
MatchableInfo &A = *Info.Matchables[i];
MatchableInfo &B = *Info.Matchables[j];
- if (A.CouldMatchAmbiguouslyWith(B)) {
+ if (A.couldMatchAmbiguouslyWith(B)) {
errs() << "warning: ambiguous matchables:\n";
A.dump();
errs() << "\nis incomparable with:\n";
@@ -2232,12 +2397,10 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
});
// Compute the information on the custom operand parsing.
- Info.BuildOperandMatchInfo();
+ Info.buildOperandMatchInfo();
// Write the output.
- EmitSourceFileHeader("Assembly Matcher Source Fragment", OS);
-
// Information for the class declaration.
OS << "\n#ifdef GET_ASSEMBLER_HEADER\n";
OS << "#undef GET_ASSEMBLER_HEADER\n";
@@ -2270,41 +2433,55 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << "#endif // GET_ASSEMBLER_HEADER_INFO\n\n";
+ // Emit the operand match diagnostic enum names.
+ OS << "\n#ifdef GET_OPERAND_DIAGNOSTIC_TYPES\n";
+ OS << "#undef GET_OPERAND_DIAGNOSTIC_TYPES\n\n";
+ emitOperandDiagnosticTypes(Info, OS);
+ OS << "#endif // GET_OPERAND_DIAGNOSTIC_TYPES\n\n";
+
+
OS << "\n#ifdef GET_REGISTER_MATCHER\n";
OS << "#undef GET_REGISTER_MATCHER\n\n";
// Emit the subtarget feature enumeration.
- EmitSubtargetFeatureFlagEnumeration(Info, OS);
+ emitSubtargetFeatureFlagEnumeration(Info, OS);
// Emit the function to match a register name to number.
- EmitMatchRegisterName(Target, AsmParser, OS);
+ emitMatchRegisterName(Target, AsmParser, OS);
OS << "#endif // GET_REGISTER_MATCHER\n\n";
+ OS << "\n#ifdef GET_SUBTARGET_FEATURE_NAME\n";
+ OS << "#undef GET_SUBTARGET_FEATURE_NAME\n\n";
+
+ // Generate the helper function to get the names for subtarget features.
+ emitGetSubtargetFeatureName(Info, OS);
+
+ OS << "#endif // GET_SUBTARGET_FEATURE_NAME\n\n";
OS << "\n#ifdef GET_MATCHER_IMPLEMENTATION\n";
OS << "#undef GET_MATCHER_IMPLEMENTATION\n\n";
// Generate the function that remaps for mnemonic aliases.
- bool HasMnemonicAliases = EmitMnemonicAliases(OS, Info);
+ bool HasMnemonicAliases = emitMnemonicAliases(OS, Info);
// Generate the unified function to convert operands into an MCInst.
- EmitConvertToMCInst(Target, ClassName, Info.Matchables, OS);
+ emitConvertToMCInst(Target, ClassName, Info.Matchables, OS);
// Emit the enumeration for classes which participate in matching.
- EmitMatchClassEnumeration(Target, Info.Classes, OS);
+ emitMatchClassEnumeration(Target, Info.Classes, OS);
// Emit the routine to match token strings to their match class.
- EmitMatchTokenString(Target, Info.Classes, OS);
+ emitMatchTokenString(Target, Info.Classes, OS);
// Emit the subclass predicate routine.
- EmitIsSubclass(Target, Info.Classes, OS);
+ emitIsSubclass(Target, Info.Classes, OS);
// Emit the routine to validate an operand against a match class.
- EmitValidateOperandClass(Info, OS);
+ emitValidateOperandClass(Info, OS);
// Emit the available features compute function.
- EmitComputeAvailableFeatures(Info, OS);
+ emitComputeAvailableFeatures(Info, OS);
size_t MaxNumOperands = 0;
@@ -2415,8 +2592,8 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
<< Target.getName() << ClassName << "::\n"
<< "MatchInstructionImpl(const SmallVectorImpl<MCParsedAsmOperand*>"
<< " &Operands,\n";
- OS << " MCInst &Inst, unsigned &ErrorInfo,\n";
- OS << " unsigned VariantID) {\n";
+ OS << " MCInst &Inst, unsigned &ErrorInfo, ";
+ OS << "unsigned VariantID) {\n";
// Emit code to get the available features.
OS << " // Get the current feature set.\n";
@@ -2444,6 +2621,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << " bool HadMatchOtherThanFeatures = false;\n";
OS << " bool HadMatchOtherThanPredicate = false;\n";
OS << " unsigned RetCode = Match_InvalidOperand;\n";
+ OS << " unsigned MissingFeatures = ~0U;\n";
OS << " // Set ErrorInfo to the operand that mismatches if it is\n";
OS << " // wrong for all instances of the instruction.\n";
OS << " ErrorInfo = ~0U;\n";
@@ -2471,15 +2649,25 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << " for (unsigned i = 0; i != " << MaxNumOperands << "; ++i) {\n";
OS << " if (i + 1 >= Operands.size()) {\n";
OS << " OperandsValid = (it->Classes[i] == " <<"InvalidMatchClass);\n";
+ OS << " if (!OperandsValid) ErrorInfo = i + 1;\n";
OS << " break;\n";
OS << " }\n";
- OS << " if (validateOperandClass(Operands[i+1], "
- "(MatchClassKind)it->Classes[i]))\n";
+ OS << " unsigned Diag = validateOperandClass(Operands[i+1],\n";
+ OS.indent(43);
+ OS << "(MatchClassKind)it->Classes[i]);\n";
+ OS << " if (Diag == Match_Success)\n";
OS << " continue;\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 (it == MnemonicRange.first || ErrorInfo <= i+1)\n";
+ OS << " // If we already had a match that only failed due to a\n";
+ OS << " // target predicate, that diagnostic is preferred.\n";
+ OS << " if (!HadMatchOtherThanPredicate &&\n";
+ OS << " (it == MnemonicRange.first || ErrorInfo <= i+1)) {\n";
OS << " ErrorInfo = i+1;\n";
+ OS << " // InvalidOperand is the default. Prefer specificity.\n";
+ OS << " if (Diag != Match_InvalidOperand)\n";
+ OS << " RetCode = Diag;\n";
+ OS << " }\n";
OS << " // Otherwise, just reject this instance of the mnemonic.\n";
OS << " OperandsValid = false;\n";
OS << " break;\n";
@@ -2491,6 +2679,11 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << " if ((AvailableFeatures & it->RequiredFeatures) "
<< "!= it->RequiredFeatures) {\n";
OS << " HadMatchOtherThanFeatures = true;\n";
+ OS << " unsigned NewMissingFeatures = it->RequiredFeatures & "
+ "~AvailableFeatures;\n";
+ OS << " if (CountPopulation_32(NewMissingFeatures) <= "
+ "CountPopulation_32(MissingFeatures))\n";
+ OS << " MissingFeatures = NewMissingFeatures;\n";
OS << " continue;\n";
OS << " }\n";
OS << "\n";
@@ -2524,12 +2717,23 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << " // Okay, we had no match. Try to return a useful error code.\n";
OS << " if (HadMatchOtherThanPredicate || !HadMatchOtherThanFeatures)";
- OS << " return RetCode;\n";
+ OS << " return RetCode;\n";
+ OS << " // Missing feature matches return which features were missing\n";
+ OS << " ErrorInfo = MissingFeatures;\n";
OS << " return Match_MissingFeature;\n";
OS << "}\n\n";
if (Info.OperandMatchInfo.size())
- EmitCustomOperandParsing(OS, Target, Info, ClassName);
+ emitCustomOperandParsing(OS, Target, Info, ClassName);
OS << "#endif // GET_MATCHER_IMPLEMENTATION\n\n";
}
+
+namespace llvm {
+
+void EmitAsmMatcher(RecordKeeper &RK, raw_ostream &OS) {
+ emitSourceFileHeader("Assembly Matcher Source Fragment", OS);
+ AsmMatcherEmitter(RK).run(OS);
+}
+
+} // End llvm namespace
diff --git a/utils/TableGen/AsmMatcherEmitter.h b/utils/TableGen/AsmMatcherEmitter.h
deleted file mode 100644
index e04ac103a401..000000000000
--- a/utils/TableGen/AsmMatcherEmitter.h
+++ /dev/null
@@ -1,31 +0,0 @@
-//===- AsmMatcherEmitter.h - Generate an assembly matcher -------*- 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 emits a target specifier matcher for converting parsed
-// assembly operands in the MCInst structures.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef ASMMATCHER_EMITTER_H
-#define ASMMATCHER_EMITTER_H
-
-#include "llvm/TableGen/TableGenBackend.h"
-#include <cassert>
-
-namespace llvm {
- class AsmMatcherEmitter : public TableGenBackend {
- RecordKeeper &Records;
- public:
- AsmMatcherEmitter(RecordKeeper &R) : Records(R) {}
-
- // run - Output the matcher, returning true on failure.
- void run(raw_ostream &o);
- };
-}
-#endif
diff --git a/utils/TableGen/AsmWriterEmitter.cpp b/utils/TableGen/AsmWriterEmitter.cpp
index d079b45e8d59..57979b3e6dbd 100644
--- a/utils/TableGen/AsmWriterEmitter.cpp
+++ b/utils/TableGen/AsmWriterEmitter.cpp
@@ -12,19 +12,50 @@
//
//===----------------------------------------------------------------------===//
-#include "AsmWriterEmitter.h"
#include "AsmWriterInst.h"
#include "CodeGenTarget.h"
-#include "StringToOffsetTable.h"
#include "SequenceToOffsetTable.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
+#include "llvm/TableGen/TableGenBackend.h"
#include <algorithm>
+#include <cassert>
+#include <map>
+#include <vector>
using namespace llvm;
+namespace {
+class AsmWriterEmitter {
+ RecordKeeper &Records;
+ std::map<const CodeGenInstruction*, AsmWriterInst*> CGIAWIMap;
+ std::vector<const CodeGenInstruction*> NumberedInstructions;
+public:
+ AsmWriterEmitter(RecordKeeper &R) : Records(R) {}
+
+ void run(raw_ostream &o);
+
+private:
+ void EmitPrintInstruction(raw_ostream &o);
+ void EmitGetRegisterName(raw_ostream &o);
+ void EmitPrintAliasInstruction(raw_ostream &O);
+
+ AsmWriterInst *getAsmWriterInstByID(unsigned ID) const {
+ assert(ID < NumberedInstructions.size());
+ std::map<const CodeGenInstruction*, AsmWriterInst*>::const_iterator I =
+ CGIAWIMap.find(NumberedInstructions[ID]);
+ assert(I != CGIAWIMap.end() && "Didn't find inst!");
+ return I->second;
+ }
+ void FindUniqueOperandCommands(std::vector<std::string> &UOC,
+ std::vector<unsigned> &InstIdxs,
+ std::vector<unsigned> &InstOpsUsed) const;
+};
+} // end anonymous namespace
+
static void PrintCases(std::vector<std::pair<std::string,
AsmWriterOperand> > &OpsToPrint, raw_ostream &O) {
O << " case " << OpsToPrint.back().first << ": ";
@@ -928,10 +959,17 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) {
}
void AsmWriterEmitter::run(raw_ostream &O) {
- EmitSourceFileHeader("Assembly Writer Source Fragment", O);
-
EmitPrintInstruction(O);
EmitGetRegisterName(O);
EmitPrintAliasInstruction(O);
}
+
+namespace llvm {
+
+void EmitAsmWriter(RecordKeeper &RK, raw_ostream &OS) {
+ emitSourceFileHeader("Assembly Writer Source Fragment", OS);
+ AsmWriterEmitter(RK).run(OS);
+}
+
+} // End llvm namespace
diff --git a/utils/TableGen/AsmWriterEmitter.h b/utils/TableGen/AsmWriterEmitter.h
deleted file mode 100644
index 9719b202faab..000000000000
--- a/utils/TableGen/AsmWriterEmitter.h
+++ /dev/null
@@ -1,54 +0,0 @@
-//===- AsmWriterEmitter.h - Generate an assembly writer ---------*- 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 an assembly printer for the
-// code generator.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef ASMWRITER_EMITTER_H
-#define ASMWRITER_EMITTER_H
-
-#include "llvm/TableGen/TableGenBackend.h"
-#include <map>
-#include <vector>
-#include <cassert>
-
-namespace llvm {
- class AsmWriterInst;
- class CodeGenInstruction;
-
- class AsmWriterEmitter : public TableGenBackend {
- RecordKeeper &Records;
- std::map<const CodeGenInstruction*, AsmWriterInst*> CGIAWIMap;
- std::vector<const CodeGenInstruction*> NumberedInstructions;
- public:
- AsmWriterEmitter(RecordKeeper &R) : Records(R) {}
-
- // run - Output the asmwriter, returning true on failure.
- void run(raw_ostream &o);
-
-private:
- void EmitPrintInstruction(raw_ostream &o);
- void EmitGetRegisterName(raw_ostream &o);
- void EmitPrintAliasInstruction(raw_ostream &O);
-
- AsmWriterInst *getAsmWriterInstByID(unsigned ID) const {
- assert(ID < NumberedInstructions.size());
- std::map<const CodeGenInstruction*, AsmWriterInst*>::const_iterator I =
- CGIAWIMap.find(NumberedInstructions[ID]);
- assert(I != CGIAWIMap.end() && "Didn't find inst!");
- return I->second;
- }
- void FindUniqueOperandCommands(std::vector<std::string> &UOC,
- std::vector<unsigned> &InstIdxs,
- std::vector<unsigned> &InstOpsUsed) const;
- };
-}
-#endif
diff --git a/utils/TableGen/CMakeLists.txt b/utils/TableGen/CMakeLists.txt
index 2b70f1c52bd0..0e14cbae38ad 100644
--- a/utils/TableGen/CMakeLists.txt
+++ b/utils/TableGen/CMakeLists.txt
@@ -11,6 +11,7 @@ add_tablegen(llvm-tblgen LLVM
CodeGenDAGPatterns.cpp
CodeGenInstruction.cpp
CodeGenRegisters.cpp
+ CodeGenSchedule.cpp
CodeGenTarget.cpp
DAGISelEmitter.cpp
DAGISelMatcherEmitter.cpp
@@ -27,7 +28,6 @@ add_tablegen(llvm-tblgen LLVM
PseudoLoweringEmitter.cpp
RegisterInfoEmitter.cpp
SetTheory.cpp
- StringMatcher.cpp
SubtargetEmitter.cpp
TGValueTypes.cpp
TableGen.cpp
diff --git a/utils/TableGen/CallingConvEmitter.cpp b/utils/TableGen/CallingConvEmitter.cpp
index afbb3a870894..e9c4bd30f914 100644
--- a/utils/TableGen/CallingConvEmitter.cpp
+++ b/utils/TableGen/CallingConvEmitter.cpp
@@ -12,13 +12,28 @@
//
//===----------------------------------------------------------------------===//
-#include "CallingConvEmitter.h"
#include "CodeGenTarget.h"
#include "llvm/TableGen/Record.h"
+#include "llvm/TableGen/TableGenBackend.h"
+#include <cassert>
using namespace llvm;
+namespace {
+class CallingConvEmitter {
+ RecordKeeper &Records;
+public:
+ explicit CallingConvEmitter(RecordKeeper &R) : Records(R) {}
+
+ void run(raw_ostream &o);
+
+private:
+ void EmitCallingConv(Record *CC, raw_ostream &O);
+ void EmitAction(Record *Action, unsigned Indent, raw_ostream &O);
+ unsigned Counter;
+};
+} // End anonymous namespace
+
void CallingConvEmitter::run(raw_ostream &O) {
- EmitSourceFileHeader("Calling Convention Implementation Fragment", O);
std::vector<Record*> CCs = Records.getAllDerivedDefinitions("CallingConv");
@@ -210,3 +225,12 @@ void CallingConvEmitter::EmitAction(Record *Action,
}
}
}
+
+namespace llvm {
+
+void EmitCallingConv(RecordKeeper &RK, raw_ostream &OS) {
+ emitSourceFileHeader("Calling Convention Implementation Fragment", OS);
+ CallingConvEmitter(RK).run(OS);
+}
+
+} // End llvm namespace
diff --git a/utils/TableGen/CallingConvEmitter.h b/utils/TableGen/CallingConvEmitter.h
deleted file mode 100644
index 7bddd6c93eff..000000000000
--- a/utils/TableGen/CallingConvEmitter.h
+++ /dev/null
@@ -1,36 +0,0 @@
-//===- CallingConvEmitter.h - Generate calling conventions ------*- 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 descriptions of the calling
-// conventions supported by this target.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef CALLINGCONV_EMITTER_H
-#define CALLINGCONV_EMITTER_H
-
-#include "llvm/TableGen/TableGenBackend.h"
-#include <cassert>
-
-namespace llvm {
- class CallingConvEmitter : public TableGenBackend {
- RecordKeeper &Records;
- public:
- explicit CallingConvEmitter(RecordKeeper &R) : Records(R) {}
-
- // run - Output the asmwriter, returning true on failure.
- void run(raw_ostream &o);
-
- private:
- void EmitCallingConv(Record *CC, raw_ostream &O);
- void EmitAction(Record *Action, unsigned Indent, raw_ostream &O);
- unsigned Counter;
- };
-}
-#endif
diff --git a/utils/TableGen/CodeEmitterGen.cpp b/utils/TableGen/CodeEmitterGen.cpp
index 3943e8a40f87..31a39b1f0426 100644
--- a/utils/TableGen/CodeEmitterGen.cpp
+++ b/utils/TableGen/CodeEmitterGen.cpp
@@ -13,13 +13,15 @@
//
//===----------------------------------------------------------------------===//
-#include "CodeEmitterGen.h"
#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/TableGenBackend.h"
#include <map>
+#include <string>
+#include <vector>
using namespace llvm;
// FIXME: Somewhat hackish to use a command line option for this. There should
@@ -30,6 +32,27 @@ MCEmitter("mc-emitter",
cl::desc("Generate CodeEmitter for use with the MC library."),
cl::init(false));
+namespace {
+
+class CodeEmitterGen {
+ RecordKeeper &Records;
+public:
+ CodeEmitterGen(RecordKeeper &R) : Records(R) {}
+
+ void run(raw_ostream &o);
+private:
+ void emitMachineOpEmitter(raw_ostream &o, const std::string &Namespace);
+ void emitGetValueBit(raw_ostream &o, const std::string &Namespace);
+ void reverseBits(std::vector<Record*> &Insts);
+ int getVariableBit(const std::string &VarName, BitsInit *BI, int bit);
+ std::string getInstructionCase(Record *R, CodeGenTarget &Target);
+ void AddCodeToMergeInOperand(Record *R, BitsInit *BI,
+ const std::string &VarName,
+ unsigned &NumberedOp,
+ std::string &Case, CodeGenTarget &Target);
+
+};
+
void CodeEmitterGen::reverseBits(std::vector<Record*> &Insts) {
for (std::vector<Record*>::iterator I = Insts.begin(), E = Insts.end();
I != E; ++I) {
@@ -214,7 +237,6 @@ void CodeEmitterGen::run(raw_ostream &o) {
// For little-endian instruction bit encodings, reverse the bit order
if (Target.isLittleEndianEncoding()) reverseBits(Insts);
- EmitSourceFileHeader("Machine Code Emitter", o);
const std::vector<const CodeGenInstruction*> &NumberedInstructions =
Target.getInstructionsByEnumValue();
@@ -304,3 +326,14 @@ void CodeEmitterGen::run(raw_ostream &o) {
<< " return Value;\n"
<< "}\n\n";
}
+
+} // End anonymous namespace
+
+namespace llvm {
+
+void EmitCodeEmitter(RecordKeeper &RK, raw_ostream &OS) {
+ emitSourceFileHeader("Machine Code Emitter", OS);
+ CodeEmitterGen(RK).run(OS);
+}
+
+} // End llvm namespace
diff --git a/utils/TableGen/CodeEmitterGen.h b/utils/TableGen/CodeEmitterGen.h
deleted file mode 100644
index 7f6ee2a1b40f..000000000000
--- a/utils/TableGen/CodeEmitterGen.h
+++ /dev/null
@@ -1,49 +0,0 @@
-//===- CodeEmitterGen.h - Code Emitter Generator ----------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// FIXME: document
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef CODEMITTERGEN_H
-#define CODEMITTERGEN_H
-
-#include "llvm/TableGen/TableGenBackend.h"
-#include <vector>
-#include <string>
-
-namespace llvm {
-
-class RecordVal;
-class BitsInit;
-class CodeGenTarget;
-
-class CodeEmitterGen : public TableGenBackend {
- RecordKeeper &Records;
-public:
- CodeEmitterGen(RecordKeeper &R) : Records(R) {}
-
- // run - Output the code emitter
- void run(raw_ostream &o);
-private:
- void emitMachineOpEmitter(raw_ostream &o, const std::string &Namespace);
- void emitGetValueBit(raw_ostream &o, const std::string &Namespace);
- void reverseBits(std::vector<Record*> &Insts);
- int getVariableBit(const std::string &VarName, BitsInit *BI, int bit);
- std::string getInstructionCase(Record *R, CodeGenTarget &Target);
- void
- AddCodeToMergeInOperand(Record *R, BitsInit *BI, const std::string &VarName,
- unsigned &NumberedOp,
- std::string &Case, CodeGenTarget &Target);
-
-};
-
-} // End llvm namespace
-
-#endif
diff --git a/utils/TableGen/CodeGenDAGPatterns.cpp b/utils/TableGen/CodeGenDAGPatterns.cpp
index d4b02fbd2f33..34f8a34e7af7 100644
--- a/utils/TableGen/CodeGenDAGPatterns.cpp
+++ b/utils/TableGen/CodeGenDAGPatterns.cpp
@@ -2520,6 +2520,37 @@ static void InferFromPattern(const CodeGenInstruction &Inst,
IsVariadic = true; // Can warn if we want.
}
+/// hasNullFragReference - Return true if the DAG has any reference to the
+/// null_frag operator.
+static bool hasNullFragReference(DagInit *DI) {
+ DefInit *OpDef = dynamic_cast<DefInit*>(DI->getOperator());
+ if (!OpDef) return false;
+ Record *Operator = OpDef->getDef();
+
+ // If this is the null fragment, return true.
+ if (Operator->getName() == "null_frag") return true;
+ // If any of the arguments reference the null fragment, return true.
+ for (unsigned i = 0, e = DI->getNumArgs(); i != e; ++i) {
+ DagInit *Arg = dynamic_cast<DagInit*>(DI->getArg(i));
+ if (Arg && hasNullFragReference(Arg))
+ return true;
+ }
+
+ return false;
+}
+
+/// hasNullFragReference - Return true if any DAG in the list references
+/// the null_frag operator.
+static bool hasNullFragReference(ListInit *LI) {
+ for (unsigned i = 0, e = LI->getSize(); i != e; ++i) {
+ DagInit *DI = dynamic_cast<DagInit*>(LI->getElement(i));
+ assert(DI && "non-dag in an instruction Pattern list?!");
+ if (hasNullFragReference(DI))
+ 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.
@@ -2534,8 +2565,11 @@ void CodeGenDAGPatterns::ParseInstructions() {
// If there is no pattern, only collect minimal information about the
// instruction for its operand list. We have to assume that there is one
- // result, as we have no detailed info.
- if (!LI || LI->getSize() == 0) {
+ // result, as we have no detailed info. A pattern which references the
+ // null_frag operator is as-if no pattern were specified. Normally this
+ // is from a multiclass expansion w/ a SDPatternOperator passed in as
+ // null_frag.
+ if (!LI || LI->getSize() == 0 || hasNullFragReference(LI)) {
std::vector<Record*> Results;
std::vector<Record*> Operands;
@@ -2874,6 +2908,11 @@ void CodeGenDAGPatterns::ParsePatterns() {
for (unsigned i = 0, e = Patterns.size(); i != e; ++i) {
Record *CurPattern = Patterns[i];
DagInit *Tree = CurPattern->getValueAsDag("PatternToMatch");
+
+ // If the pattern references the null_frag, there's nothing to do.
+ if (hasNullFragReference(Tree))
+ continue;
+
TreePattern *Pattern = new TreePattern(CurPattern, Tree, true, *this);
// Inline pattern fragments into it.
diff --git a/utils/TableGen/CodeGenInstruction.cpp b/utils/TableGen/CodeGenInstruction.cpp
index fb9ad9371bea..33381e956905 100644
--- a/utils/TableGen/CodeGenInstruction.cpp
+++ b/utils/TableGen/CodeGenInstruction.cpp
@@ -556,9 +556,31 @@ CodeGenInstAlias::CodeGenInstAlias(Record *R, CodeGenTarget &T) : TheDef(R) {
ResultOperand ResOp(static_cast<int64_t>(0));
if (tryAliasOpMatch(Result, AliasOpNo, InstOpRec, (NumSubOps > 1),
R->getLoc(), T, ResOp)) {
- ResultOperands.push_back(ResOp);
- ResultInstOperandIndex.push_back(std::make_pair(i, -1));
- ++AliasOpNo;
+ // If this is a simple operand, or a complex operand with a custom match
+ // class, then we can match is verbatim.
+ if (NumSubOps == 1 ||
+ (InstOpRec->getValue("ParserMatchClass") &&
+ InstOpRec->getValueAsDef("ParserMatchClass")
+ ->getValueAsString("Name") != "Imm")) {
+ ResultOperands.push_back(ResOp);
+ ResultInstOperandIndex.push_back(std::make_pair(i, -1));
+ ++AliasOpNo;
+
+ // Otherwise, we need to match each of the suboperands individually.
+ } else {
+ DagInit *MIOI = ResultInst->Operands[i].MIOperandInfo;
+ for (unsigned SubOp = 0; SubOp != NumSubOps; ++SubOp) {
+ Record *SubRec = dynamic_cast<DefInit*>(MIOI->getArg(SubOp))->getDef();
+
+ // Take care to instantiate each of the suboperands with the correct
+ // nomenclature: $foo.bar
+ ResultOperands.push_back(
+ ResultOperand(Result->getArgName(AliasOpNo) + "." +
+ MIOI->getArgName(SubOp), SubRec));
+ ResultInstOperandIndex.push_back(std::make_pair(i, SubOp));
+ }
+ ++AliasOpNo;
+ }
continue;
}
diff --git a/utils/TableGen/CodeGenInstruction.h b/utils/TableGen/CodeGenInstruction.h
index 468277aa96c2..3ba9f24daaed 100644
--- a/utils/TableGen/CodeGenInstruction.h
+++ b/utils/TableGen/CodeGenInstruction.h
@@ -280,7 +280,7 @@ namespace llvm {
struct ResultOperand {
private:
- StringRef Name;
+ std::string Name;
Record *R;
int64_t Imm;
@@ -291,7 +291,7 @@ namespace llvm {
K_Reg
} Kind;
- ResultOperand(StringRef N, Record *r) : Name(N), R(r), Kind(K_Record) {}
+ ResultOperand(std::string N, Record *r) : Name(N), R(r), Kind(K_Record) {}
ResultOperand(int64_t I) : Imm(I), Kind(K_Imm) {}
ResultOperand(Record *r) : R(r), Kind(K_Reg) {}
diff --git a/utils/TableGen/CodeGenIntrinsics.h b/utils/TableGen/CodeGenIntrinsics.h
index 3f6ba61172c9..6efe952ea2bb 100644
--- a/utils/TableGen/CodeGenIntrinsics.h
+++ b/utils/TableGen/CodeGenIntrinsics.h
@@ -72,7 +72,10 @@ namespace llvm {
/// canThrow - True if the intrinsic can throw.
bool canThrow;
-
+
+ /// isNoReturn - True if the intrinsic is no-return.
+ bool isNoReturn;
+
enum ArgAttribute {
NoCapture
};
diff --git a/utils/TableGen/CodeGenRegisters.cpp b/utils/TableGen/CodeGenRegisters.cpp
index 45c5bb8b3a52..ff3ad7283939 100644
--- a/utils/TableGen/CodeGenRegisters.cpp
+++ b/utils/TableGen/CodeGenRegisters.cpp
@@ -83,9 +83,43 @@ CodeGenRegister::CodeGenRegister(Record *R, unsigned Enum)
EnumValue(Enum),
CostPerUse(R->getValueAsInt("CostPerUse")),
CoveredBySubRegs(R->getValueAsBit("CoveredBySubRegs")),
- SubRegsComplete(false)
+ NumNativeRegUnits(0),
+ SubRegsComplete(false),
+ SuperRegsComplete(false),
+ TopoSig(~0u)
{}
+void CodeGenRegister::buildObjectGraph(CodeGenRegBank &RegBank) {
+ std::vector<Record*> SRIs = TheDef->getValueAsListOfDefs("SubRegIndices");
+ std::vector<Record*> SRs = TheDef->getValueAsListOfDefs("SubRegs");
+
+ if (SRIs.size() != SRs.size())
+ throw TGError(TheDef->getLoc(),
+ "SubRegs and SubRegIndices must have the same size");
+
+ for (unsigned i = 0, e = SRIs.size(); i != e; ++i) {
+ ExplicitSubRegIndices.push_back(RegBank.getSubRegIdx(SRIs[i]));
+ ExplicitSubRegs.push_back(RegBank.getReg(SRs[i]));
+ }
+
+ // Also compute leading super-registers. Each register has a list of
+ // covered-by-subregs super-registers where it appears as the first explicit
+ // sub-register.
+ //
+ // This is used by computeSecondarySubRegs() to find candidates.
+ if (CoveredBySubRegs && !ExplicitSubRegs.empty())
+ ExplicitSubRegs.front()->LeadingSuperRegs.push_back(this);
+
+ // Add ad hoc alias links. This is a symmetric relationship between two
+ // registers, so build a symmetric graph by adding links in both ends.
+ std::vector<Record*> Aliases = TheDef->getValueAsListOfDefs("Aliases");
+ for (unsigned i = 0, e = Aliases.size(); i != e; ++i) {
+ CodeGenRegister *Reg = RegBank.getReg(Aliases[i]);
+ ExplicitAliases.push_back(Reg);
+ Reg->ExplicitAliases.push_back(this);
+ }
+}
+
const std::string &CodeGenRegister::getName() const {
return TheDef->getName();
}
@@ -109,7 +143,7 @@ public:
bool isValid() const { return UnitI != UnitE; }
- unsigned operator* () const { assert(isValid()); return *UnitI; };
+ unsigned operator* () const { assert(isValid()); return *UnitI; }
const CodeGenRegister *getReg() const { assert(isValid()); return *RegI; }
@@ -153,15 +187,7 @@ bool CodeGenRegister::inheritRegUnits(CodeGenRegBank &RegBank) {
unsigned OldNumUnits = RegUnits.size();
for (SubRegMap::const_iterator I = SubRegs.begin(), E = SubRegs.end();
I != E; ++I) {
- // Strangely a register may have itself as a subreg (self-cycle) e.g. XMM.
- // Only create a unit if no other subregs have units.
CodeGenRegister *SR = I->second;
- if (SR == this) {
- // RegUnits are only empty during getSubRegs, prior to computing weight.
- if (RegUnits.empty())
- RegUnits.push_back(RegBank.newRegUnit(0));
- continue;
- }
// Merge the subregister's units into this register's RegUnits.
mergeRegUnits(RegUnits, SR->RegUnits);
}
@@ -169,27 +195,22 @@ bool CodeGenRegister::inheritRegUnits(CodeGenRegBank &RegBank) {
}
const CodeGenRegister::SubRegMap &
-CodeGenRegister::getSubRegs(CodeGenRegBank &RegBank) {
+CodeGenRegister::computeSubRegs(CodeGenRegBank &RegBank) {
// Only compute this map once.
if (SubRegsComplete)
return SubRegs;
SubRegsComplete = true;
- std::vector<Record*> SubList = TheDef->getValueAsListOfDefs("SubRegs");
- std::vector<Record*> IdxList = TheDef->getValueAsListOfDefs("SubRegIndices");
- if (SubList.size() != IdxList.size())
- throw TGError(TheDef->getLoc(), "Register " + getName() +
- " SubRegIndices doesn't match SubRegs");
-
- // First insert the direct subregs and make sure they are fully indexed.
- SmallVector<CodeGenSubRegIndex*, 8> Indices;
- for (unsigned i = 0, e = SubList.size(); i != e; ++i) {
- CodeGenRegister *SR = RegBank.getReg(SubList[i]);
- CodeGenSubRegIndex *Idx = RegBank.getSubRegIdx(IdxList[i]);
- Indices.push_back(Idx);
+ // First insert the explicit subregs and make sure they are fully indexed.
+ for (unsigned i = 0, e = ExplicitSubRegs.size(); i != e; ++i) {
+ CodeGenRegister *SR = ExplicitSubRegs[i];
+ CodeGenSubRegIndex *Idx = ExplicitSubRegIndices[i];
if (!SubRegs.insert(std::make_pair(Idx, SR)).second)
throw TGError(TheDef->getLoc(), "SubRegIndex " + Idx->getName() +
" appears twice in Register " + getName());
+ // Map explicit sub-registers first, so the names take precedence.
+ // The inherited sub-registers are mapped below.
+ SubReg2Idx.insert(std::make_pair(SR, Idx));
}
// Keep track of inherited subregs and how they can be reached.
@@ -197,23 +218,14 @@ CodeGenRegister::getSubRegs(CodeGenRegBank &RegBank) {
// Clone inherited subregs and place duplicate entries in Orphans.
// Here the order is important - earlier subregs take precedence.
- for (unsigned i = 0, e = SubList.size(); i != e; ++i) {
- CodeGenRegister *SR = RegBank.getReg(SubList[i]);
- const SubRegMap &Map = SR->getSubRegs(RegBank);
-
- // Add this as a super-register of SR now all sub-registers are in the list.
- // This creates a topological ordering, the exact order depends on the
- // order getSubRegs is called on all registers.
- SR->SuperRegs.push_back(this);
+ for (unsigned i = 0, e = ExplicitSubRegs.size(); i != e; ++i) {
+ CodeGenRegister *SR = ExplicitSubRegs[i];
+ const SubRegMap &Map = SR->computeSubRegs(RegBank);
for (SubRegMap::const_iterator SI = Map.begin(), SE = Map.end(); SI != SE;
++SI) {
if (!SubRegs.insert(*SI).second)
Orphans.insert(SI->second);
-
- // Noop sub-register indexes are possible, so avoid duplicates.
- if (SI->second != SR)
- SI->second->SuperRegs.push_back(this);
}
}
@@ -221,11 +233,12 @@ CodeGenRegister::getSubRegs(CodeGenRegBank &RegBank) {
// If dsub_2 has ComposedOf = [qsub_1, dsub_0], and this register has a
// qsub_1 subreg, add a dsub_2 subreg. Keep growing Indices and process
// expanded subreg indices recursively.
+ SmallVector<CodeGenSubRegIndex*, 8> Indices = ExplicitSubRegIndices;
for (unsigned i = 0; i != Indices.size(); ++i) {
CodeGenSubRegIndex *Idx = Indices[i];
const CodeGenSubRegIndex::CompMap &Comps = Idx->getComposites();
CodeGenRegister *SR = SubRegs[Idx];
- const SubRegMap &Map = SR->getSubRegs(RegBank);
+ const SubRegMap &Map = SR->computeSubRegs(RegBank);
// Look at the possible compositions of Idx.
// They may not all be supported by SR.
@@ -244,44 +257,6 @@ CodeGenRegister::getSubRegs(CodeGenRegBank &RegBank) {
}
}
- // Process the composites.
- ListInit *Comps = TheDef->getValueAsListInit("CompositeIndices");
- for (unsigned i = 0, e = Comps->size(); i != e; ++i) {
- DagInit *Pat = dynamic_cast<DagInit*>(Comps->getElement(i));
- if (!Pat)
- throw TGError(TheDef->getLoc(), "Invalid dag '" +
- Comps->getElement(i)->getAsString() +
- "' in CompositeIndices");
- DefInit *BaseIdxInit = dynamic_cast<DefInit*>(Pat->getOperator());
- if (!BaseIdxInit || !BaseIdxInit->getDef()->isSubClassOf("SubRegIndex"))
- throw TGError(TheDef->getLoc(), "Invalid SubClassIndex in " +
- Pat->getAsString());
- CodeGenSubRegIndex *BaseIdx = RegBank.getSubRegIdx(BaseIdxInit->getDef());
-
- // Resolve list of subreg indices into R2.
- CodeGenRegister *R2 = this;
- for (DagInit::const_arg_iterator di = Pat->arg_begin(),
- de = Pat->arg_end(); di != de; ++di) {
- DefInit *IdxInit = dynamic_cast<DefInit*>(*di);
- if (!IdxInit || !IdxInit->getDef()->isSubClassOf("SubRegIndex"))
- throw TGError(TheDef->getLoc(), "Invalid SubClassIndex in " +
- Pat->getAsString());
- CodeGenSubRegIndex *Idx = RegBank.getSubRegIdx(IdxInit->getDef());
- const SubRegMap &R2Subs = R2->getSubRegs(RegBank);
- SubRegMap::const_iterator ni = R2Subs.find(Idx);
- if (ni == R2Subs.end())
- throw TGError(TheDef->getLoc(), "Composite " + Pat->getAsString() +
- " refers to bad index in " + R2->getName());
- R2 = ni->second;
- }
-
- // Insert composite index. Allow overriding inherited indices etc.
- SubRegs[BaseIdx] = R2;
-
- // R2 is no longer an orphan.
- Orphans.erase(R2);
- }
-
// Now Orphans contains the inherited subregisters without a direct index.
// Create inferred indexes for all missing entries.
// Work backwards in the Indices vector in order to compose subregs bottom-up.
@@ -296,46 +271,283 @@ CodeGenRegister::getSubRegs(CodeGenRegBank &RegBank) {
// dsub_2 -> ssub_0
//
// We pick the latter composition because another register may have [dsub_0,
- // dsub_1, dsub_2] subregs without neccessarily having a qsub_1 subreg. The
+ // dsub_1, dsub_2] subregs without necessarily having a qsub_1 subreg. The
// dsub_2 -> ssub_0 composition can be shared.
while (!Indices.empty() && !Orphans.empty()) {
CodeGenSubRegIndex *Idx = Indices.pop_back_val();
CodeGenRegister *SR = SubRegs[Idx];
- const SubRegMap &Map = SR->getSubRegs(RegBank);
+ const SubRegMap &Map = SR->computeSubRegs(RegBank);
for (SubRegMap::const_iterator SI = Map.begin(), SE = Map.end(); SI != SE;
++SI)
if (Orphans.erase(SI->second))
SubRegs[RegBank.getCompositeSubRegIndex(Idx, SI->first)] = SI->second;
}
- // Initialize RegUnitList. A register with no subregisters creates its own
- // unit. Otherwise, it inherits all its subregister's units. Because
- // getSubRegs is called recursively, this processes the register hierarchy in
- // postorder.
+ // Compute the inverse SubReg -> Idx map.
+ for (SubRegMap::const_iterator SI = SubRegs.begin(), SE = SubRegs.end();
+ SI != SE; ++SI) {
+ if (SI->second == this) {
+ SMLoc Loc;
+ if (TheDef)
+ Loc = TheDef->getLoc();
+ throw TGError(Loc, "Register " + getName() +
+ " has itself as a sub-register");
+ }
+ // Ensure that every sub-register has a unique name.
+ DenseMap<const CodeGenRegister*, CodeGenSubRegIndex*>::iterator Ins =
+ SubReg2Idx.insert(std::make_pair(SI->second, SI->first)).first;
+ if (Ins->second == SI->first)
+ continue;
+ // Trouble: Two different names for SI->second.
+ SMLoc Loc;
+ if (TheDef)
+ Loc = TheDef->getLoc();
+ throw TGError(Loc, "Sub-register can't have two names: " +
+ SI->second->getName() + " available as " +
+ SI->first->getName() + " and " + Ins->second->getName());
+ }
+
+ // Derive possible names for sub-register concatenations from any explicit
+ // sub-registers. By doing this before computeSecondarySubRegs(), we ensure
+ // that getConcatSubRegIndex() won't invent any concatenated indices that the
+ // user already specified.
+ for (unsigned i = 0, e = ExplicitSubRegs.size(); i != e; ++i) {
+ CodeGenRegister *SR = ExplicitSubRegs[i];
+ if (!SR->CoveredBySubRegs || SR->ExplicitSubRegs.size() <= 1)
+ continue;
+
+ // SR is composed of multiple sub-regs. Find their names in this register.
+ SmallVector<CodeGenSubRegIndex*, 8> Parts;
+ for (unsigned j = 0, e = SR->ExplicitSubRegs.size(); j != e; ++j)
+ Parts.push_back(getSubRegIndex(SR->ExplicitSubRegs[j]));
+
+ // Offer this as an existing spelling for the concatenation of Parts.
+ RegBank.addConcatSubRegIndex(Parts, ExplicitSubRegIndices[i]);
+ }
+
+ // Initialize RegUnitList. Because getSubRegs is called recursively, this
+ // processes the register hierarchy in postorder.
//
- // TODO: We currently assume all register units correspond to a named "leaf"
- // register. We should also unify register units for ad-hoc register
- // aliases. This can be done by iteratively merging units for aliasing
- // registers using a worklist.
- assert(RegUnits.empty() && "Should only initialize RegUnits once");
- if (SubRegs.empty())
- RegUnits.push_back(RegBank.newRegUnit(0));
- else
- inheritRegUnits(RegBank);
+ // Inherit all sub-register units. It is good enough to look at the explicit
+ // sub-registers, the other registers won't contribute any more units.
+ for (unsigned i = 0, e = ExplicitSubRegs.size(); i != e; ++i) {
+ CodeGenRegister *SR = ExplicitSubRegs[i];
+ // Explicit sub-registers are usually disjoint, so this is a good way of
+ // computing the union. We may pick up a few duplicates that will be
+ // eliminated below.
+ unsigned N = RegUnits.size();
+ RegUnits.append(SR->RegUnits.begin(), SR->RegUnits.end());
+ std::inplace_merge(RegUnits.begin(), RegUnits.begin() + N, RegUnits.end());
+ }
+ RegUnits.erase(std::unique(RegUnits.begin(), RegUnits.end()), RegUnits.end());
+
+ // Absent any ad hoc aliasing, we create one register unit per leaf register.
+ // These units correspond to the maximal cliques in the register overlap
+ // graph which is optimal.
+ //
+ // When there is ad hoc aliasing, we simply create one unit per edge in the
+ // undirected ad hoc aliasing graph. Technically, we could do better by
+ // identifying maximal cliques in the ad hoc graph, but cliques larger than 2
+ // are extremely rare anyway (I've never seen one), so we don't bother with
+ // the added complexity.
+ for (unsigned i = 0, e = ExplicitAliases.size(); i != e; ++i) {
+ CodeGenRegister *AR = ExplicitAliases[i];
+ // Only visit each edge once.
+ if (AR->SubRegsComplete)
+ continue;
+ // Create a RegUnit representing this alias edge, and add it to both
+ // registers.
+ unsigned Unit = RegBank.newRegUnit(this, AR);
+ RegUnits.push_back(Unit);
+ AR->RegUnits.push_back(Unit);
+ }
+
+ // Finally, create units for leaf registers without ad hoc aliases. Note that
+ // a leaf register with ad hoc aliases doesn't get its own unit - it isn't
+ // necessary. This means the aliasing leaf registers can share a single unit.
+ if (RegUnits.empty())
+ RegUnits.push_back(RegBank.newRegUnit(this));
+
+ // We have now computed the native register units. More may be adopted later
+ // for balancing purposes.
+ NumNativeRegUnits = RegUnits.size();
+
return SubRegs;
}
+// In a register that is covered by its sub-registers, try to find redundant
+// sub-registers. For example:
+//
+// QQ0 = {Q0, Q1}
+// Q0 = {D0, D1}
+// Q1 = {D2, D3}
+//
+// We can infer that D1_D2 is also a sub-register, even if it wasn't named in
+// the register definition.
+//
+// The explicitly specified registers form a tree. This function discovers
+// sub-register relationships that would force a DAG.
+//
+void CodeGenRegister::computeSecondarySubRegs(CodeGenRegBank &RegBank) {
+ // Collect new sub-registers first, add them later.
+ SmallVector<SubRegMap::value_type, 8> NewSubRegs;
+
+ // Look at the leading super-registers of each sub-register. Those are the
+ // candidates for new sub-registers, assuming they are fully contained in
+ // this register.
+ for (SubRegMap::iterator I = SubRegs.begin(), E = SubRegs.end(); I != E; ++I){
+ const CodeGenRegister *SubReg = I->second;
+ const CodeGenRegister::SuperRegList &Leads = SubReg->LeadingSuperRegs;
+ for (unsigned i = 0, e = Leads.size(); i != e; ++i) {
+ CodeGenRegister *Cand = const_cast<CodeGenRegister*>(Leads[i]);
+ // Already got this sub-register?
+ if (Cand == this || getSubRegIndex(Cand))
+ continue;
+ // Check if each component of Cand is already a sub-register.
+ // We know that the first component is I->second, and is present with the
+ // name I->first.
+ SmallVector<CodeGenSubRegIndex*, 8> Parts(1, I->first);
+ assert(!Cand->ExplicitSubRegs.empty() &&
+ "Super-register has no sub-registers");
+ for (unsigned j = 1, e = Cand->ExplicitSubRegs.size(); j != e; ++j) {
+ if (CodeGenSubRegIndex *Idx = getSubRegIndex(Cand->ExplicitSubRegs[j]))
+ Parts.push_back(Idx);
+ else {
+ // Sub-register doesn't exist.
+ Parts.clear();
+ break;
+ }
+ }
+ // If some Cand sub-register is not part of this register, or if Cand only
+ // has one sub-register, there is nothing to do.
+ if (Parts.size() <= 1)
+ continue;
+
+ // Each part of Cand is a sub-register of this. Make the full Cand also
+ // a sub-register with a concatenated sub-register index.
+ CodeGenSubRegIndex *Concat= RegBank.getConcatSubRegIndex(Parts);
+ NewSubRegs.push_back(std::make_pair(Concat, Cand));
+ }
+ }
+
+ // Now add all the new sub-registers.
+ for (unsigned i = 0, e = NewSubRegs.size(); i != e; ++i) {
+ // Don't add Cand if another sub-register is already using the index.
+ if (!SubRegs.insert(NewSubRegs[i]).second)
+ continue;
+
+ CodeGenSubRegIndex *NewIdx = NewSubRegs[i].first;
+ CodeGenRegister *NewSubReg = NewSubRegs[i].second;
+ SubReg2Idx.insert(std::make_pair(NewSubReg, NewIdx));
+ }
+
+ // Create sub-register index composition maps for the synthesized indices.
+ for (unsigned i = 0, e = NewSubRegs.size(); i != e; ++i) {
+ CodeGenSubRegIndex *NewIdx = NewSubRegs[i].first;
+ CodeGenRegister *NewSubReg = NewSubRegs[i].second;
+ for (SubRegMap::const_iterator SI = NewSubReg->SubRegs.begin(),
+ SE = NewSubReg->SubRegs.end(); SI != SE; ++SI) {
+ CodeGenSubRegIndex *SubIdx = getSubRegIndex(SI->second);
+ if (!SubIdx)
+ throw TGError(TheDef->getLoc(), "No SubRegIndex for " +
+ SI->second->getName() + " in " + getName());
+ NewIdx->addComposite(SI->first, SubIdx);
+ }
+ }
+}
+
+void CodeGenRegister::computeSuperRegs(CodeGenRegBank &RegBank) {
+ // Only visit each register once.
+ if (SuperRegsComplete)
+ return;
+ SuperRegsComplete = true;
+
+ // Make sure all sub-registers have been visited first, so the super-reg
+ // lists will be topologically ordered.
+ for (SubRegMap::const_iterator I = SubRegs.begin(), E = SubRegs.end();
+ I != E; ++I)
+ I->second->computeSuperRegs(RegBank);
+
+ // Now add this as a super-register on all sub-registers.
+ // Also compute the TopoSigId in post-order.
+ TopoSigId Id;
+ for (SubRegMap::const_iterator I = SubRegs.begin(), E = SubRegs.end();
+ I != E; ++I) {
+ // Topological signature computed from SubIdx, TopoId(SubReg).
+ // Loops and idempotent indices have TopoSig = ~0u.
+ Id.push_back(I->first->EnumValue);
+ Id.push_back(I->second->TopoSig);
+
+ // Don't add duplicate entries.
+ if (!I->second->SuperRegs.empty() && I->second->SuperRegs.back() == this)
+ continue;
+ I->second->SuperRegs.push_back(this);
+ }
+ TopoSig = RegBank.getTopoSig(Id);
+}
+
void
CodeGenRegister::addSubRegsPreOrder(SetVector<const CodeGenRegister*> &OSet,
CodeGenRegBank &RegBank) const {
assert(SubRegsComplete && "Must precompute sub-registers");
- std::vector<Record*> Indices = TheDef->getValueAsListOfDefs("SubRegIndices");
- for (unsigned i = 0, e = Indices.size(); i != e; ++i) {
- CodeGenSubRegIndex *Idx = RegBank.getSubRegIdx(Indices[i]);
- CodeGenRegister *SR = SubRegs.find(Idx)->second;
+ for (unsigned i = 0, e = ExplicitSubRegs.size(); i != e; ++i) {
+ CodeGenRegister *SR = ExplicitSubRegs[i];
if (OSet.insert(SR))
SR->addSubRegsPreOrder(OSet, RegBank);
}
+ // Add any secondary sub-registers that weren't part of the explicit tree.
+ for (SubRegMap::const_iterator I = SubRegs.begin(), E = SubRegs.end();
+ I != E; ++I)
+ OSet.insert(I->second);
+}
+
+// Compute overlapping registers.
+//
+// The standard set is all super-registers and all sub-registers, but the
+// target description can add arbitrary overlapping registers via the 'Aliases'
+// field. This complicates things, but we can compute overlapping sets using
+// the following rules:
+//
+// 1. The relation overlap(A, B) is reflexive and symmetric but not transitive.
+//
+// 2. overlap(A, B) implies overlap(A, S) for all S in supers(B).
+//
+// Alternatively:
+//
+// overlap(A, B) iff there exists:
+// A' in { A, subregs(A) } and B' in { B, subregs(B) } such that:
+// A' = B' or A' in aliases(B') or B' in aliases(A').
+//
+// Here subregs(A) is the full flattened sub-register set returned by
+// A.getSubRegs() while aliases(A) is simply the special 'Aliases' field in the
+// description of register A.
+//
+// This also implies that registers with a common sub-register are considered
+// overlapping. This can happen when forming register pairs:
+//
+// P0 = (R0, R1)
+// P1 = (R1, R2)
+// P2 = (R2, R3)
+//
+// In this case, we will infer an overlap between P0 and P1 because of the
+// shared sub-register R1. There is no overlap between P0 and P2.
+//
+void CodeGenRegister::computeOverlaps(CodeGenRegister::Set &Overlaps,
+ const CodeGenRegBank &RegBank) const {
+ assert(!RegUnits.empty() && "Compute register units before overlaps.");
+
+ // Register units are assigned such that the overlapping registers are the
+ // super-registers of the root registers of the register units.
+ for (unsigned rui = 0, rue = RegUnits.size(); rui != rue; ++rui) {
+ const RegUnit &RU = RegBank.getRegUnit(RegUnits[rui]);
+ ArrayRef<const CodeGenRegister*> Roots = RU.getRoots();
+ for (unsigned ri = 0, re = Roots.size(); ri != re; ++ri) {
+ const CodeGenRegister *Root = Roots[ri];
+ Overlaps.insert(Root);
+ ArrayRef<const CodeGenRegister*> Supers = Root->getSuperRegs();
+ Overlaps.insert(Supers.begin(), Supers.end());
+ }
+ }
}
// Get the sum of this register's unit weights.
@@ -343,7 +555,7 @@ unsigned CodeGenRegister::getWeight(const CodeGenRegBank &RegBank) const {
unsigned Weight = 0;
for (RegUnitList::const_iterator I = RegUnits.begin(), E = RegUnits.end();
I != E; ++I) {
- Weight += RegBank.getRegUnitWeight(*I);
+ Weight += RegBank.getRegUnit(*I).Weight;
}
return Weight;
}
@@ -462,7 +674,10 @@ struct TupleExpander : SetTheory::Expander {
//===----------------------------------------------------------------------===//
CodeGenRegisterClass::CodeGenRegisterClass(CodeGenRegBank &RegBank, Record *R)
- : TheDef(R), Name(R->getName()), EnumValue(-1) {
+ : TheDef(R),
+ Name(R->getName()),
+ TopoSigs(RegBank.getNumTopoSigs()),
+ EnumValue(-1) {
// Rename anonymous register classes.
if (R->getName().size() > 9 && R->getName()[9] == '.') {
static unsigned AnonCounter = 0;
@@ -487,7 +702,9 @@ CodeGenRegisterClass::CodeGenRegisterClass(CodeGenRegBank &RegBank, Record *R)
// Default allocation order always contains all registers.
for (unsigned i = 0, e = Elements->size(); i != e; ++i) {
Orders[0].push_back((*Elements)[i]);
- Members.insert(RegBank.getReg((*Elements)[i]));
+ const CodeGenRegister *Reg = RegBank.getReg((*Elements)[i]);
+ Members.insert(Reg);
+ TopoSigs.set(Reg->getTopoSig());
}
// Alternative allocation orders may be subsets.
@@ -505,29 +722,6 @@ CodeGenRegisterClass::CodeGenRegisterClass(CodeGenRegBank &RegBank, Record *R)
}
}
- // SubRegClasses is a list<dag> containing (RC, subregindex, ...) dags.
- ListInit *SRC = R->getValueAsListInit("SubRegClasses");
- for (ListInit::const_iterator i = SRC->begin(), e = SRC->end(); i != e; ++i) {
- DagInit *DAG = dynamic_cast<DagInit*>(*i);
- if (!DAG) throw "SubRegClasses must contain DAGs";
- DefInit *DAGOp = dynamic_cast<DefInit*>(DAG->getOperator());
- Record *RCRec;
- if (!DAGOp || !(RCRec = DAGOp->getDef())->isSubClassOf("RegisterClass"))
- throw "Operator '" + DAG->getOperator()->getAsString() +
- "' in SubRegClasses is not a RegisterClass";
- // Iterate over args, all SubRegIndex instances.
- for (DagInit::const_arg_iterator ai = DAG->arg_begin(), ae = DAG->arg_end();
- ai != ae; ++ai) {
- DefInit *Idx = dynamic_cast<DefInit*>(*ai);
- Record *IdxRec;
- if (!Idx || !(IdxRec = Idx->getDef())->isSubClassOf("SubRegIndex"))
- throw "Argument '" + (*ai)->getAsString() +
- "' in SubRegClasses is not a SubRegIndex";
- if (!SubRegClasses.insert(std::make_pair(IdxRec, RCRec)).second)
- throw "SubRegIndex '" + IdxRec->getName() + "' mentioned twice";
- }
- }
-
// Allow targets to override the size in bits of the RegisterClass.
unsigned Size = R->getValueAsInt("Size");
@@ -542,15 +736,20 @@ CodeGenRegisterClass::CodeGenRegisterClass(CodeGenRegBank &RegBank, Record *R)
// Create an inferred register class that was missing from the .td files.
// Most properties will be inherited from the closest super-class after the
// class structure has been computed.
-CodeGenRegisterClass::CodeGenRegisterClass(StringRef Name, Key Props)
+CodeGenRegisterClass::CodeGenRegisterClass(CodeGenRegBank &RegBank,
+ StringRef Name, Key Props)
: Members(*Props.Members),
TheDef(0),
Name(Name),
+ TopoSigs(RegBank.getNumTopoSigs()),
EnumValue(-1),
SpillSize(Props.SpillSize),
SpillAlignment(Props.SpillAlignment),
CopyCost(0),
Allocatable(true) {
+ for (CodeGenRegister::Set::iterator I = Members.begin(), E = Members.end();
+ I != E; ++I)
+ TopoSigs.set((*I)->getTopoSig());
}
// Compute inherited propertied for a synthesized register class.
@@ -634,13 +833,6 @@ static int TopoOrderRC(const void *PA, const void *PB) {
if (A == B)
return 0;
- // Order by descending set size. Note that the classes' allocation order may
- // not have been computed yet. The Members set is always vaild.
- if (A->getMembers().size() > B->getMembers().size())
- return -1;
- if (A->getMembers().size() < B->getMembers().size())
- return 1;
-
// Order by ascending spill size.
if (A->SpillSize < B->SpillSize)
return -1;
@@ -653,6 +845,13 @@ static int TopoOrderRC(const void *PA, const void *PB) {
if (A->SpillAlignment > B->SpillAlignment)
return 1;
+ // Order by descending set size. Note that the classes' allocation order may
+ // not have been computed yet. The Members set is always vaild.
+ if (A->getMembers().size() > B->getMembers().size())
+ return -1;
+ if (A->getMembers().size() < B->getMembers().size())
+ return 1;
+
// Finally order by name as a tie breaker.
return StringRef(A->getName()).compare(B->getName());
}
@@ -687,7 +886,7 @@ void CodeGenRegisterClass::computeSubClasses(CodeGenRegBank &RegBank) {
RC.SubClasses |= SubRC->SubClasses;
}
- // Sweep up missed clique members. They will be immediately preceeding RC.
+ // Sweep up missed clique members. They will be immediately preceding RC.
for (unsigned s = rci - 1; s && testSubClass(&RC, RegClasses[s - 1]); --s)
RC.SubClasses.set(s - 1);
}
@@ -772,15 +971,29 @@ CodeGenRegBank::CodeGenRegBank(RecordKeeper &Records) : Records(Records) {
getReg((*TupRegs)[j]);
}
- // Precompute all sub-register maps now all the registers are known.
+ // Now all the registers are known. Build the object graph of explicit
+ // register-register references.
+ for (unsigned i = 0, e = Registers.size(); i != e; ++i)
+ Registers[i]->buildObjectGraph(*this);
+
+ // Precompute all sub-register maps.
// This will create Composite entries for all inferred sub-register indices.
- NumRegUnits = 0;
for (unsigned i = 0, e = Registers.size(); i != e; ++i)
- Registers[i]->getSubRegs(*this);
+ Registers[i]->computeSubRegs(*this);
+
+ // Infer even more sub-registers by combining leading super-registers.
+ for (unsigned i = 0, e = Registers.size(); i != e; ++i)
+ if (Registers[i]->CoveredBySubRegs)
+ Registers[i]->computeSecondarySubRegs(*this);
+
+ // After the sub-register graph is complete, compute the topologically
+ // ordered SuperRegs list.
+ for (unsigned i = 0, e = Registers.size(); i != e; ++i)
+ Registers[i]->computeSuperRegs(*this);
// Native register units are associated with a leaf register. They've all been
// discovered now.
- NumNativeRegUnits = NumRegUnits;
+ NumNativeRegUnits = RegUnits.size();
// Read in register class definitions.
std::vector<Record*> RCs = Records.getAllDerivedDefinitions("RegisterClass");
@@ -844,7 +1057,7 @@ CodeGenRegBank::getOrCreateSubClass(const CodeGenRegisterClass *RC,
return FoundI->second;
// Sub-class doesn't exist, create a new one.
- CodeGenRegisterClass *NewRC = new CodeGenRegisterClass(Name, K);
+ CodeGenRegisterClass *NewRC = new CodeGenRegisterClass(*this, Name, K);
addToMaps(NewRC);
return NewRC;
}
@@ -871,9 +1084,37 @@ CodeGenRegBank::getCompositeSubRegIndex(CodeGenSubRegIndex *A,
return Comp;
}
+CodeGenSubRegIndex *CodeGenRegBank::
+getConcatSubRegIndex(const SmallVector<CodeGenSubRegIndex*, 8> &Parts) {
+ assert(Parts.size() > 1 && "Need two parts to concatenate");
+
+ // Look for an existing entry.
+ CodeGenSubRegIndex *&Idx = ConcatIdx[Parts];
+ if (Idx)
+ return Idx;
+
+ // None exists, synthesize one.
+ std::string Name = Parts.front()->getName();
+ for (unsigned i = 1, e = Parts.size(); i != e; ++i) {
+ Name += '_';
+ Name += Parts[i]->getName();
+ }
+ return Idx = getSubRegIdx(new Record(Name, SMLoc(), Records));
+}
+
void CodeGenRegBank::computeComposites() {
+ // Keep track of TopoSigs visited. We only need to visit each TopoSig once,
+ // and many registers will share TopoSigs on regular architectures.
+ BitVector TopoSigs(getNumTopoSigs());
+
for (unsigned i = 0, e = Registers.size(); i != e; ++i) {
CodeGenRegister *Reg1 = Registers[i];
+
+ // Skip identical subreg structures already processed.
+ if (TopoSigs.test(Reg1->getTopoSig()))
+ continue;
+ TopoSigs.set(Reg1->getTopoSig());
+
const CodeGenRegister::SubRegMap &SRM1 = Reg1->getSubRegs();
for (CodeGenRegister::SubRegMap::const_iterator i1 = SRM1.begin(),
e1 = SRM1.end(); i1 != e1; ++i1) {
@@ -886,23 +1127,21 @@ void CodeGenRegBank::computeComposites() {
// Try composing Idx1 with another SubRegIndex.
for (CodeGenRegister::SubRegMap::const_iterator i2 = SRM2.begin(),
e2 = SRM2.end(); i2 != e2; ++i2) {
- CodeGenSubRegIndex *Idx2 = i2->first;
+ CodeGenSubRegIndex *Idx2 = i2->first;
CodeGenRegister *Reg3 = i2->second;
// Ignore identity compositions.
if (Reg2 == Reg3)
continue;
// OK Reg1:IdxPair == Reg3. Find the index with Reg:Idx == Reg3.
- for (CodeGenRegister::SubRegMap::const_iterator i1d = SRM1.begin(),
- e1d = SRM1.end(); i1d != e1d; ++i1d) {
- if (i1d->second == Reg3) {
- // Conflicting composition? Emit a warning but allow it.
- if (CodeGenSubRegIndex *Prev = Idx1->addComposite(Idx2, i1d->first))
- PrintWarning(Twine("SubRegIndex") + Idx1->getQualifiedName() +
- " and " + Idx2->getQualifiedName() +
- " compose ambiguously as " + Prev->getQualifiedName() +
- " or " + i1d->first->getQualifiedName());
- }
- }
+ CodeGenSubRegIndex *Idx3 = Reg1->getSubRegIndex(Reg3);
+ assert(Idx3 && "Sub-register doesn't have an index");
+
+ // Conflicting composition? Emit a warning but allow it.
+ if (CodeGenSubRegIndex *Prev = Idx1->addComposite(Idx2, Idx3))
+ PrintWarning(Twine("SubRegIndex ") + Idx1->getQualifiedName() +
+ " and " + Idx2->getQualifiedName() +
+ " compose ambiguously as " + Prev->getQualifiedName() +
+ " or " + Idx3->getQualifiedName());
}
}
}
@@ -1023,7 +1262,7 @@ static void computeUberWeights(std::vector<UberRegSet> &UberSets,
Reg = UnitI.getReg();
Weight = 0;
}
- unsigned UWeight = RegBank.getRegUnitWeight(*UnitI);
+ unsigned UWeight = RegBank.getRegUnit(*UnitI).Weight;
if (!UWeight) {
UWeight = 1;
RegBank.increaseRegUnitWeight(*UnitI, UWeight);
@@ -1059,17 +1298,21 @@ static void computeUberWeights(std::vector<UberRegSet> &UberSets,
static bool normalizeWeight(CodeGenRegister *Reg,
std::vector<UberRegSet> &UberSets,
std::vector<UberRegSet*> &RegSets,
+ std::set<unsigned> &NormalRegs,
CodeGenRegister::RegUnitList &NormalUnits,
CodeGenRegBank &RegBank) {
bool Changed = false;
+ if (!NormalRegs.insert(Reg->EnumValue).second)
+ return Changed;
+
const CodeGenRegister::SubRegMap &SRM = Reg->getSubRegs();
for (CodeGenRegister::SubRegMap::const_iterator SRI = SRM.begin(),
SRE = SRM.end(); SRI != SRE; ++SRI) {
if (SRI->second == Reg)
continue; // self-cycles happen
- Changed |=
- normalizeWeight(SRI->second, UberSets, RegSets, NormalUnits, RegBank);
+ Changed |= normalizeWeight(SRI->second, UberSets, RegSets,
+ NormalRegs, NormalUnits, RegBank);
}
// Postorder register normalization.
@@ -1114,11 +1357,6 @@ static bool normalizeWeight(CodeGenRegister *Reg,
// The goal is that two registers in the same class will have the same weight,
// where each register's weight is defined as sum of its units' weights.
void CodeGenRegBank::computeRegUnitWeights() {
- assert(RegUnitWeights.empty() && "Only initialize RegUnitWeights once");
-
- // Only allocatable units will be initialized to nonzero weight.
- RegUnitWeights.resize(NumRegUnits);
-
std::vector<UberRegSet> UberSets;
std::vector<UberRegSet*> RegSets(Registers.size());
computeUberSets(UberSets, RegSets, *this);
@@ -1134,8 +1372,9 @@ void CodeGenRegBank::computeRegUnitWeights() {
Changed = false;
for (unsigned i = 0, e = Registers.size(); i != e; ++i) {
CodeGenRegister::RegUnitList NormalUnits;
- Changed |=
- normalizeWeight(Registers[i], UberSets, RegSets, NormalUnits, *this);
+ std::set<unsigned> NormalRegs;
+ Changed |= normalizeWeight(Registers[i], UberSets, RegSets,
+ NormalRegs, NormalUnits, *this);
}
}
}
@@ -1294,80 +1533,6 @@ void CodeGenRegBank::computeRegUnitSets() {
}
}
-// Compute sets of overlapping registers.
-//
-// The standard set is all super-registers and all sub-registers, but the
-// target description can add arbitrary overlapping registers via the 'Aliases'
-// field. This complicates things, but we can compute overlapping sets using
-// the following rules:
-//
-// 1. The relation overlap(A, B) is reflexive and symmetric but not transitive.
-//
-// 2. overlap(A, B) implies overlap(A, S) for all S in supers(B).
-//
-// Alternatively:
-//
-// overlap(A, B) iff there exists:
-// A' in { A, subregs(A) } and B' in { B, subregs(B) } such that:
-// A' = B' or A' in aliases(B') or B' in aliases(A').
-//
-// Here subregs(A) is the full flattened sub-register set returned by
-// A.getSubRegs() while aliases(A) is simply the special 'Aliases' field in the
-// description of register A.
-//
-// This also implies that registers with a common sub-register are considered
-// overlapping. This can happen when forming register pairs:
-//
-// P0 = (R0, R1)
-// P1 = (R1, R2)
-// P2 = (R2, R3)
-//
-// In this case, we will infer an overlap between P0 and P1 because of the
-// shared sub-register R1. There is no overlap between P0 and P2.
-//
-void CodeGenRegBank::
-computeOverlaps(std::map<const CodeGenRegister*, CodeGenRegister::Set> &Map) {
- assert(Map.empty());
-
- // Collect overlaps that don't follow from rule 2.
- for (unsigned i = 0, e = Registers.size(); i != e; ++i) {
- CodeGenRegister *Reg = Registers[i];
- CodeGenRegister::Set &Overlaps = Map[Reg];
-
- // Reg overlaps itself.
- Overlaps.insert(Reg);
-
- // All super-registers overlap.
- const CodeGenRegister::SuperRegList &Supers = Reg->getSuperRegs();
- Overlaps.insert(Supers.begin(), Supers.end());
-
- // Form symmetrical relations from the special Aliases[] lists.
- std::vector<Record*> RegList = Reg->TheDef->getValueAsListOfDefs("Aliases");
- for (unsigned i2 = 0, e2 = RegList.size(); i2 != e2; ++i2) {
- CodeGenRegister *Reg2 = getReg(RegList[i2]);
- CodeGenRegister::Set &Overlaps2 = Map[Reg2];
- const CodeGenRegister::SuperRegList &Supers2 = Reg2->getSuperRegs();
- // Reg overlaps Reg2 which implies it overlaps supers(Reg2).
- Overlaps.insert(Reg2);
- Overlaps.insert(Supers2.begin(), Supers2.end());
- Overlaps2.insert(Reg);
- Overlaps2.insert(Supers.begin(), Supers.end());
- }
- }
-
- // Apply rule 2. and inherit all sub-register overlaps.
- for (unsigned i = 0, e = Registers.size(); i != e; ++i) {
- CodeGenRegister *Reg = Registers[i];
- CodeGenRegister::Set &Overlaps = Map[Reg];
- const CodeGenRegister::SubRegMap &SRM = Reg->getSubRegs();
- for (CodeGenRegister::SubRegMap::const_iterator i2 = SRM.begin(),
- e2 = SRM.end(); i2 != e2; ++i2) {
- CodeGenRegister::Set &Overlaps2 = Map[i2->second];
- Overlaps.insert(Overlaps2.begin(), Overlaps2.end());
- }
- }
-}
-
void CodeGenRegBank::computeDerivedInfo() {
computeComposites();
@@ -1471,6 +1636,7 @@ void CodeGenRegBank::inferMatchingSuperRegClass(CodeGenRegisterClass *RC,
unsigned FirstSubRegRC) {
SmallVector<std::pair<const CodeGenRegister*,
const CodeGenRegister*>, 16> SSPairs;
+ BitVector TopoSigs(getNumTopoSigs());
// Iterate in SubRegIndex numerical order to visit synthetic indices last.
for (unsigned sri = 0, sre = SubRegIndices.size(); sri != sre; ++sri) {
@@ -1483,12 +1649,14 @@ void CodeGenRegBank::inferMatchingSuperRegClass(CodeGenRegisterClass *RC,
// Build list of (Super, Sub) pairs for this SubIdx.
SSPairs.clear();
+ TopoSigs.reset();
for (CodeGenRegister::Set::const_iterator RI = RC->getMembers().begin(),
RE = RC->getMembers().end(); RI != RE; ++RI) {
const CodeGenRegister *Super = *RI;
const CodeGenRegister *Sub = Super->getSubRegs().find(SubIdx)->second;
assert(Sub && "Missing sub-register");
SSPairs.push_back(std::make_pair(Super, Sub));
+ TopoSigs.set(Sub->getTopoSig());
}
// Iterate over sub-register class candidates. Ignore classes created by
@@ -1496,6 +1664,9 @@ void CodeGenRegBank::inferMatchingSuperRegClass(CodeGenRegisterClass *RC,
for (unsigned rci = FirstSubRegRC, rce = RegClasses.size(); rci != rce;
++rci) {
CodeGenRegisterClass *SubRC = RegClasses[rci];
+ // Topological shortcut: SubRC members have the wrong shape.
+ if (!TopoSigs.anyCommon(SubRC->getTopoSigs()))
+ continue;
// Compute the subset of RC that maps into SubRC.
CodeGenRegister::Set SubSet;
for (unsigned i = 0, e = SSPairs.size(); i != e; ++i)
diff --git a/utils/TableGen/CodeGenRegisters.h b/utils/TableGen/CodeGenRegisters.h
index 232a6e71de2d..eb6724ea1ac5 100644
--- a/utils/TableGen/CodeGenRegisters.h
+++ b/utils/TableGen/CodeGenRegisters.h
@@ -35,9 +35,10 @@ namespace llvm {
/// CodeGenSubRegIndex - Represents a sub-register index.
class CodeGenSubRegIndex {
Record *const TheDef;
- const unsigned EnumValue;
public:
+ const unsigned EnumValue;
+
CodeGenSubRegIndex(Record *R, unsigned Enum);
const std::string &getName() const;
@@ -67,6 +68,7 @@ namespace llvm {
// Return a conflicting composite, or NULL
CodeGenSubRegIndex *addComposite(CodeGenSubRegIndex *A,
CodeGenSubRegIndex *B) {
+ assert(A && B);
std::pair<CompMap::iterator, bool> Ins =
Composed.insert(std::make_pair(A, B));
return (Ins.second || Ins.first->second == B) ? 0 : Ins.first->second;
@@ -100,9 +102,20 @@ namespace llvm {
const std::string &getName() const;
- // Get a map of sub-registers computed lazily.
+ // Extract more information from TheDef. This is used to build an object
+ // graph after all CodeGenRegister objects have been created.
+ void buildObjectGraph(CodeGenRegBank&);
+
+ // Lazily compute a map of all sub-registers.
// This includes unique entries for all sub-sub-registers.
- const SubRegMap &getSubRegs(CodeGenRegBank&);
+ const SubRegMap &computeSubRegs(CodeGenRegBank&);
+
+ // Compute extra sub-registers by combining the existing sub-registers.
+ void computeSecondarySubRegs(CodeGenRegBank&);
+
+ // Add this as a super-register to all sub-registers after the sub-register
+ // graph has been built.
+ void computeSuperRegs(CodeGenRegBank&);
const SubRegMap &getSubRegs() const {
assert(SubRegsComplete && "Must precompute sub-registers");
@@ -113,23 +126,54 @@ namespace llvm {
void addSubRegsPreOrder(SetVector<const CodeGenRegister*> &OSet,
CodeGenRegBank&) const;
- // List of super-registers in topological order, small to large.
+ // Return the sub-register index naming Reg as a sub-register of this
+ // register. Returns NULL if Reg is not a sub-register.
+ CodeGenSubRegIndex *getSubRegIndex(const CodeGenRegister *Reg) const {
+ return SubReg2Idx.lookup(Reg);
+ }
+
typedef std::vector<const CodeGenRegister*> SuperRegList;
- // Get the list of super-registers. This is valid after getSubReg
- // visits all registers during RegBank construction.
+ // Get the list of super-registers in topological order, small to large.
+ // This is valid after computeSubRegs visits all registers during RegBank
+ // construction.
const SuperRegList &getSuperRegs() const {
assert(SubRegsComplete && "Must precompute sub-registers");
return SuperRegs;
}
+ // Get the list of ad hoc aliases. The graph is symmetric, so the list
+ // contains all registers in 'Aliases', and all registers that mention this
+ // register in 'Aliases'.
+ ArrayRef<CodeGenRegister*> getExplicitAliases() const {
+ return ExplicitAliases;
+ }
+
+ // Get the topological signature of this register. This is a small integer
+ // less than RegBank.getNumTopoSigs(). Registers with the same TopoSig have
+ // identical sub-register structure. That is, they support the same set of
+ // sub-register indices mapping to the same kind of sub-registers
+ // (TopoSig-wise).
+ unsigned getTopoSig() const {
+ assert(SuperRegsComplete && "TopoSigs haven't been computed yet.");
+ return TopoSig;
+ }
+
// List of register units in ascending order.
typedef SmallVector<unsigned, 16> RegUnitList;
+ // How many entries in RegUnitList are native?
+ unsigned NumNativeRegUnits;
+
// Get the list of register units.
- // This is only valid after getSubRegs() completes.
+ // This is only valid after computeSubRegs() completes.
const RegUnitList &getRegUnits() const { return RegUnits; }
+ // Get the native register units. This is a prefix of getRegUnits().
+ ArrayRef<unsigned> getNativeRegUnits() const {
+ return makeArrayRef(RegUnits).slice(0, NumNativeRegUnits);
+ }
+
// Inherit register units from subregisters.
// Return true if the RegUnits changed.
bool inheritRegUnits(CodeGenRegBank &RegBank);
@@ -153,10 +197,27 @@ namespace llvm {
// Canonically ordered set.
typedef std::set<const CodeGenRegister*, Less> Set;
+ // Compute the set of registers overlapping this.
+ void computeOverlaps(Set &Overlaps, const CodeGenRegBank&) const;
+
private:
bool SubRegsComplete;
+ bool SuperRegsComplete;
+ unsigned TopoSig;
+
+ // The sub-registers explicit in the .td file form a tree.
+ SmallVector<CodeGenSubRegIndex*, 8> ExplicitSubRegIndices;
+ SmallVector<CodeGenRegister*, 8> ExplicitSubRegs;
+
+ // Explicit ad hoc aliases, symmetrized to form an undirected graph.
+ SmallVector<CodeGenRegister*, 8> ExplicitAliases;
+
+ // Super-registers where this is the first explicit sub-register.
+ SuperRegList LeadingSuperRegs;
+
SubRegMap SubRegs;
SuperRegList SuperRegs;
+ DenseMap<const CodeGenRegister*, CodeGenSubRegIndex*> SubReg2Idx;
RegUnitList RegUnits;
};
@@ -189,6 +250,10 @@ namespace llvm {
DenseMap<CodeGenSubRegIndex*,
SmallPtrSet<CodeGenRegisterClass*, 8> > SuperRegClasses;
+ // Bit vector of TopoSigs for the registers in this class. This will be
+ // very sparse on regular architectures.
+ BitVector TopoSigs;
+
public:
unsigned EnumValue;
std::string Namespace;
@@ -197,8 +262,6 @@ namespace llvm {
unsigned SpillAlignment;
int CopyCost;
bool Allocatable;
- // Map SubRegIndex -> RegisterClass
- DenseMap<Record*,Record*> SubRegClasses;
std::string AltOrderSelect;
// Return the Record that defined this class, or NULL if the class was
@@ -279,6 +342,9 @@ namespace llvm {
// getOrder(0).
const CodeGenRegister::Set &getMembers() const { return Members; }
+ // Get a bit vector of TopoSigs present in this register class.
+ const BitVector &getTopoSigs() const { return TopoSigs; }
+
// Populate a unique sorted list of units from a register set.
void buildRegUnitSet(std::vector<unsigned> &RegUnits) const;
@@ -310,12 +376,37 @@ namespace llvm {
};
// Create a non-user defined register class.
- CodeGenRegisterClass(StringRef Name, Key Props);
+ CodeGenRegisterClass(CodeGenRegBank&, StringRef Name, Key Props);
// Called by CodeGenRegBank::CodeGenRegBank().
static void computeSubClasses(CodeGenRegBank&);
};
+ // Register units are used to model interference and register pressure.
+ // Every register is assigned one or more register units such that two
+ // registers overlap if and only if they have a register unit in common.
+ //
+ // Normally, one register unit is created per leaf register. Non-leaf
+ // registers inherit the units of their sub-registers.
+ struct RegUnit {
+ // Weight assigned to this RegUnit for estimating register pressure.
+ // This is useful when equalizing weights in register classes with mixed
+ // register topologies.
+ unsigned Weight;
+
+ // Each native RegUnit corresponds to one or two root registers. The full
+ // set of registers containing this unit can be computed as the union of
+ // these two registers and their super-registers.
+ const CodeGenRegister *Roots[2];
+
+ RegUnit() : Weight(0) { Roots[0] = Roots[1] = 0; }
+
+ ArrayRef<const CodeGenRegister*> getRoots() const {
+ assert(!(Roots[1] && !Roots[0]) && "Invalid roots array");
+ return makeArrayRef(Roots, !!Roots[0] + !!Roots[1]);
+ }
+ };
+
// Each RegUnitSet is a sorted vector with a name.
struct RegUnitSet {
typedef std::vector<unsigned>::const_iterator iterator;
@@ -324,6 +415,10 @@ namespace llvm {
std::vector<unsigned> Units;
};
+ // Base vector for identifying TopoSigs. The contents uniquely identify a
+ // TopoSig, only computeSuperRegs needs to know how.
+ typedef SmallVector<unsigned, 16> TopoSigId;
+
// CodeGenRegBank - Represent a target's registers and the relations between
// them.
class CodeGenRegBank {
@@ -335,15 +430,19 @@ namespace llvm {
DenseMap<Record*, CodeGenSubRegIndex*> Def2SubRegIdx;
unsigned NumNamedIndices;
+ typedef std::map<SmallVector<CodeGenSubRegIndex*, 8>,
+ CodeGenSubRegIndex*> ConcatIdxMap;
+ ConcatIdxMap ConcatIdx;
+
// Registers.
std::vector<CodeGenRegister*> Registers;
DenseMap<Record*, CodeGenRegister*> Def2Reg;
unsigned NumNativeRegUnits;
- unsigned NumRegUnits; // # native + adopted register units.
- // Map each register unit to a weight (for register pressure).
- // Includes native and adopted register units.
- std::vector<unsigned> RegUnitWeights;
+ std::map<TopoSigId, unsigned> TopoSigs;
+
+ // Includes native (0..NumNativeRegUnits-1) and adopted register units.
+ SmallVector<RegUnit, 8> RegUnits;
// Register classes.
std::vector<CodeGenRegisterClass*> RegClasses;
@@ -405,6 +504,17 @@ namespace llvm {
CodeGenSubRegIndex *getCompositeSubRegIndex(CodeGenSubRegIndex *A,
CodeGenSubRegIndex *B);
+ // Find or create a sub-register index representing the concatenation of
+ // non-overlapping sibling indices.
+ CodeGenSubRegIndex *
+ getConcatSubRegIndex(const SmallVector<CodeGenSubRegIndex*, 8>&);
+
+ void
+ addConcatSubRegIndex(const SmallVector<CodeGenSubRegIndex*, 8> &Parts,
+ CodeGenSubRegIndex *Idx) {
+ ConcatIdx.insert(std::make_pair(Parts, Idx));
+ }
+
const std::vector<CodeGenRegister*> &getRegisters() { return Registers; }
// Find a register from its Record def.
@@ -415,15 +525,34 @@ namespace llvm {
return Reg->EnumValue - 1;
}
+ // Return the number of allocated TopoSigs. The first TopoSig representing
+ // leaf registers is allocated number 0.
+ unsigned getNumTopoSigs() const {
+ return TopoSigs.size();
+ }
+
+ // Find or create a TopoSig for the given TopoSigId.
+ // This function is only for use by CodeGenRegister::computeSuperRegs().
+ // Others should simply use Reg->getTopoSig().
+ unsigned getTopoSig(const TopoSigId &Id) {
+ return TopoSigs.insert(std::make_pair(Id, TopoSigs.size())).first->second;
+ }
+
+ // Create a native register unit that is associated with one or two root
+ // registers.
+ unsigned newRegUnit(CodeGenRegister *R0, CodeGenRegister *R1 = 0) {
+ RegUnits.resize(RegUnits.size() + 1);
+ RegUnits.back().Roots[0] = R0;
+ RegUnits.back().Roots[1] = R1;
+ return RegUnits.size() - 1;
+ }
+
// Create a new non-native register unit that can be adopted by a register
// to increase its pressure. Note that NumNativeRegUnits is not increased.
unsigned newRegUnit(unsigned Weight) {
- if (!RegUnitWeights.empty()) {
- assert(Weight && "should only add allocatable units");
- RegUnitWeights.resize(NumRegUnits+1);
- RegUnitWeights[NumRegUnits] = Weight;
- }
- return NumRegUnits++;
+ RegUnits.resize(RegUnits.size() + 1);
+ RegUnits.back().Weight = Weight;
+ return RegUnits.size() - 1;
}
// Native units are the singular unit of a leaf register. Register aliasing
@@ -433,6 +562,13 @@ namespace llvm {
return RUID < NumNativeRegUnits;
}
+ unsigned getNumNativeRegUnits() const {
+ return NumNativeRegUnits;
+ }
+
+ RegUnit &getRegUnit(unsigned RUID) { return RegUnits[RUID]; }
+ const RegUnit &getRegUnit(unsigned RUID) const { return RegUnits[RUID]; }
+
ArrayRef<CodeGenRegisterClass*> getRegClasses() const {
return RegClasses;
}
@@ -447,23 +583,18 @@ namespace llvm {
/// return the superclass. Otherwise return null.
const CodeGenRegisterClass* getRegClassForRegister(Record *R);
- // Get a register unit's weight. Zero for unallocatable registers.
- unsigned getRegUnitWeight(unsigned RUID) const {
- return RegUnitWeights[RUID];
- }
-
// Get the sum of unit weights.
unsigned getRegUnitSetWeight(const std::vector<unsigned> &Units) const {
unsigned Weight = 0;
for (std::vector<unsigned>::const_iterator
I = Units.begin(), E = Units.end(); I != E; ++I)
- Weight += getRegUnitWeight(*I);
+ Weight += getRegUnit(*I).Weight;
return Weight;
}
// Increase a RegUnitWeight.
void increaseRegUnitWeight(unsigned RUID, unsigned Inc) {
- RegUnitWeights[RUID] += Inc;
+ getRegUnit(RUID).Weight += Inc;
}
// Get the number of register pressure dimensions.
@@ -485,15 +616,6 @@ namespace llvm {
// Computed derived records such as missing sub-register indices.
void computeDerivedInfo();
- // Compute full overlap sets for every register. These sets include the
- // rarely used aliases that are neither sub nor super-registers.
- //
- // Map[R1].count(R2) is reflexive and symmetric, but not transitive.
- //
- // If R1 is a sub-register of R2, Map[R1] is a subset of Map[R2].
- void computeOverlaps(std::map<const CodeGenRegister*,
- CodeGenRegister::Set> &Map);
-
// Compute the set of registers completely covered by the registers in Regs.
// The returned BitVector will have a bit set for each register in Regs,
// all sub-registers, and all super-registers that are covered by the
diff --git a/utils/TableGen/CodeGenSchedule.cpp b/utils/TableGen/CodeGenSchedule.cpp
new file mode 100644
index 000000000000..f57fd182eafb
--- /dev/null
+++ b/utils/TableGen/CodeGenSchedule.cpp
@@ -0,0 +1,151 @@
+//===- CodeGenSchedule.cpp - Scheduling MachineModels ---------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines structures to encapsulate the machine model as decribed in
+// the target description.
+//
+//===----------------------------------------------------------------------===//
+
+#define DEBUG_TYPE "subtarget-emitter"
+
+#include "CodeGenSchedule.h"
+#include "CodeGenTarget.h"
+#include "llvm/Support/Debug.h"
+
+using namespace llvm;
+
+// CodeGenModels ctor interprets machine model records and populates maps.
+CodeGenSchedModels::CodeGenSchedModels(RecordKeeper &RK,
+ const CodeGenTarget &TGT):
+ Records(RK), Target(TGT), NumItineraryClasses(0), HasProcItineraries(false) {
+
+ // Populate SchedClassIdxMap and set NumItineraryClasses.
+ CollectSchedClasses();
+
+ // Populate ProcModelMap.
+ CollectProcModels();
+}
+
+// Visit all the instruction definitions for this target to gather and enumerate
+// the itinerary classes. These are the explicitly specified SchedClasses. More
+// SchedClasses may be inferred.
+void CodeGenSchedModels::CollectSchedClasses() {
+
+ // NoItinerary is always the first class at Index=0
+ SchedClasses.resize(1);
+ SchedClasses.back().Name = "NoItinerary";
+ SchedClassIdxMap[SchedClasses.back().Name] = 0;
+
+ // Gather and sort all itinerary classes used by instruction descriptions.
+ std::vector<Record*> ItinClassList;
+ for (CodeGenTarget::inst_iterator I = Target.inst_begin(),
+ E = Target.inst_end(); I != E; ++I) {
+ Record *SchedDef = (*I)->TheDef->getValueAsDef("Itinerary");
+ // Map a new SchedClass with no index.
+ if (!SchedClassIdxMap.count(SchedDef->getName())) {
+ SchedClassIdxMap[SchedDef->getName()] = 0;
+ ItinClassList.push_back(SchedDef);
+ }
+ }
+ // 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));
+ }
+
+ // TODO: Infer classes from non-itinerary scheduler resources.
+}
+
+// Gather all processor models.
+void CodeGenSchedModels::CollectProcModels() {
+ std::vector<Record*> ProcRecords =
+ Records.getAllDerivedDefinitions("Processor");
+ std::sort(ProcRecords.begin(), ProcRecords.end(), LessRecordFieldName());
+
+ // Reserve space because we can. Reallocation would be ok.
+ ProcModels.reserve(ProcRecords.size());
+
+ // For each processor, find a unique machine model.
+ for (unsigned i = 0, N = ProcRecords.size(); i < N; ++i)
+ addProcModel(ProcRecords[i]);
+}
+
+// Get a unique processor model based on the defined MachineModel and
+// ProcessorItineraries.
+void CodeGenSchedModels::addProcModel(Record *ProcDef) {
+ unsigned Idx = getProcModelIdx(ProcDef);
+ if (Idx < ProcModels.size())
+ return;
+
+ Record *ModelDef = ProcDef->getValueAsDef("SchedModel");
+ Record *ItinsDef = ProcDef->getValueAsDef("ProcItin");
+
+ std::string ModelName = ModelDef->getName();
+ const std::string &ItinName = ItinsDef->getName();
+
+ bool NoModel = ModelDef->getValueAsBit("NoModel");
+ bool hasTopLevelItin = !ItinsDef->getValueAsListOfDefs("IID").empty();
+ if (NoModel) {
+ // If an itinerary is defined without a machine model, infer a new model.
+ if (NoModel && hasTopLevelItin) {
+ ModelName = ItinName + "Model";
+ ModelDef = NULL;
+ }
+ }
+ else {
+ // If a machine model is defined, the itinerary must be defined within it
+ // rather than in the Processor definition itself.
+ assert(!hasTopLevelItin && "Itinerary must be defined in SchedModel");
+ ItinsDef = ModelDef->getValueAsDef("Itineraries");
+ }
+
+ ProcModelMap[getProcModelKey(ProcDef)]= ProcModels.size();
+
+ ProcModels.push_back(CodeGenProcModel(ModelName, ModelDef, ItinsDef));
+
+ std::vector<Record*> ItinRecords = ItinsDef->getValueAsListOfDefs("IID");
+ CollectProcItin(ProcModels.back(), ItinRecords);
+}
+
+// Gather the processor itineraries.
+void CodeGenSchedModels::CollectProcItin(CodeGenProcModel &ProcModel,
+ std::vector<Record*> ItinRecords) {
+ // Skip empty itinerary.
+ if (ItinRecords.empty())
+ return;
+
+ HasProcItineraries = true;
+
+ ProcModel.ItinDefList.resize(NumItineraryClasses+1);
+
+ // 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())) {
+ DEBUG(dbgs() << ProcModel.ItinsDef->getName()
+ << " has unused itinerary class " << ItinDef->getName() << '\n');
+ continue;
+ }
+ ProcModel.ItinDefList[getItinClassIdx(ItinDef)] = ItinData;
+ }
+#ifndef NDEBUG
+ // Check for missing itinerary entries.
+ assert(!ProcModel.ItinDefList[0] && "NoItinerary class can't have rec");
+ for (unsigned i = 1, N = ProcModel.ItinDefList.size(); i < N; ++i) {
+ if (!ProcModel.ItinDefList[i])
+ DEBUG(dbgs() << ProcModel.ItinsDef->getName()
+ << " missing itinerary for class " << SchedClasses[i].Name << '\n');
+ }
+#endif
+}
diff --git a/utils/TableGen/CodeGenSchedule.h b/utils/TableGen/CodeGenSchedule.h
new file mode 100644
index 000000000000..9da0145732b3
--- /dev/null
+++ b/utils/TableGen/CodeGenSchedule.h
@@ -0,0 +1,172 @@
+//===- CodeGenSchedule.h - Scheduling Machine Models ------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines structures to encapsulate the machine model as decribed in
+// the target description.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CODEGEN_SCHEDULE_H
+#define CODEGEN_SCHEDULE_H
+
+#include "llvm/TableGen/Record.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringMap.h"
+
+namespace llvm {
+
+class CodeGenTarget;
+
+// Scheduling class.
+//
+// Each instruction description will be mapped to a scheduling class. It may be
+// an explicitly defined itinerary class, or an inferred class in which case
+// ItinClassDef == NULL.
+struct CodeGenSchedClass {
+ std::string Name;
+ unsigned Index;
+ Record *ItinClassDef;
+
+ CodeGenSchedClass(): Index(0), ItinClassDef(0) {}
+ CodeGenSchedClass(Record *rec): Index(0), ItinClassDef(rec) {
+ Name = rec->getName();
+ }
+};
+
+// Processor model.
+//
+// ModelName is a unique name used to name an instantiation of MCSchedModel.
+//
+// ModelDef is NULL for inferred Models. This happens when a processor defines
+// an itinerary but no machine model. If the processer defines neither a machine
+// model nor itinerary, then ModelDef remains pointing to NoModel. NoModel has
+// the special "NoModel" field set to true.
+//
+// ItinsDef always points to a valid record definition, but may point to the
+// default NoItineraries. NoItineraries has an empty list of InstrItinData
+// records.
+//
+// ItinDefList orders this processor's InstrItinData records by SchedClass idx.
+struct CodeGenProcModel {
+ std::string ModelName;
+ Record *ModelDef;
+ Record *ItinsDef;
+
+ // Array of InstrItinData records indexed by CodeGenSchedClass::Index.
+ // The list is empty if the subtarget has no itineraries.
+ std::vector<Record *> ItinDefList;
+
+ CodeGenProcModel(const std::string &Name, Record *MDef, Record *IDef):
+ ModelName(Name), ModelDef(MDef), ItinsDef(IDef) {}
+};
+
+// Top level container for machine model data.
+class CodeGenSchedModels {
+ RecordKeeper &Records;
+ const CodeGenTarget &Target;
+
+ // List of unique SchedClasses.
+ std::vector<CodeGenSchedClass> SchedClasses;
+
+ // Map SchedClass name to itinerary index.
+ // These are either explicit itinerary classes or inferred classes.
+ 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 inferred SchedClass have a index greater than NumItineraryClasses.
+ unsigned NumItineraryClasses;
+
+ // List of unique processor models.
+ std::vector<CodeGenProcModel> ProcModels;
+
+ // Map Processor's MachineModel + ProcItin fields to a CodeGenProcModel index.
+ typedef DenseMap<std::pair<Record*, Record*>, unsigned> ProcModelMapTy;
+ ProcModelMapTy ProcModelMap;
+
+ // True if any processors have nonempty itineraries.
+ bool HasProcItineraries;
+
+public:
+ CodeGenSchedModels(RecordKeeper& RK, const CodeGenTarget &TGT);
+
+ // 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.
+ const CodeGenSchedClass &getSchedClass(unsigned Idx) {
+ assert(Idx < SchedClasses.size() && "bad SchedClass index");
+ return SchedClasses[Idx];
+ }
+
+ // Get an itinerary class's index. Value indices are '0' for NoItinerary up to
+ // and including numItineraryClasses().
+ unsigned getItinClassIdx(Record *ItinDef) const {
+ assert(SchedClassIdxMap.count(ItinDef->getName()) && "missing ItinClass");
+ unsigned Idx = SchedClassIdxMap.lookup(ItinDef->getName());
+ assert(Idx <= NumItineraryClasses && "bad ItinClass index");
+ return Idx;
+ }
+
+ bool hasProcessorItineraries() const {
+ return HasProcItineraries;
+ }
+
+ // Get an existing machine model for a processor definition.
+ const CodeGenProcModel &getProcModel(Record *ProcDef) const {
+ unsigned idx = getProcModelIdx(ProcDef);
+ assert(idx < ProcModels.size() && "missing machine model");
+ return ProcModels[idx];
+ }
+
+ // Iterate over the unique processor models.
+ typedef std::vector<CodeGenProcModel>::const_iterator ProcIter;
+ ProcIter procModelBegin() const { return ProcModels.begin(); }
+ ProcIter procModelEnd() const { return ProcModels.end(); }
+
+private:
+ // Get a key that can uniquely identify a machine model.
+ ProcModelMapTy::key_type getProcModelKey(Record *ProcDef) const {
+ Record *ModelDef = ProcDef->getValueAsDef("SchedModel");
+ Record *ItinsDef = ProcDef->getValueAsDef("ProcItin");
+ return std::make_pair(ModelDef, ItinsDef);
+ }
+
+ // Get the unique index of a machine model.
+ unsigned getProcModelIdx(Record *ProcDef) const {
+ ProcModelMapTy::const_iterator I =
+ ProcModelMap.find(getProcModelKey(ProcDef));
+ if (I == ProcModelMap.end())
+ return ProcModels.size();
+ return I->second;
+ }
+
+ // Initialize a new processor model if it is unique.
+ void addProcModel(Record *ProcDef);
+
+ void CollectSchedClasses();
+ void CollectProcModels();
+ void CollectProcItin(CodeGenProcModel &ProcModel,
+ std::vector<Record*> ItinRecords);
+};
+
+} // namespace llvm
+
+#endif
diff --git a/utils/TableGen/CodeGenTarget.cpp b/utils/TableGen/CodeGenTarget.cpp
index cf6793570a26..1dd2efc4a1bf 100644
--- a/utils/TableGen/CodeGenTarget.cpp
+++ b/utils/TableGen/CodeGenTarget.cpp
@@ -16,6 +16,7 @@
#include "CodeGenTarget.h"
#include "CodeGenIntrinsics.h"
+#include "CodeGenSchedule.h"
#include "llvm/TableGen/Record.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/STLExtras.h"
@@ -112,7 +113,7 @@ std::string llvm::getQualifiedName(const Record *R) {
/// getTarget - Return the current instance of the Target class.
///
CodeGenTarget::CodeGenTarget(RecordKeeper &records)
- : Records(records), RegBank(0) {
+ : Records(records), RegBank(0), SchedModels(0) {
std::vector<Record*> Targets = Records.getAllDerivedDefinitions("Target");
if (Targets.size() == 0)
throw std::string("ERROR: No 'Target' subclasses defined!");
@@ -121,6 +122,10 @@ CodeGenTarget::CodeGenTarget(RecordKeeper &records)
TargetRec = Targets[0];
}
+CodeGenTarget::~CodeGenTarget() {
+ delete RegBank;
+ delete SchedModels;
+}
const std::string &CodeGenTarget::getName() const {
return TargetRec->getName();
@@ -155,18 +160,18 @@ Record *CodeGenTarget::getAsmParser() const {
/// this target.
///
Record *CodeGenTarget::getAsmParserVariant(unsigned i) const {
- std::vector<Record*> LI =
+ std::vector<Record*> LI =
TargetRec->getValueAsListOfDefs("AssemblyParserVariants");
if (i >= LI.size())
throw "Target does not have an AsmParserVariant #" + utostr(i) + "!";
return LI[i];
}
-/// getAsmParserVariantCount - Return the AssmblyParserVariant definition
+/// getAsmParserVariantCount - Return the AssmblyParserVariant definition
/// available for this target.
///
unsigned CodeGenTarget::getAsmParserVariantCount() const {
- std::vector<Record*> LI =
+ std::vector<Record*> LI =
TargetRec->getValueAsListOfDefs("AssemblyParserVariants");
return LI.size();
}
@@ -235,6 +240,11 @@ void CodeGenTarget::ReadLegalValueTypes() const {
LegalValueTypes.end());
}
+CodeGenSchedModels &CodeGenTarget::getSchedModels() const {
+ if (!SchedModels)
+ SchedModels = new CodeGenSchedModels(Records, *this);
+ return *SchedModels;
+}
void CodeGenTarget::ReadInstructions() const {
std::vector<Record*> Insts = Records.getAllDerivedDefinitions("Instruction");
@@ -387,6 +397,7 @@ CodeGenIntrinsic::CodeGenIntrinsic(Record *R) {
isOverloaded = false;
isCommutative = false;
canThrow = false;
+ isNoReturn = false;
if (DefName.size() <= 4 ||
std::string(DefName.begin(), DefName.begin() + 4) != "int_")
@@ -511,6 +522,8 @@ CodeGenIntrinsic::CodeGenIntrinsic(Record *R) {
isCommutative = true;
else if (Property->getName() == "Throws")
canThrow = true;
+ else if (Property->getName() == "IntrNoReturn")
+ isNoReturn = true;
else if (Property->isSubClassOf("NoCapture")) {
unsigned ArgNo = Property->getValueAsInt("ArgNo");
ArgumentAttributes.push_back(std::make_pair(ArgNo, NoCapture));
diff --git a/utils/TableGen/CodeGenTarget.h b/utils/TableGen/CodeGenTarget.h
index 85463da59731..2f8cee4588a4 100644
--- a/utils/TableGen/CodeGenTarget.h
+++ b/utils/TableGen/CodeGenTarget.h
@@ -26,6 +26,7 @@
namespace llvm {
struct CodeGenRegister;
+class CodeGenSchedModels;
class CodeGenTarget;
// SelectionDAG node properties.
@@ -72,9 +73,12 @@ class CodeGenTarget {
void ReadInstructions() const;
void ReadLegalValueTypes() const;
+ mutable CodeGenSchedModels *SchedModels;
+
mutable std::vector<const CodeGenInstruction*> InstrsByEnum;
public:
CodeGenTarget(RecordKeeper &Records);
+ ~CodeGenTarget();
Record *getTargetRecord() const { return TargetRec; }
const std::string &getName() const;
@@ -96,7 +100,7 @@ public:
///
Record *getAsmParserVariant(unsigned i) const;
- /// getAsmParserVariantCount - Return the AssmblyParserVariant definition
+ /// getAsmParserVariantCount - Return the AssmblyParserVariant definition
/// available for this target.
///
unsigned getAsmParserVariantCount() const;
@@ -139,6 +143,8 @@ public:
return false;
}
+ CodeGenSchedModels &getSchedModels() const;
+
private:
DenseMap<const Record*, CodeGenInstruction*> &getInstructions() const {
if (Instructions.empty()) ReadInstructions();
diff --git a/utils/TableGen/DAGISelEmitter.cpp b/utils/TableGen/DAGISelEmitter.cpp
index 7db90034999f..b47dd71e88e6 100644
--- a/utils/TableGen/DAGISelEmitter.cpp
+++ b/utils/TableGen/DAGISelEmitter.cpp
@@ -11,12 +11,24 @@
//
//===----------------------------------------------------------------------===//
-#include "DAGISelEmitter.h"
+#include "CodeGenDAGPatterns.h"
#include "DAGISelMatcher.h"
-#include "llvm/TableGen/Record.h"
#include "llvm/Support/Debug.h"
+#include "llvm/TableGen/Record.h"
+#include "llvm/TableGen/TableGenBackend.h"
using namespace llvm;
+namespace {
+/// DAGISelEmitter - The top-level class which coordinates construction
+/// and emission of the instruction selector.
+class DAGISelEmitter {
+ CodeGenDAGPatterns CGP;
+public:
+ explicit DAGISelEmitter(RecordKeeper &R) : CGP(R) {}
+ void run(raw_ostream &OS);
+};
+} // End anonymous namespace
+
//===----------------------------------------------------------------------===//
// DAGISelEmitter Helper methods
//
@@ -104,11 +116,11 @@ struct PatternSortingPredicate {
return LHS->ID < RHS->ID;
}
};
-}
+} // End anonymous namespace
void DAGISelEmitter::run(raw_ostream &OS) {
- EmitSourceFileHeader("DAG Instruction Selector for the " +
+ emitSourceFileHeader("DAG Instruction Selector for the " +
CGP.getTargetInfo().getName() + " target", OS);
OS << "// *** NOTE: This file is #included into the middle of the target\n"
@@ -153,3 +165,11 @@ void DAGISelEmitter::run(raw_ostream &OS) {
EmitMatcherTable(TheMatcher, CGP, OS);
delete TheMatcher;
}
+
+namespace llvm {
+
+void EmitDAGISel(RecordKeeper &RK, raw_ostream &OS) {
+ DAGISelEmitter(RK).run(OS);
+}
+
+} // End llvm namespace
diff --git a/utils/TableGen/DAGISelEmitter.h b/utils/TableGen/DAGISelEmitter.h
deleted file mode 100644
index 9c9fe4273fed..000000000000
--- a/utils/TableGen/DAGISelEmitter.h
+++ /dev/null
@@ -1,37 +0,0 @@
-//===- DAGISelEmitter.h - Generate an instruction selector ------*- 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 emits a DAG instruction selector.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef DAGISEL_EMITTER_H
-#define DAGISEL_EMITTER_H
-
-#include "llvm/TableGen/TableGenBackend.h"
-#include "CodeGenDAGPatterns.h"
-
-namespace llvm {
-
-/// DAGISelEmitter - The top-level class which coordinates construction
-/// and emission of the instruction selector.
-///
-class DAGISelEmitter : public TableGenBackend {
- RecordKeeper &Records;
- CodeGenDAGPatterns CGP;
-public:
- explicit DAGISelEmitter(RecordKeeper &R) : Records(R), CGP(R) {}
-
- // run - Output the isel, returning true on failure.
- void run(raw_ostream &OS);
-};
-
-} // End llvm namespace
-
-#endif
diff --git a/utils/TableGen/DAGISelMatcher.h b/utils/TableGen/DAGISelMatcher.h
index 99ebf98b1e4b..3ca16f04269d 100644
--- a/utils/TableGen/DAGISelMatcher.h
+++ b/utils/TableGen/DAGISelMatcher.h
@@ -35,7 +35,7 @@ void EmitMatcherTable(const Matcher *Matcher, const CodeGenDAGPatterns &CGP,
raw_ostream &OS);
-/// Matcher - Base class for all the the DAG ISel Matcher representation
+/// Matcher - Base class for all the DAG ISel Matcher representation
/// nodes.
class Matcher {
// The next matcher node that is executed after this one. Null if this is the
diff --git a/utils/TableGen/DAGISelMatcherEmitter.cpp b/utils/TableGen/DAGISelMatcherEmitter.cpp
index bd425a9bc1a9..1445edbe720a 100644
--- a/utils/TableGen/DAGISelMatcherEmitter.cpp
+++ b/utils/TableGen/DAGISelMatcherEmitter.cpp
@@ -526,10 +526,10 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
// Print the result #'s for EmitNode.
if (const EmitNodeMatcher *E = dyn_cast<EmitNodeMatcher>(EN)) {
if (unsigned NumResults = EN->getNumVTs()) {
- OS.PadToColumn(CommentIndent) << "// Results = ";
+ OS.PadToColumn(CommentIndent) << "// Results =";
unsigned First = E->getFirstResultSlot();
for (unsigned i = 0; i != NumResults; ++i)
- OS << "#" << First+i << " ";
+ OS << " #" << First+i;
}
}
OS << '\n';
diff --git a/utils/TableGen/DAGISelMatcherGen.cpp b/utils/TableGen/DAGISelMatcherGen.cpp
index 2ac7b87e7010..aed222c09495 100644
--- a/utils/TableGen/DAGISelMatcherGen.cpp
+++ b/utils/TableGen/DAGISelMatcherGen.cpp
@@ -690,6 +690,13 @@ EmitResultInstructionAsOperand(const TreePatternNode *N,
bool NodeHasChain = InstPatNode &&
InstPatNode->TreeHasProperty(SDNPHasChain, CGP);
+ // Instructions which load and store from memory should have a chain,
+ // regardless of whether they happen to have an internal pattern saying so.
+ if (Pattern.getSrcPattern()->TreeHasProperty(SDNPHasChain, CGP)
+ && (II.hasCtrlDep || II.mayLoad || II.mayStore || II.canFoldAsLoad ||
+ II.hasSideEffects))
+ NodeHasChain = true;
+
bool isRoot = N == Pattern.getDstPattern();
// TreeHasOutGlue - True if this tree has glue.
diff --git a/utils/TableGen/DFAPacketizerEmitter.cpp b/utils/TableGen/DFAPacketizerEmitter.cpp
index 4abf54ebae2e..8bfecead6d2e 100644
--- a/utils/TableGen/DFAPacketizerEmitter.cpp
+++ b/utils/TableGen/DFAPacketizerEmitter.cpp
@@ -15,14 +15,47 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/TableGen/Record.h"
#include "CodeGenTarget.h"
-#include "DFAPacketizerEmitter.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/TableGen/Record.h"
+#include "llvm/TableGen/TableGenBackend.h"
#include <list>
-
+#include <map>
+#include <string>
using namespace llvm;
//
+// class DFAPacketizerEmitter: class that generates and prints out the DFA
+// for resource tracking.
+//
+namespace {
+class DFAPacketizerEmitter {
+private:
+ std::string TargetName;
+ //
+ // allInsnClasses is the set of all possible resources consumed by an
+ // InstrStage.
+ //
+ DenseSet<unsigned> allInsnClasses;
+ RecordKeeper &Records;
+
+public:
+ DFAPacketizerEmitter(RecordKeeper &R);
+
+ //
+ // collectAllInsnClasses: Populate allInsnClasses which is a set of units
+ // used in each stage.
+ //
+ void collectAllInsnClasses(const std::string &Name,
+ Record *ItinData,
+ unsigned &NStages,
+ raw_ostream &OS);
+
+ void run(raw_ostream &OS);
+};
+} // End anonymous namespace.
+
+//
//
// State represents the usage of machine resources if the packet contains
// a set of instruction classes.
@@ -61,7 +94,12 @@ class State {
// PossibleStates is the set of valid resource states that ensue from valid
// transitions.
//
- bool canAddInsnClass(unsigned InsnClass, std::set<unsigned> &PossibleStates);
+ bool canAddInsnClass(unsigned InsnClass) const;
+ //
+ // AddInsnClass - Return all combinations of resource reservation
+ // which are possible from this state (PossibleStates).
+ //
+ void AddInsnClass(unsigned InsnClass, std::set<unsigned> &PossibleStates);
};
} // End anonymous namespace.
@@ -87,6 +125,10 @@ namespace {
struct ltState {
bool operator()(const State *s1, const State *s2) const;
};
+
+struct ltTransition {
+ bool operator()(const Transition *s1, const Transition *s2) const;
+};
} // End anonymous namespace.
@@ -102,7 +144,8 @@ public:
std::set<State*, ltState> states;
// Map from a state to the list of transitions with that state as source.
- std::map<State*, SmallVector<Transition*, 16>, ltState> stateTransitions;
+ std::map<State*, std::set<Transition*, ltTransition>, ltState>
+ stateTransitions;
State *currentState;
// Highest valued Input seen.
@@ -160,21 +203,19 @@ bool ltState::operator()(const State *s1, const State *s2) const {
return (s1->stateNum < s2->stateNum);
}
+bool ltTransition::operator()(const Transition *s1, const Transition *s2) const {
+ return (s1->input < s2->input);
+}
//
-// canAddInsnClass - Returns true if an instruction of type InsnClass is a
-// valid transition from this state i.e., can an instruction of type InsnClass
-// be added to the packet represented by this state.
-//
-// PossibleStates is the set of valid resource states that ensue from valid
-// transitions.
+// AddInsnClass - Return all combinations of resource reservation
+// which are possible from this state (PossibleStates).
//
-bool State::canAddInsnClass(unsigned InsnClass,
+void State::AddInsnClass(unsigned InsnClass,
std::set<unsigned> &PossibleStates) {
//
// Iterate over all resource states in currentState.
//
- bool AddedState = false;
for (std::set<unsigned>::iterator SI = stateInfo.begin();
SI != stateInfo.end(); ++SI) {
@@ -207,13 +248,26 @@ bool State::canAddInsnClass(unsigned InsnClass,
(VisitedResourceStates.count(ResultingResourceState) == 0)) {
VisitedResourceStates.insert(ResultingResourceState);
PossibleStates.insert(ResultingResourceState);
- AddedState = true;
}
}
}
}
- return AddedState;
+}
+
+
+//
+// canAddInsnClass - Quickly verifies if an instruction of type InsnClass is a
+// valid transition from this state i.e., can an instruction of type InsnClass
+// be added to the packet represented by this state.
+//
+bool State::canAddInsnClass(unsigned InsnClass) const {
+ for (std::set<unsigned>::const_iterator SI = stateInfo.begin();
+ SI != stateInfo.end(); ++SI) {
+ if (~*SI & InsnClass)
+ return true;
+ }
+ return false;
}
@@ -234,7 +288,9 @@ void DFA::addTransition(Transition *T) {
LargestInput = T->input;
// Add the new transition.
- stateTransitions[T->from].push_back(T);
+ bool Added = stateTransitions[T->from].insert(T).second;
+ assert(Added && "Cannot have multiple states for the same input");
+ (void)Added;
}
@@ -248,11 +304,13 @@ State *DFA::getTransition(State *From, unsigned I) {
return NULL;
// Do we have a transition from state From with Input I?
- for (SmallVector<Transition*, 16>::iterator VI =
- stateTransitions[From].begin();
- VI != stateTransitions[From].end(); ++VI)
- if ((*VI)->input == I)
- return (*VI)->to;
+ Transition TVal(NULL, I, NULL);
+ // Do not count this temporal instance
+ Transition::currentTransitionNum--;
+ std::set<Transition*, ltTransition>::iterator T =
+ stateTransitions[From].find(&TVal);
+ if (T != stateTransitions[From].end())
+ return (*T)->to;
return NULL;
}
@@ -266,7 +324,7 @@ bool DFA::isValidTransition(State *From, unsigned InsnClass) {
int State::currentStateNum = 0;
int Transition::currentTransitionNum = 0;
-DFAGen::DFAGen(RecordKeeper &R):
+DFAPacketizerEmitter::DFAPacketizerEmitter(RecordKeeper &R):
TargetName(CodeGenTarget(R).getName()),
allInsnClasses(), Records(R) {}
@@ -298,11 +356,12 @@ void DFA::writeTableAndAPI(raw_ostream &OS, const std::string &TargetName) {
StateEntry[i] = ValidTransitions;
for (unsigned j = 0; j <= LargestInput; ++j) {
assert (((*SI)->stateNum == (int) i) && "Mismatch in state numbers");
- if (!isValidTransition(*SI, j))
+ State *To = getTransition(*SI, j);
+ if (To == NULL)
continue;
OS << "{" << j << ", "
- << getTransition(*SI, j)->stateNum
+ << To->stateNum
<< "}, ";
++ValidTransitions;
}
@@ -346,7 +405,7 @@ void DFA::writeTableAndAPI(raw_ostream &OS, const std::string &TargetName) {
// collectAllInsnClasses - Populate allInsnClasses which is a set of units
// used in each stage.
//
-void DFAGen::collectAllInsnClasses(const std::string &Name,
+void DFAPacketizerEmitter::collectAllInsnClasses(const std::string &Name,
Record *ItinData,
unsigned &NStages,
raw_ostream &OS) {
@@ -402,8 +461,7 @@ void DFAGen::collectAllInsnClasses(const std::string &Name,
//
// Run the worklist algorithm to generate the DFA.
//
-void DFAGen::run(raw_ostream &OS) {
- EmitSourceFileHeader("Target DFA Packetizer Tables", OS);
+void DFAPacketizerEmitter::run(raw_ostream &OS) {
// Collect processor iteraries.
std::vector<Record*> ProcItinList =
@@ -482,8 +540,10 @@ void DFAGen::run(raw_ostream &OS) {
// and the state can accommodate this InsnClass, create a transition.
//
if (!D.getTransition(current, InsnClass) &&
- current->canAddInsnClass(InsnClass, NewStateResources)) {
+ current->canAddInsnClass(InsnClass)) {
State *NewState = NULL;
+ current->AddInsnClass(InsnClass, NewStateResources);
+ assert(NewStateResources.size() && "New states must be generated");
//
// If we have seen this state before, then do not create a new state.
@@ -510,3 +570,12 @@ void DFAGen::run(raw_ostream &OS) {
// Print out the table.
D.writeTableAndAPI(OS, TargetName);
}
+
+namespace llvm {
+
+void EmitDFAPacketizer(RecordKeeper &RK, raw_ostream &OS) {
+ emitSourceFileHeader("Target DFA Packetizer Tables", OS);
+ DFAPacketizerEmitter(RK).run(OS);
+}
+
+} // End llvm namespace
diff --git a/utils/TableGen/DFAPacketizerEmitter.h b/utils/TableGen/DFAPacketizerEmitter.h
deleted file mode 100644
index 1727150ae926..000000000000
--- a/utils/TableGen/DFAPacketizerEmitter.h
+++ /dev/null
@@ -1,52 +0,0 @@
-//===- DFAPacketizerEmitter.h - Packetization DFA for a VLIW machine-------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This class parses the Schedule.td file and produces an API that can be used
-// to reason about whether an instruction can be added to a packet on a VLIW
-// architecture. The class internally generates a deterministic finite
-// automaton (DFA) that models all possible mappings of machine instructions
-// to functional units as instructions are added to a packet.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/ADT/DenseSet.h"
-#include "llvm/TableGen/TableGenBackend.h"
-#include <map>
-#include <string>
-
-namespace llvm {
-//
-// class DFAGen: class that generates and prints out the DFA for resource
-// tracking.
-//
-class DFAGen : public TableGenBackend {
-private:
- std::string TargetName;
- //
- // allInsnClasses is the set of all possible resources consumed by an
- // InstrStage.
- //
- DenseSet<unsigned> allInsnClasses;
- RecordKeeper &Records;
-
-public:
- DFAGen(RecordKeeper &R);
-
- //
- // collectAllInsnClasses: Populate allInsnClasses which is a set of units
- // used in each stage.
- //
- void collectAllInsnClasses(const std::string &Name,
- Record *ItinData,
- unsigned &NStages,
- raw_ostream &OS);
-
- void run(raw_ostream &OS);
-};
-}
diff --git a/utils/TableGen/DisassemblerEmitter.cpp b/utils/TableGen/DisassemblerEmitter.cpp
index 4650197ae718..826465a51642 100644
--- a/utils/TableGen/DisassemblerEmitter.cpp
+++ b/utils/TableGen/DisassemblerEmitter.cpp
@@ -7,13 +7,12 @@
//
//===----------------------------------------------------------------------===//
-#include "DisassemblerEmitter.h"
#include "CodeGenTarget.h"
#include "X86DisassemblerTables.h"
#include "X86RecognizableInstr.h"
-#include "FixedLenDecoderEmitter.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
+#include "llvm/TableGen/TableGenBackend.h"
using namespace llvm;
using namespace llvm::X86Disassembler;
@@ -94,26 +93,27 @@ using namespace llvm::X86Disassembler;
/// X86RecognizableInstr.cpp contains the implementation for a single
/// instruction.
-void DisassemblerEmitter::run(raw_ostream &OS) {
- CodeGenTarget Target(Records);
+namespace llvm {
+
+extern void EmitFixedLenDecoder(RecordKeeper &RK, raw_ostream &OS,
+ std::string PredicateNamespace,
+ std::string GPrefix,
+ std::string GPostfix,
+ std::string ROK,
+ std::string RFail,
+ std::string L);
- OS << "/*===- TableGen'erated file "
- << "---------------------------------------*- C -*-===*\n"
- << " *\n"
- << " * " << Target.getName() << " Disassembler\n"
- << " *\n"
- << " * Automatically generated file, do not edit!\n"
- << " *\n"
- << " *===---------------------------------------------------------------"
- << "-------===*/\n";
+void EmitDisassembler(RecordKeeper &Records, raw_ostream &OS) {
+ CodeGenTarget Target(Records);
+ emitSourceFileHeader(" * " + Target.getName() + " Disassembler", OS);
// X86 uses a custom disassembler.
if (Target.getName() == "X86") {
DisassemblerTables Tables;
-
+
const std::vector<const CodeGenInstruction*> &numberedInstructions =
Target.getInstructionsByEnumValue();
-
+
for (unsigned i = 0, e = numberedInstructions.size(); i != e; ++i)
RecognizableInstr::processInstr(Tables, *numberedInstructions[i], i);
@@ -130,13 +130,18 @@ void DisassemblerEmitter::run(raw_ostream &OS) {
// ARM and Thumb have a CHECK() macro to deal with DecodeStatuses.
if (Target.getName() == "ARM" ||
Target.getName() == "Thumb") {
- FixedLenDecoderEmitter(Records,
- "ARM",
- "if (!Check(S, ", ")) return MCDisassembler::Fail;",
- "S", "MCDisassembler::Fail",
- " MCDisassembler::DecodeStatus S = MCDisassembler::Success;\n(void)S;").run(OS);
+ EmitFixedLenDecoder(Records, OS, "ARM",
+ "if (!Check(S, ", ")) return MCDisassembler::Fail;",
+ "S", "MCDisassembler::Fail",
+ " MCDisassembler::DecodeStatus S = "
+ "MCDisassembler::Success;\n(void)S;");
return;
}
- FixedLenDecoderEmitter(Records, Target.getName()).run(OS);
+ EmitFixedLenDecoder(Records, OS, Target.getName(),
+ "if (", " == MCDisassembler::Fail)"
+ " return MCDisassembler::Fail;",
+ "MCDisassembler::Success", "MCDisassembler::Fail", "");
}
+
+} // End llvm namespace
diff --git a/utils/TableGen/DisassemblerEmitter.h b/utils/TableGen/DisassemblerEmitter.h
deleted file mode 100644
index 63ee55264ad8..000000000000
--- a/utils/TableGen/DisassemblerEmitter.h
+++ /dev/null
@@ -1,28 +0,0 @@
-//===- DisassemblerEmitter.h - Disassembler Generator -----------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef DISASSEMBLEREMITTER_H
-#define DISASSEMBLEREMITTER_H
-
-#include "llvm/TableGen/TableGenBackend.h"
-
-namespace llvm {
-
- class DisassemblerEmitter : public TableGenBackend {
- RecordKeeper &Records;
- public:
- DisassemblerEmitter(RecordKeeper &R) : Records(R) {}
-
- /// run - Output the disassembler.
- void run(raw_ostream &o);
- };
-
-} // end llvm namespace
-
-#endif
diff --git a/utils/TableGen/EDEmitter.cpp b/utils/TableGen/EDEmitter.cpp
index fe484ca8cf18..0c8b28d22027 100644
--- a/utils/TableGen/EDEmitter.cpp
+++ b/utils/TableGen/EDEmitter.cpp
@@ -13,192 +13,199 @@
//
//===----------------------------------------------------------------------===//
-#include "EDEmitter.h"
-
#include "AsmWriterInst.h"
#include "CodeGenTarget.h"
-
-#include "llvm/TableGen/Record.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/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 //
///////////////////////////////////////////////////////////
-namespace {
+// TODO: These classes are probably generally useful to other backends;
+// add them to TableGen's "helper" API's.
- 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;
+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";
}
- 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";
+ 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;
}
- 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
- i -= 2;
- o.indent(i) << "};" << "\n";
- }
- };
+namespace {
+class ConstantEmitter {
+public:
+ virtual ~ConstantEmitter() { }
+ virtual void emit(raw_ostream &o, unsigned int &i) = 0;
+};
+} // End anonymous namespace
- class ConstantEmitter {
- public:
- virtual ~ConstantEmitter() { }
- virtual void emit(raw_ostream &o, unsigned int &i) = 0;
+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
- 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;
- }
- };
+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);
- class CompoundConstantEmitter : public ConstantEmitter {
- private:
- unsigned int Padding;
- std::vector<ConstantEmitter *> Entries;
- public:
- CompoundConstantEmitter(unsigned int padding = 0) : Padding(padding) {
+ return *this;
+ }
+ ~CompoundConstantEmitter() {
+ while (Entries.size()) {
+ ConstantEmitter *entry = Entries.back();
+ Entries.pop_back();
+ delete entry;
}
- CompoundConstantEmitter &addEntry(ConstantEmitter *e) {
- Entries.push_back(e);
+ }
+ void emit(raw_ostream &o, unsigned int &i) {
+ o << "{" << "\n";
+ i += 2;
- 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;
- }
+ unsigned int index;
+ unsigned int numEntries = Entries.size();
- for (index = 0; index < numToPrint; ++index) {
- o.indent(i);
- if (index < numEntries)
- Entries[index]->emit(o, i);
- else
- o << "-1";
+ unsigned int numToPrint;
- if (index < (numToPrint - 1))
- o << ",";
- o << "\n";
+ if (Padding) {
+ if (numEntries > Padding) {
+ fprintf(stderr, "%u entries but %u padding\n", numEntries, Padding);
+ llvm_unreachable("More entries than padding");
}
-
- i -= 2;
- o.indent(i) << "}";
+ numToPrint = Padding;
+ } else {
+ numToPrint = numEntries;
}
- };
- 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 << " | ";
- }
+ 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";
}
- };
-}
-EDEmitter::EDEmitter(RecordKeeper &R) : Records(R) {
-}
+ 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
@@ -213,9 +220,9 @@ EDEmitter::EDEmitter(RecordKeeper &R) : Records(R) {
/// 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
-void populateOperandOrder(CompoundConstantEmitter *operandOrder,
- const CodeGenInstruction &inst,
- unsigned syntax) {
+static void populateOperandOrder(CompoundConstantEmitter *operandOrder,
+ const CodeGenInstruction &inst,
+ unsigned syntax) {
unsigned int numArgs = 0;
AsmWriterInst awInst(inst, syntax, -1, -1);
@@ -310,6 +317,11 @@ static int X86TypeFromOpName(LiteralConstantEmitter *type,
MEM("f128mem");
MEM("f256mem");
MEM("opaque512mem");
+ // Gather
+ MEM("vx32mem")
+ MEM("vy32mem")
+ MEM("vx64mem")
+ MEM("vy64mem")
// all R, I, R, I
LEA("lea32mem");
@@ -975,17 +987,23 @@ static void emitCommonEnums(raw_ostream &o, unsigned int &i) {
o << "\n";
}
-void EDEmitter::run(raw_ostream &o) {
+namespace llvm {
+
+void EmitEnhancedDisassemblerInfo(RecordKeeper &RK, raw_ostream &OS) {
+ emitSourceFileHeader("Enhanced Disassembler Info", OS);
unsigned int i = 0;
CompoundConstantEmitter infoArray;
- CodeGenTarget target(Records);
+ CodeGenTarget target(RK);
populateInstInfo(infoArray, target);
- emitCommonEnums(o, i);
+ emitCommonEnums(OS, i);
- o << "static const llvm::EDInstInfo instInfo" << target.getName() << "[] = ";
- infoArray.emit(o, i);
- o << ";" << "\n";
+ OS << "static const llvm::EDInstInfo instInfo"
+ << target.getName() << "[] = ";
+ infoArray.emit(OS, i);
+ OS << ";" << "\n";
}
+
+} // End llvm namespace
diff --git a/utils/TableGen/EDEmitter.h b/utils/TableGen/EDEmitter.h
deleted file mode 100644
index f26837554722..000000000000
--- a/utils/TableGen/EDEmitter.h
+++ /dev/null
@@ -1,34 +0,0 @@
-//===- EDEmitter.h - 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 semantic disassembler can use to tokenize
-// and parse instructions.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef SEMANTIC_INFO_EMITTER_H
-#define SEMANTIC_INFO_EMITTER_H
-
-#include "llvm/TableGen/TableGenBackend.h"
-
-namespace llvm {
-
- class EDEmitter : public TableGenBackend {
- RecordKeeper &Records;
- public:
- EDEmitter(RecordKeeper &R);
-
- // run - Output the instruction table.
- void run(raw_ostream &o);
- };
-
-} // End llvm namespace
-
-#endif
diff --git a/utils/TableGen/FastISelEmitter.cpp b/utils/TableGen/FastISelEmitter.cpp
index e8dad77302c3..ca784d0dda92 100644
--- a/utils/TableGen/FastISelEmitter.cpp
+++ b/utils/TableGen/FastISelEmitter.cpp
@@ -17,28 +17,31 @@
//
//===----------------------------------------------------------------------===//
-#include "FastISelEmitter.h"
-#include "llvm/TableGen/Error.h"
-#include "llvm/TableGen/Record.h"
+#include "CodeGenDAGPatterns.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/TableGen/Error.h"
+#include "llvm/TableGen/Record.h"
+#include "llvm/TableGen/TableGenBackend.h"
using namespace llvm;
-namespace {
/// InstructionMemo - This class holds additional information about an
/// instruction needed to emit code for it.
///
+namespace {
struct InstructionMemo {
std::string Name;
const CodeGenRegisterClass *RC;
std::string SubRegNo;
std::vector<std::string>* PhysRegs;
};
-
+} // End anonymous namespace
+
/// ImmPredicateSet - This uniques predicates (represented as a string) and
/// gives them unique (small) integer ID's that start at 0.
+namespace {
class ImmPredicateSet {
DenseMap<TreePattern *, unsigned> ImmIDs;
std::vector<TreePredicateFn> PredsByName;
@@ -63,10 +66,12 @@ public:
iterator end() const { return PredsByName.end(); }
};
+} // End anonymous namespace
/// OperandsSignature - This class holds a description of a list of operand
/// types. It has utility methods for emitting text based on the operands.
///
+namespace {
struct OperandsSignature {
class OpKind {
enum { OK_Reg, OK_FP, OK_Imm, OK_Invalid = -1 };
@@ -352,7 +357,9 @@ struct OperandsSignature {
Operands[i].printManglingSuffix(OS, ImmPredicates, StripImmCodes);
}
};
+} // End anonymous namespace
+namespace {
class FastISelMap {
typedef std::map<std::string, InstructionMemo> PredMap;
typedef std::map<MVT::SimpleValueType, PredMap> RetPredMap;
@@ -375,8 +382,7 @@ public:
void printImmediatePredicates(raw_ostream &OS);
void printFunctionDefinitions(raw_ostream &OS);
};
-
-}
+} // End anonymous namespace
static std::string getOpcodeName(Record *Op, CodeGenDAGPatterns &CGP) {
return CGP.getSDNodeInfo(Op).getEnumName();
@@ -639,7 +645,7 @@ void FastISelMap::printFunctionDefinitions(raw_ostream &OS) {
Operands.PrintManglingSuffix(OS, *Memo.PhysRegs,
ImmediatePredicates, true);
OS << "(" << InstNS << Memo.Name << ", ";
- OS << InstNS << Memo.RC->getName() << "RegisterClass";
+ OS << "&" << InstNS << Memo.RC->getName() << "RegClass";
if (!Operands.empty())
OS << ", ";
Operands.PrintArguments(OS, *Memo.PhysRegs);
@@ -731,7 +737,7 @@ void FastISelMap::printFunctionDefinitions(raw_ostream &OS) {
Operands.PrintManglingSuffix(OS, *Memo.PhysRegs,
ImmediatePredicates, true);
OS << "(" << InstNS << Memo.Name << ", ";
- OS << InstNS << Memo.RC->getName() << "RegisterClass";
+ OS << "&" << InstNS << Memo.RC->getName() << "RegClass";
if (!Operands.empty())
OS << ", ";
Operands.PrintArguments(OS, *Memo.PhysRegs);
@@ -850,23 +856,22 @@ void FastISelMap::printFunctionDefinitions(raw_ostream &OS) {
// TODO: SignaturesWithConstantForms should be empty here.
}
-void FastISelEmitter::run(raw_ostream &OS) {
+namespace llvm {
+
+void EmitFastISel(RecordKeeper &RK, raw_ostream &OS) {
+ CodeGenDAGPatterns CGP(RK);
const CodeGenTarget &Target = CGP.getTargetInfo();
+ emitSourceFileHeader("\"Fast\" Instruction Selector for the " +
+ Target.getName() + " target", OS);
// Determine the target's namespace name.
std::string InstNS = Target.getInstNamespace() + "::";
assert(InstNS.size() > 2 && "Can't determine target-specific namespace!");
- EmitSourceFileHeader("\"Fast\" Instruction Selector for the " +
- Target.getName() + " target", OS);
-
FastISelMap F(InstNS);
F.collectPatterns(CGP);
F.printImmediatePredicates(OS);
F.printFunctionDefinitions(OS);
}
-FastISelEmitter::FastISelEmitter(RecordKeeper &R)
- : Records(R), CGP(R) {
-}
-
+} // End llvm namespace
diff --git a/utils/TableGen/FastISelEmitter.h b/utils/TableGen/FastISelEmitter.h
deleted file mode 100644
index 4f75ac1fd9d2..000000000000
--- a/utils/TableGen/FastISelEmitter.h
+++ /dev/null
@@ -1,39 +0,0 @@
-//===- FastISelEmitter.h - Generate an instruction selector -----*- 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 emits a "fast" instruction selector.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef FASTISEL_EMITTER_H
-#define FASTISEL_EMITTER_H
-
-#include "CodeGenDAGPatterns.h"
-#include "llvm/TableGen/TableGenBackend.h"
-
-namespace llvm {
-
-class CodeGenTarget;
-
-/// FastISelEmitter - The top-level class which coordinates construction
-/// and emission of the instruction selector.
-///
-class FastISelEmitter : public TableGenBackend {
- RecordKeeper &Records;
- CodeGenDAGPatterns CGP;
-public:
- explicit FastISelEmitter(RecordKeeper &R);
-
- // run - Output the isel, returning true on failure.
- void run(raw_ostream &OS);
-};
-
-} // End llvm namespace
-
-#endif
diff --git a/utils/TableGen/FixedLenDecoderEmitter.cpp b/utils/TableGen/FixedLenDecoderEmitter.cpp
index 9b676f21a1d3..2cdde5500954 100644
--- a/utils/TableGen/FixedLenDecoderEmitter.cpp
+++ b/utils/TableGen/FixedLenDecoderEmitter.cpp
@@ -14,13 +14,14 @@
#define DEBUG_TYPE "decoder-emitter"
-#include "FixedLenDecoderEmitter.h"
#include "CodeGenTarget.h"
#include "llvm/TableGen/Record.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/DataTypes.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/TableGen/TableGenBackend.h"
#include <vector>
#include <map>
@@ -28,6 +29,67 @@
using namespace llvm;
+namespace {
+struct EncodingField {
+ unsigned Base, Width, Offset;
+ EncodingField(unsigned B, unsigned W, unsigned O)
+ : Base(B), Width(W), Offset(O) { }
+};
+} // End anonymous namespace
+
+namespace {
+struct OperandInfo {
+ std::vector<EncodingField> Fields;
+ std::string Decoder;
+
+ OperandInfo(std::string D)
+ : Decoder(D) { }
+
+ void addField(unsigned Base, unsigned Width, unsigned Offset) {
+ Fields.push_back(EncodingField(Base, Width, Offset));
+ }
+
+ unsigned numFields() const { return Fields.size(); }
+
+ typedef std::vector<EncodingField>::const_iterator const_iterator;
+
+ const_iterator begin() const { return Fields.begin(); }
+ const_iterator end() const { return Fields.end(); }
+};
+} // End anonymous namespace
+
+namespace {
+class FixedLenDecoderEmitter {
+public:
+
+ // Defaults preserved here for documentation, even though they aren't
+ // strictly necessary given the way that this is currently being called.
+ FixedLenDecoderEmitter(RecordKeeper &R,
+ std::string PredicateNamespace,
+ std::string GPrefix = "if (",
+ std::string GPostfix = " == MCDisassembler::Fail)"
+ " return MCDisassembler::Fail;",
+ std::string ROK = "MCDisassembler::Success",
+ std::string RFail = "MCDisassembler::Fail",
+ std::string L = "") :
+ Target(R),
+ PredicateNamespace(PredicateNamespace),
+ GuardPrefix(GPrefix), GuardPostfix(GPostfix),
+ ReturnOK(ROK), ReturnFail(RFail), Locals(L) {}
+
+ // run - Output the code emitter
+ void run(raw_ostream &o);
+
+private:
+ CodeGenTarget Target;
+public:
+ std::string PredicateNamespace;
+ std::string GuardPrefix, GuardPostfix;
+ std::string ReturnOK, ReturnFail;
+ std::string Locals;
+};
+} // End anonymous namespace
+
// The set (BIT_TRUE, BIT_FALSE, BIT_UNSET) represents a ternary logic system
// for a bit value.
//
@@ -83,7 +145,9 @@ static BitsInit &getBitsField(const Record &def, const char *str) {
}
// Forward declaration.
+namespace {
class FilterChooser;
+} // End anonymous namespace
// Representation of the instruction to work on.
typedef std::vector<bit_value_t> insn_t;
@@ -124,6 +188,7 @@ typedef std::vector<bit_value_t> insn_t;
/// decoder could try to decode the even/odd register numbering and assign to
/// VST4q8a or VST4q8b, but for the time being, the decoder chooses the "a"
/// version and return the Opcode since the two have the same Asm format string.
+namespace {
class Filter {
protected:
const FilterChooser *Owner;// points to the FilterChooser who owns this filter
@@ -180,6 +245,7 @@ public:
// the filter distinguishes more categories of instructions.
unsigned usefulness() const;
}; // End of class Filter
+} // End anonymous namespace
// These are states of our finite state machines used in FilterChooser's
// filterProcessor() which produces the filter candidates to use.
@@ -206,6 +272,7 @@ typedef enum {
/// It is useful to think of a Filter as governing the switch stmts of the
/// decoding tree. And each case is delegated to an inferior FilterChooser to
/// decide what further remaining bits to look at.
+namespace {
class FilterChooser {
protected:
friend class Filter;
@@ -385,6 +452,7 @@ protected:
// the instruction at this level or the instruction is not decodeable.
bool emit(raw_ostream &o, unsigned &Indentation) const;
};
+} // End anonymous namespace
///////////////////////////
// //
@@ -1573,3 +1641,18 @@ void FixedLenDecoderEmitter::run(raw_ostream &o) {
o << "\n} // End llvm namespace \n";
}
+
+namespace llvm {
+
+void EmitFixedLenDecoder(RecordKeeper &RK, raw_ostream &OS,
+ std::string PredicateNamespace,
+ std::string GPrefix,
+ std::string GPostfix,
+ std::string ROK,
+ std::string RFail,
+ std::string L) {
+ FixedLenDecoderEmitter(RK, PredicateNamespace, GPrefix, GPostfix,
+ ROK, RFail, L).run(OS);
+}
+
+} // End llvm namespace
diff --git a/utils/TableGen/FixedLenDecoderEmitter.h b/utils/TableGen/FixedLenDecoderEmitter.h
deleted file mode 100644
index 195297c966dd..000000000000
--- a/utils/TableGen/FixedLenDecoderEmitter.h
+++ /dev/null
@@ -1,79 +0,0 @@
-//===------------ FixedLenDecoderEmitter.h - Decoder Generator --*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// It contains the tablegen backend that emits the decoder functions for
-// targets with fixed length instruction set.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef FixedLenDECODEREMITTER_H
-#define FixedLenDECODEREMITTER_H
-
-#include "CodeGenTarget.h"
-
-#include "llvm/TableGen/TableGenBackend.h"
-#include "llvm/Support/DataTypes.h"
-
-namespace llvm {
-
-struct EncodingField {
- unsigned Base, Width, Offset;
- EncodingField(unsigned B, unsigned W, unsigned O)
- : Base(B), Width(W), Offset(O) { }
-};
-
-struct OperandInfo {
- std::vector<EncodingField> Fields;
- std::string Decoder;
-
- OperandInfo(std::string D)
- : Decoder(D) { }
-
- void addField(unsigned Base, unsigned Width, unsigned Offset) {
- Fields.push_back(EncodingField(Base, Width, Offset));
- }
-
- unsigned numFields() const { return Fields.size(); }
-
- typedef std::vector<EncodingField>::const_iterator const_iterator;
-
- const_iterator begin() const { return Fields.begin(); }
- const_iterator end() const { return Fields.end(); }
-};
-
-class FixedLenDecoderEmitter : public TableGenBackend {
-public:
- FixedLenDecoderEmitter(RecordKeeper &R,
- std::string PredicateNamespace,
- std::string GPrefix = "if (",
- std::string GPostfix = " == MCDisassembler::Fail)"
- " return MCDisassembler::Fail;",
- std::string ROK = "MCDisassembler::Success",
- std::string RFail = "MCDisassembler::Fail",
- std::string L = "") :
- Target(R),
- PredicateNamespace(PredicateNamespace),
- GuardPrefix(GPrefix), GuardPostfix(GPostfix),
- ReturnOK(ROK), ReturnFail(RFail), Locals(L) {}
-
- // run - Output the code emitter
- void run(raw_ostream &o);
-
-private:
- CodeGenTarget Target;
-public:
- std::string PredicateNamespace;
- std::string GuardPrefix, GuardPostfix;
- std::string ReturnOK, ReturnFail;
- std::string Locals;
-};
-
-} // end llvm namespace
-
-#endif
diff --git a/utils/TableGen/InstrInfoEmitter.cpp b/utils/TableGen/InstrInfoEmitter.cpp
index 8b3efd33f4dc..3adb8694d9ab 100644
--- a/utils/TableGen/InstrInfoEmitter.cpp
+++ b/utils/TableGen/InstrInfoEmitter.cpp
@@ -12,15 +12,49 @@
//
//===----------------------------------------------------------------------===//
-#include "InstrInfoEmitter.h"
+
+#include "CodeGenDAGPatterns.h"
+#include "CodeGenSchedule.h"
#include "CodeGenTarget.h"
#include "SequenceToOffsetTable.h"
-#include "llvm/TableGen/Record.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/TableGen/Record.h"
+#include "llvm/TableGen/TableGenBackend.h"
#include <algorithm>
#include <cstdio>
+#include <map>
+#include <vector>
using namespace llvm;
+namespace {
+class InstrInfoEmitter {
+ RecordKeeper &Records;
+ CodeGenDAGPatterns CDP;
+ const CodeGenSchedModels &SchedModels;
+
+public:
+ InstrInfoEmitter(RecordKeeper &R):
+ Records(R), CDP(R), SchedModels(CDP.getTargetInfo().getSchedModels()) {}
+
+ // run - Output the instruction set description.
+ void run(raw_ostream &OS);
+
+private:
+ void emitEnums(raw_ostream &OS);
+
+ typedef std::map<std::vector<std::string>, unsigned> OperandInfoMapTy;
+ void emitRecord(const CodeGenInstruction &Inst, unsigned Num,
+ Record *InstrInfo,
+ std::map<std::vector<Record*>, unsigned> &EL,
+ const OperandInfoMapTy &OpInfo,
+ raw_ostream &OS);
+
+ // Operand information.
+ void EmitOperandInfo(raw_ostream &OS, OperandInfoMapTy &OperandInfoIDs);
+ std::vector<std::string> GetOperandInfo(const CodeGenInstruction &Inst);
+};
+} // End anonymous namespace
+
static void PrintDefList(const std::vector<Record*> &Uses,
unsigned Num, raw_ostream &OS) {
OS << "static const uint16_t ImplicitList" << Num << "[] = { ";
@@ -30,23 +64,6 @@ static void PrintDefList(const std::vector<Record*> &Uses,
}
//===----------------------------------------------------------------------===//
-// Instruction Itinerary Information.
-//===----------------------------------------------------------------------===//
-
-void InstrInfoEmitter::GatherItinClasses() {
- std::vector<Record*> DefList =
- Records.getAllDerivedDefinitions("InstrItinClass");
- std::sort(DefList.begin(), DefList.end(), LessRecord());
-
- for (unsigned i = 0, N = DefList.size(); i < N; i++)
- ItinClassMap[DefList[i]->getName()] = i;
-}
-
-unsigned InstrInfoEmitter::getItinClassNumber(const Record *InstRec) {
- return ItinClassMap[InstRec->getValueAsDef("Itinerary")->getName()];
-}
-
-//===----------------------------------------------------------------------===//
// Operand Info Emission.
//===----------------------------------------------------------------------===//
@@ -163,11 +180,10 @@ void InstrInfoEmitter::EmitOperandInfo(raw_ostream &OS,
// run - Emit the main instruction description records for the target...
void InstrInfoEmitter::run(raw_ostream &OS) {
+ emitSourceFileHeader("Target Instruction Enum Values", OS);
emitEnums(OS);
- GatherItinClasses();
-
- EmitSourceFileHeader("Target Instruction Descriptors", OS);
+ emitSourceFileHeader("Target Instruction Descriptors", OS);
OS << "\n#ifdef GET_INSTRINFO_MC_DESC\n";
OS << "#undef GET_INSTRINFO_MC_DESC\n";
@@ -288,10 +304,11 @@ void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num,
MinOperands = Inst.Operands.back().MIOperandNo +
Inst.Operands.back().MINumOperands;
+ Record *ItinDef = Inst.TheDef->getValueAsDef("Itinerary");
OS << " { ";
OS << Num << ",\t" << MinOperands << ",\t"
<< Inst.Operands.NumDefs << ",\t"
- << getItinClassNumber(Inst.TheDef) << ",\t"
+ << SchedModels.getItinClassIdx(ItinDef) << ",\t"
<< Inst.TheDef->getValueAsInt("Size") << ",\t0";
// Emit all of the target indepedent flags...
@@ -362,7 +379,6 @@ void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num,
// emitEnums - Print out enum values for all of the instructions.
void InstrInfoEmitter::emitEnums(raw_ostream &OS) {
- EmitSourceFileHeader("Target Instruction Enum Values", OS);
OS << "\n#ifdef GET_INSTRINFO_ENUM\n";
OS << "#undef GET_INSTRINFO_ENUM\n";
@@ -394,3 +410,11 @@ void InstrInfoEmitter::emitEnums(raw_ostream &OS) {
OS << "#endif // GET_INSTRINFO_ENUM\n\n";
}
+
+namespace llvm {
+
+void EmitInstrInfo(RecordKeeper &RK, raw_ostream &OS) {
+ InstrInfoEmitter(RK).run(OS);
+}
+
+} // End llvm namespace
diff --git a/utils/TableGen/InstrInfoEmitter.h b/utils/TableGen/InstrInfoEmitter.h
deleted file mode 100644
index f8d3ea51c814..000000000000
--- a/utils/TableGen/InstrInfoEmitter.h
+++ /dev/null
@@ -1,62 +0,0 @@
-//===- InstrInfoEmitter.h - Generate a Instruction Set Desc. ----*- 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 the target
-// instruction set for the code generator.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef INSTRINFO_EMITTER_H
-#define INSTRINFO_EMITTER_H
-
-#include "CodeGenDAGPatterns.h"
-#include "llvm/TableGen/TableGenBackend.h"
-#include <vector>
-#include <map>
-
-namespace llvm {
-
-class StringInit;
-class IntInit;
-class ListInit;
-class CodeGenInstruction;
-
-class InstrInfoEmitter : public TableGenBackend {
- RecordKeeper &Records;
- CodeGenDAGPatterns CDP;
- std::map<std::string, unsigned> ItinClassMap;
-
-public:
- InstrInfoEmitter(RecordKeeper &R) : Records(R), CDP(R) { }
-
- // run - Output the instruction set description.
- void run(raw_ostream &OS);
-
-private:
- void emitEnums(raw_ostream &OS);
-
- typedef std::map<std::vector<std::string>, unsigned> OperandInfoMapTy;
- void emitRecord(const CodeGenInstruction &Inst, unsigned Num,
- Record *InstrInfo,
- std::map<std::vector<Record*>, unsigned> &EL,
- const OperandInfoMapTy &OpInfo,
- raw_ostream &OS);
-
- // Itinerary information.
- void GatherItinClasses();
- unsigned getItinClassNumber(const Record *InstRec);
-
- // Operand information.
- void EmitOperandInfo(raw_ostream &OS, OperandInfoMapTy &OperandInfoIDs);
- std::vector<std::string> GetOperandInfo(const CodeGenInstruction &Inst);
-};
-
-} // End llvm namespace
-
-#endif
diff --git a/utils/TableGen/IntrinsicEmitter.cpp b/utils/TableGen/IntrinsicEmitter.cpp
index 8e1bae8c1f0f..155d1abea331 100644
--- a/utils/TableGen/IntrinsicEmitter.cpp
+++ b/utils/TableGen/IntrinsicEmitter.cpp
@@ -11,23 +11,62 @@
//
//===----------------------------------------------------------------------===//
+#include "CodeGenIntrinsics.h"
#include "CodeGenTarget.h"
-#include "IntrinsicEmitter.h"
-#include "StringMatcher.h"
-#include "llvm/TableGen/Record.h"
+#include "SequenceToOffsetTable.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/TableGen/Record.h"
+#include "llvm/TableGen/StringMatcher.h"
+#include "llvm/TableGen/TableGenBackend.h"
#include <algorithm>
using namespace llvm;
+namespace {
+class IntrinsicEmitter {
+ RecordKeeper &Records;
+ bool TargetOnly;
+ std::string TargetPrefix;
+
+public:
+ IntrinsicEmitter(RecordKeeper &R, bool T)
+ : Records(R), TargetOnly(T) {}
+
+ void run(raw_ostream &OS);
+
+ void EmitPrefix(raw_ostream &OS);
+
+ void EmitEnumInfo(const std::vector<CodeGenIntrinsic> &Ints,
+ raw_ostream &OS);
+
+ void EmitFnNameRecognizer(const std::vector<CodeGenIntrinsic> &Ints,
+ raw_ostream &OS);
+ void EmitIntrinsicToNameTable(const std::vector<CodeGenIntrinsic> &Ints,
+ raw_ostream &OS);
+ void EmitIntrinsicToOverloadTable(const std::vector<CodeGenIntrinsic> &Ints,
+ raw_ostream &OS);
+ void EmitVerifier(const std::vector<CodeGenIntrinsic> &Ints,
+ raw_ostream &OS);
+ void EmitGenerator(const std::vector<CodeGenIntrinsic> &Ints,
+ raw_ostream &OS);
+ void EmitAttributes(const std::vector<CodeGenIntrinsic> &Ints,
+ raw_ostream &OS);
+ void EmitModRefBehavior(const std::vector<CodeGenIntrinsic> &Ints,
+ raw_ostream &OS);
+ void EmitIntrinsicToGCCBuiltinMap(const std::vector<CodeGenIntrinsic> &Ints,
+ raw_ostream &OS);
+ void EmitSuffix(raw_ostream &OS);
+};
+} // End anonymous namespace
+
//===----------------------------------------------------------------------===//
// IntrinsicEmitter Implementation
//===----------------------------------------------------------------------===//
void IntrinsicEmitter::run(raw_ostream &OS) {
- EmitSourceFileHeader("Intrinsic Function Source Fragment", OS);
-
+ emitSourceFileHeader("Intrinsic Function Source Fragment", OS);
+
std::vector<CodeGenIntrinsic> Ints = LoadIntrinsics(Records, TargetOnly);
-
+
if (TargetOnly && !Ints.empty())
TargetPrefix = Ints[0].TargetPrefix;
@@ -45,9 +84,6 @@ void IntrinsicEmitter::run(raw_ostream &OS) {
// Emit the function name recognizer.
EmitFnNameRecognizer(Ints, OS);
- // Emit the intrinsic verifier.
- EmitVerifier(Ints, OS);
-
// Emit the intrinsic declaration generator.
EmitGenerator(Ints, OS);
@@ -174,337 +210,299 @@ EmitIntrinsicToOverloadTable(const std::vector<CodeGenIntrinsic> &Ints,
OS << "#endif\n\n";
}
-static void EmitTypeForValueType(raw_ostream &OS, MVT::SimpleValueType VT) {
+
+// NOTE: This must be kept in synch with the copy in lib/VMCore/Function.cpp!
+enum IIT_Info {
+ // Common values should be encoded with 0-15.
+ IIT_Done = 0,
+ IIT_I1 = 1,
+ IIT_I8 = 2,
+ 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_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
+};
+
+
+static void EncodeFixedValueType(MVT::SimpleValueType VT,
+ std::vector<unsigned char> &Sig) {
if (EVT(VT).isInteger()) {
unsigned BitWidth = EVT(VT).getSizeInBits();
- OS << "IntegerType::get(Context, " << BitWidth << ")";
- } else if (VT == MVT::Other) {
- // MVT::OtherVT is used to mean the empty struct type here.
- OS << "StructType::get(Context)";
- } else if (VT == MVT::f16) {
- OS << "Type::getHalfTy(Context)";
- } else if (VT == MVT::f32) {
- OS << "Type::getFloatTy(Context)";
- } else if (VT == MVT::f64) {
- OS << "Type::getDoubleTy(Context)";
- } else if (VT == MVT::f80) {
- OS << "Type::getX86_FP80Ty(Context)";
- } else if (VT == MVT::f128) {
- OS << "Type::getFP128Ty(Context)";
- } else if (VT == MVT::ppcf128) {
- OS << "Type::getPPC_FP128Ty(Context)";
- } else if (VT == MVT::isVoid) {
- OS << "Type::getVoidTy(Context)";
- } else if (VT == MVT::Metadata) {
- OS << "Type::getMetadataTy(Context)";
- } else if (VT == MVT::x86mmx) {
- OS << "Type::getX86_MMXTy(Context)";
- } else {
- assert(false && "Unsupported ValueType!");
+ switch (BitWidth) {
+ default: throw "unhandled integer type width in intrinsic!";
+ case 1: return Sig.push_back(IIT_I1);
+ case 8: return Sig.push_back(IIT_I8);
+ case 16: return Sig.push_back(IIT_I16);
+ case 32: return Sig.push_back(IIT_I32);
+ case 64: return Sig.push_back(IIT_I64);
+ }
}
-}
-
-static void EmitTypeGenerate(raw_ostream &OS, const Record *ArgType,
- unsigned &ArgNo);
-
-static void EmitTypeGenerate(raw_ostream &OS,
- const std::vector<Record*> &ArgTypes,
- unsigned &ArgNo) {
- if (ArgTypes.empty())
- return EmitTypeForValueType(OS, MVT::isVoid);
- if (ArgTypes.size() == 1)
- return EmitTypeGenerate(OS, ArgTypes.front(), ArgNo);
-
- OS << "StructType::get(";
-
- for (std::vector<Record*>::const_iterator
- I = ArgTypes.begin(), E = ArgTypes.end(); I != E; ++I) {
- EmitTypeGenerate(OS, *I, ArgNo);
- OS << ", ";
+ switch (VT) {
+ default: throw "unhandled MVT in intrinsic!";
+ 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);
+ case MVT::x86mmx: return Sig.push_back(IIT_MMX);
+ // MVT::OtherVT is used to mean the empty struct type here.
+ case MVT::Other: return Sig.push_back(IIT_EMPTYSTRUCT);
}
-
- OS << " NULL)";
}
-static void EmitTypeGenerate(raw_ostream &OS, const Record *ArgType,
- unsigned &ArgNo) {
- MVT::SimpleValueType VT = getValueType(ArgType->getValueAsDef("VT"));
-
- if (ArgType->isSubClassOf("LLVMMatchType")) {
- unsigned Number = ArgType->getValueAsInt("Number");
- assert(Number < ArgNo && "Invalid matching number!");
- if (ArgType->isSubClassOf("LLVMExtendedElementVectorType"))
- OS << "VectorType::getExtendedElementVectorType"
- << "(dyn_cast<VectorType>(Tys[" << Number << "]))";
- else if (ArgType->isSubClassOf("LLVMTruncatedElementVectorType"))
- OS << "VectorType::getTruncatedElementVectorType"
- << "(dyn_cast<VectorType>(Tys[" << Number << "]))";
+#ifdef _MSC_VER
+#pragma optimize("",off) // MSVC 2010 optimizer can't deal with this function.
+#endif
+
+static void EncodeFixedType(Record *R, std::vector<unsigned char> &ArgCodes,
+ std::vector<unsigned char> &Sig) {
+
+ if (R->isSubClassOf("LLVMMatchType")) {
+ unsigned Number = R->getValueAsInt("Number");
+ assert(Number < ArgCodes.size() && "Invalid matching number!");
+ if (R->isSubClassOf("LLVMExtendedElementVectorType"))
+ Sig.push_back(IIT_EXTEND_VEC_ARG);
+ else if (R->isSubClassOf("LLVMTruncatedElementVectorType"))
+ Sig.push_back(IIT_TRUNC_VEC_ARG);
else
- OS << "Tys[" << Number << "]";
- } else if (VT == MVT::iAny || VT == MVT::fAny || VT == MVT::vAny) {
- // NOTE: The ArgNo variable here is not the absolute argument number, it is
- // the index of the "arbitrary" type in the Tys array passed to the
- // Intrinsic::getDeclaration function. Consequently, we only want to
- // increment it when we actually hit an overloaded type. Getting this wrong
- // leads to very subtle bugs!
- OS << "Tys[" << ArgNo++ << "]";
- } else if (EVT(VT).isVector()) {
+ Sig.push_back(IIT_ARG);
+ return Sig.push_back((Number << 2) | ArgCodes[Number]);
+ }
+
+ MVT::SimpleValueType VT = getValueType(R->getValueAsDef("VT"));
+
+ unsigned Tmp = 0;
+ switch (VT) {
+ default: break;
+ case MVT::iPTRAny: ++Tmp; // FALL THROUGH.
+ case MVT::vAny: ++Tmp; // FALL THROUGH.
+ case MVT::fAny: ++Tmp; // FALL THROUGH.
+ case MVT::iAny: {
+ // If this is an "any" valuetype, then the type is the type of the next
+ // type in the list specified to getIntrinsic().
+ Sig.push_back(IIT_ARG);
+
+ // Figure out what arg # this is consuming, and remember what kind it was.
+ unsigned ArgNo = ArgCodes.size();
+ ArgCodes.push_back(Tmp);
+
+ // Encode what sort of argument it must be in the low 2 bits of the ArgNo.
+ return Sig.push_back((ArgNo << 2) | Tmp);
+ }
+
+ case MVT::iPTR: {
+ unsigned AddrSpace = 0;
+ if (R->isSubClassOf("LLVMQualPointerType")) {
+ AddrSpace = R->getValueAsInt("AddrSpace");
+ assert(AddrSpace < 256 && "Address space exceeds 255");
+ }
+ if (AddrSpace) {
+ Sig.push_back(IIT_ANYPTR);
+ Sig.push_back(AddrSpace);
+ } else {
+ Sig.push_back(IIT_PTR);
+ }
+ return EncodeFixedType(R->getValueAsDef("ElTy"), ArgCodes, Sig);
+ }
+ }
+
+ if (EVT(VT).isVector()) {
EVT VVT = VT;
- OS << "VectorType::get(";
- EmitTypeForValueType(OS, VVT.getVectorElementType().getSimpleVT().SimpleTy);
- OS << ", " << VVT.getVectorNumElements() << ")";
- } else if (VT == MVT::iPTR) {
- OS << "PointerType::getUnqual(";
- EmitTypeGenerate(OS, ArgType->getValueAsDef("ElTy"), ArgNo);
- OS << ")";
- } else if (VT == MVT::iPTRAny) {
- // Make sure the user has passed us an argument type to overload. If not,
- // treat it as an ordinary (not overloaded) intrinsic.
- OS << "(" << ArgNo << " < Tys.size()) ? Tys[" << ArgNo
- << "] : PointerType::getUnqual(";
- EmitTypeGenerate(OS, ArgType->getValueAsDef("ElTy"), ArgNo);
- OS << ")";
- ++ArgNo;
- } else if (VT == MVT::isVoid) {
- if (ArgNo == 0)
- OS << "Type::getVoidTy(Context)";
- else
- // MVT::isVoid is used to mean varargs here.
- OS << "...";
- } else {
- EmitTypeForValueType(OS, VT);
+ switch (VVT.getVectorNumElements()) {
+ default: throw "unhandled vector type width in intrinsic!";
+ case 2: Sig.push_back(IIT_V2); break;
+ case 4: Sig.push_back(IIT_V4); break;
+ case 8: Sig.push_back(IIT_V8); break;
+ case 16: Sig.push_back(IIT_V16); break;
+ case 32: Sig.push_back(IIT_V32); break;
+ }
+
+ return EncodeFixedValueType(VVT.getVectorElementType().
+ getSimpleVT().SimpleTy, Sig);
}
-}
-
-/// RecordListComparator - Provide a deterministic comparator for lists of
-/// records.
-namespace {
- typedef std::pair<std::vector<Record*>, std::vector<Record*> > RecPair;
- struct RecordListComparator {
- bool operator()(const RecPair &LHS,
- const RecPair &RHS) const {
- unsigned i = 0;
- const std::vector<Record*> *LHSVec = &LHS.first;
- const std::vector<Record*> *RHSVec = &RHS.first;
- unsigned RHSSize = RHSVec->size();
- unsigned LHSSize = LHSVec->size();
-
- for (; i != LHSSize; ++i) {
- if (i == RHSSize) return false; // RHS is shorter than LHS.
- if ((*LHSVec)[i] != (*RHSVec)[i])
- return (*LHSVec)[i]->getName() < (*RHSVec)[i]->getName();
- }
- if (i != RHSSize) return true;
+ EncodeFixedValueType(VT, Sig);
+}
- i = 0;
- LHSVec = &LHS.second;
- RHSVec = &RHS.second;
- RHSSize = RHSVec->size();
- LHSSize = LHSVec->size();
+#ifdef _MSC_VER
+#pragma optimize("",on)
+#endif
- for (i = 0; i != LHSSize; ++i) {
- if (i == RHSSize) return false; // RHS is shorter than LHS.
- if ((*LHSVec)[i] != (*RHSVec)[i])
- return (*LHSVec)[i]->getName() < (*RHSVec)[i]->getName();
- }
-
- return i != RHSSize;
+/// ComputeFixedEncoding - If we can encode the type signature for this
+/// intrinsic into 32 bits, return it. If not, return ~0U.
+static void ComputeFixedEncoding(const CodeGenIntrinsic &Int,
+ std::vector<unsigned char> &TypeSig) {
+ std::vector<unsigned char> ArgCodes;
+
+ if (Int.IS.RetVTs.empty())
+ TypeSig.push_back(IIT_Done);
+ else if (Int.IS.RetVTs.size() == 1 &&
+ Int.IS.RetVTs[0] == MVT::isVoid)
+ TypeSig.push_back(IIT_Done);
+ else {
+ switch (Int.IS.RetVTs.size()) {
+ case 1: break;
+ case 2: TypeSig.push_back(IIT_STRUCT2); break;
+ case 3: TypeSig.push_back(IIT_STRUCT3); break;
+ case 4: TypeSig.push_back(IIT_STRUCT4); break;
+ case 5: TypeSig.push_back(IIT_STRUCT5); break;
+ default: assert(0 && "Unhandled case in struct");
}
- };
+
+ for (unsigned i = 0, e = Int.IS.RetVTs.size(); i != e; ++i)
+ EncodeFixedType(Int.IS.RetTypeDefs[i], ArgCodes, TypeSig);
+ }
+
+ for (unsigned i = 0, e = Int.IS.ParamTypeDefs.size(); i != e; ++i)
+ EncodeFixedType(Int.IS.ParamTypeDefs[i], ArgCodes, TypeSig);
}
-void IntrinsicEmitter::EmitVerifier(const std::vector<CodeGenIntrinsic> &Ints,
- raw_ostream &OS) {
- OS << "// Verifier::visitIntrinsicFunctionCall code.\n";
- OS << "#ifdef GET_INTRINSIC_VERIFIER\n";
- OS << " switch (ID) {\n";
- OS << " default: llvm_unreachable(\"Invalid intrinsic!\");\n";
+static void printIITEntry(raw_ostream &OS, unsigned char X) {
+ OS << (unsigned)X;
+}
+
+void IntrinsicEmitter::EmitGenerator(const std::vector<CodeGenIntrinsic> &Ints,
+ raw_ostream &OS) {
+ // If we can compute a 32-bit fixed encoding for this intrinsic, do so and
+ // capture it in this vector, otherwise store a ~0U.
+ std::vector<unsigned> FixedEncodings;
+
+ SequenceToOffsetTable<std::vector<unsigned char> > LongEncodingTable;
- // This checking can emit a lot of very common code. To reduce the amount of
- // code that we emit, batch up cases that have identical types. This avoids
- // problems where GCC can run out of memory compiling Verifier.cpp.
- typedef std::map<RecPair, std::vector<unsigned>, RecordListComparator> MapTy;
- MapTy UniqueArgInfos;
+ std::vector<unsigned char> TypeSig;
// Compute the unique argument type info.
- for (unsigned i = 0, e = Ints.size(); i != e; ++i)
- UniqueArgInfos[make_pair(Ints[i].IS.RetTypeDefs,
- Ints[i].IS.ParamTypeDefs)].push_back(i);
-
- // Loop through the array, emitting one comparison for each batch.
- for (MapTy::iterator I = UniqueArgInfos.begin(),
- E = UniqueArgInfos.end(); I != E; ++I) {
- for (unsigned i = 0, e = I->second.size(); i != e; ++i)
- OS << " case Intrinsic::" << Ints[I->second[i]].EnumName << ":\t\t// "
- << Ints[I->second[i]].Name << "\n";
-
- const RecPair &ArgTypes = I->first;
- const std::vector<Record*> &RetTys = ArgTypes.first;
- const std::vector<Record*> &ParamTys = ArgTypes.second;
- std::vector<unsigned> OverloadedTypeIndices;
-
- OS << " VerifyIntrinsicPrototype(ID, IF, " << RetTys.size() << ", "
- << ParamTys.size();
-
- // Emit return types.
- for (unsigned j = 0, je = RetTys.size(); j != je; ++j) {
- Record *ArgType = RetTys[j];
- OS << ", ";
-
- if (ArgType->isSubClassOf("LLVMMatchType")) {
- unsigned Number = ArgType->getValueAsInt("Number");
- assert(Number < OverloadedTypeIndices.size() &&
- "Invalid matching number!");
- Number = OverloadedTypeIndices[Number];
- if (ArgType->isSubClassOf("LLVMExtendedElementVectorType"))
- OS << "~(ExtendedElementVectorType | " << Number << ")";
- else if (ArgType->isSubClassOf("LLVMTruncatedElementVectorType"))
- OS << "~(TruncatedElementVectorType | " << Number << ")";
- else
- OS << "~" << Number;
- } else {
- MVT::SimpleValueType VT = getValueType(ArgType->getValueAsDef("VT"));
- OS << getEnumName(VT);
-
- if (EVT(VT).isOverloaded())
- OverloadedTypeIndices.push_back(j);
-
- if (VT == MVT::isVoid && j != 0 && j != je - 1)
- throw "Var arg type not last argument";
+ for (unsigned i = 0, e = Ints.size(); i != e; ++i) {
+ // Get the signature for the intrinsic.
+ TypeSig.clear();
+ ComputeFixedEncoding(Ints[i], TypeSig);
+
+ // Check to see if we can encode it into a 32-bit word. We can only encode
+ // 8 nibbles into a 32-bit word.
+ if (TypeSig.size() <= 8) {
+ bool Failed = false;
+ unsigned Result = 0;
+ for (unsigned i = 0, e = TypeSig.size(); i != e; ++i) {
+ // If we had an unencodable argument, bail out.
+ if (TypeSig[i] > 15) {
+ Failed = true;
+ break;
+ }
+ Result = (Result << 4) | TypeSig[e-i-1];
}
- }
-
- // Emit the parameter types.
- for (unsigned j = 0, je = ParamTys.size(); j != je; ++j) {
- Record *ArgType = ParamTys[j];
- OS << ", ";
-
- if (ArgType->isSubClassOf("LLVMMatchType")) {
- unsigned Number = ArgType->getValueAsInt("Number");
- assert(Number < OverloadedTypeIndices.size() &&
- "Invalid matching number!");
- Number = OverloadedTypeIndices[Number];
- if (ArgType->isSubClassOf("LLVMExtendedElementVectorType"))
- OS << "~(ExtendedElementVectorType | " << Number << ")";
- else if (ArgType->isSubClassOf("LLVMTruncatedElementVectorType"))
- OS << "~(TruncatedElementVectorType | " << Number << ")";
- else
- OS << "~" << Number;
- } else {
- MVT::SimpleValueType VT = getValueType(ArgType->getValueAsDef("VT"));
- OS << getEnumName(VT);
-
- if (EVT(VT).isOverloaded())
- OverloadedTypeIndices.push_back(j + RetTys.size());
-
- if (VT == MVT::isVoid && j != 0 && j != je - 1)
- throw "Var arg type not last argument";
+
+ // If this could be encoded into a 31-bit word, return it.
+ if (!Failed && (Result >> 31) == 0) {
+ FixedEncodings.push_back(Result);
+ continue;
}
}
+
+ // Otherwise, we're going to unique the sequence into the
+ // LongEncodingTable, and use its offset in the 32-bit table instead.
+ LongEncodingTable.add(TypeSig);
- OS << ");\n";
- OS << " break;\n";
+ // This is a placehold that we'll replace after the table is laid out.
+ FixedEncodings.push_back(~0U);
}
- OS << " }\n";
- OS << "#endif\n\n";
-}
-
-void IntrinsicEmitter::EmitGenerator(const std::vector<CodeGenIntrinsic> &Ints,
- raw_ostream &OS) {
- OS << "// Code for generating Intrinsic function declarations.\n";
- OS << "#ifdef GET_INTRINSIC_GENERATOR\n";
- OS << " switch (id) {\n";
- OS << " default: llvm_unreachable(\"Invalid intrinsic!\");\n";
- // Similar to GET_INTRINSIC_VERIFIER, batch up cases that have identical
- // types.
- typedef std::map<RecPair, std::vector<unsigned>, RecordListComparator> MapTy;
- MapTy UniqueArgInfos;
+ LongEncodingTable.layout();
- // Compute the unique argument type info.
- for (unsigned i = 0, e = Ints.size(); i != e; ++i)
- UniqueArgInfos[make_pair(Ints[i].IS.RetTypeDefs,
- Ints[i].IS.ParamTypeDefs)].push_back(i);
+ OS << "// Global intrinsic function declaration type table.\n";
+ OS << "#ifdef GET_INTRINSIC_GENERATOR_GLOBAL\n";
- // Loop through the array, emitting one generator for each batch.
- std::string IntrinsicStr = TargetPrefix + "Intrinsic::";
+ OS << "static const unsigned IIT_Table[] = {\n ";
- for (MapTy::iterator I = UniqueArgInfos.begin(),
- E = UniqueArgInfos.end(); I != E; ++I) {
- for (unsigned i = 0, e = I->second.size(); i != e; ++i)
- OS << " case " << IntrinsicStr << Ints[I->second[i]].EnumName
- << ":\t\t// " << Ints[I->second[i]].Name << "\n";
+ for (unsigned i = 0, e = FixedEncodings.size(); i != e; ++i) {
+ if ((i & 7) == 7)
+ OS << "\n ";
- const RecPair &ArgTypes = I->first;
- const std::vector<Record*> &RetTys = ArgTypes.first;
- const std::vector<Record*> &ParamTys = ArgTypes.second;
-
- unsigned N = ParamTys.size();
-
- if (N > 1 &&
- getValueType(ParamTys[N - 1]->getValueAsDef("VT")) == MVT::isVoid) {
- OS << " IsVarArg = true;\n";
- --N;
+ // If the entry fit in the table, just emit it.
+ if (FixedEncodings[i] != ~0U) {
+ OS << "0x" << utohexstr(FixedEncodings[i]) << ", ";
+ continue;
}
-
- unsigned ArgNo = 0;
- OS << " ResultTy = ";
- EmitTypeGenerate(OS, RetTys, ArgNo);
- OS << ";\n";
- for (unsigned j = 0; j != N; ++j) {
- OS << " ArgTys.push_back(";
- EmitTypeGenerate(OS, ParamTys[j], ArgNo);
- OS << ");\n";
- }
+ TypeSig.clear();
+ ComputeFixedEncoding(Ints[i], TypeSig);
- OS << " break;\n";
+
+ // Otherwise, emit the offset into the long encoding table. We emit it this
+ // way so that it is easier to read the offset in the .def file.
+ OS << "(1U<<31) | " << LongEncodingTable.get(TypeSig) << ", ";
}
+
+ OS << "0\n};\n\n";
+
+ // Emit the shared table of register lists.
+ OS << "static const unsigned char IIT_LongEncodingTable[] = {\n";
+ if (!LongEncodingTable.empty())
+ LongEncodingTable.emit(OS, printIITEntry);
+ OS << " 255\n};\n\n";
+
+ OS << "#endif\n\n"; // End of GET_INTRINSIC_GENERATOR_GLOBAL
+}
- OS << " }\n";
- OS << "#endif\n\n";
+enum ModRefKind {
+ MRK_none,
+ MRK_readonly,
+ MRK_readnone
+};
+
+static ModRefKind getModRefKind(const CodeGenIntrinsic &intrinsic) {
+ switch (intrinsic.ModRef) {
+ case CodeGenIntrinsic::NoMem:
+ return MRK_readnone;
+ case CodeGenIntrinsic::ReadArgMem:
+ case CodeGenIntrinsic::ReadMem:
+ return MRK_readonly;
+ case CodeGenIntrinsic::ReadWriteArgMem:
+ case CodeGenIntrinsic::ReadWriteMem:
+ return MRK_none;
+ }
+ llvm_unreachable("bad mod-ref kind");
}
namespace {
- enum ModRefKind {
- MRK_none,
- MRK_readonly,
- MRK_readnone
- };
-
- ModRefKind getModRefKind(const CodeGenIntrinsic &intrinsic) {
- switch (intrinsic.ModRef) {
- case CodeGenIntrinsic::NoMem:
- return MRK_readnone;
- case CodeGenIntrinsic::ReadArgMem:
- case CodeGenIntrinsic::ReadMem:
- return MRK_readonly;
- case CodeGenIntrinsic::ReadWriteArgMem:
- case CodeGenIntrinsic::ReadWriteMem:
- return MRK_none;
- }
- llvm_unreachable("bad mod-ref kind");
+struct AttributeComparator {
+ bool operator()(const CodeGenIntrinsic *L, const CodeGenIntrinsic *R) const {
+ // Sort throwing intrinsics after non-throwing intrinsics.
+ if (L->canThrow != R->canThrow)
+ return R->canThrow;
+
+ if (L->isNoReturn != R->isNoReturn)
+ return R->isNoReturn;
+
+ // Try to order by readonly/readnone attribute.
+ ModRefKind LK = getModRefKind(*L);
+ ModRefKind RK = getModRefKind(*R);
+ if (LK != RK) return (LK > RK);
+
+ // Order by argument attributes.
+ // This is reliable because each side is already sorted internally.
+ return (L->ArgumentAttributes < R->ArgumentAttributes);
}
-
- struct AttributeComparator {
- bool operator()(const CodeGenIntrinsic *L, const CodeGenIntrinsic *R) const {
- // Sort throwing intrinsics after non-throwing intrinsics.
- if (L->canThrow != R->canThrow)
- return R->canThrow;
-
- // Try to order by readonly/readnone attribute.
- ModRefKind LK = getModRefKind(*L);
- ModRefKind RK = getModRefKind(*R);
- if (LK != RK) return (LK > RK);
-
- // Order by argument attributes.
- // This is reliable because each side is already sorted internally.
- return (L->ArgumentAttributes < R->ArgumentAttributes);
- }
- };
-}
+};
+} // End anonymous namespace
/// EmitAttributes - This emits the Intrinsic::getAttributes method.
void IntrinsicEmitter::
@@ -592,16 +590,30 @@ EmitAttributes(const std::vector<CodeGenIntrinsic> &Ints, raw_ostream &OS) {
ModRefKind modRef = getModRefKind(intrinsic);
- if (!intrinsic.canThrow || modRef) {
+ if (!intrinsic.canThrow || modRef || intrinsic.isNoReturn) {
OS << " AWI[" << numAttrs++ << "] = AttributeWithIndex::get(~0, ";
+ bool Emitted = false;
if (!intrinsic.canThrow) {
OS << "Attribute::NoUnwind";
- if (modRef) OS << '|';
+ Emitted = true;
+ }
+
+ if (intrinsic.isNoReturn) {
+ if (Emitted) OS << '|';
+ OS << "Attribute::NoReturn";
+ Emitted = true;
}
+
switch (modRef) {
case MRK_none: break;
- case MRK_readonly: OS << "Attribute::ReadOnly"; break;
- case MRK_readnone: OS << "Attribute::ReadNone"; break;
+ case MRK_readonly:
+ if (Emitted) OS << '|';
+ OS << "Attribute::ReadOnly";
+ break;
+ case MRK_readnone:
+ if (Emitted) OS << '|';
+ OS << "Attribute::ReadNone";
+ break;
}
OS << ");\n";
}
@@ -616,7 +628,8 @@ EmitAttributes(const std::vector<CodeGenIntrinsic> &Ints, raw_ostream &OS) {
OS << " }\n";
OS << " }\n";
- OS << " return AttrListPtr::get(AWI, NumAttrs);\n";
+ OS << " return AttrListPtr::get(ArrayRef<AttributeWithIndex>(AWI, "
+ "NumAttrs));\n";
OS << "}\n";
OS << "#endif // GET_INTRINSIC_ATTRIBUTES\n\n";
}
@@ -730,3 +743,11 @@ EmitIntrinsicToGCCBuiltinMap(const std::vector<CodeGenIntrinsic> &Ints,
OS << "}\n";
OS << "#endif\n\n";
}
+
+namespace llvm {
+
+void EmitIntrinsics(RecordKeeper &RK, raw_ostream &OS, bool TargetOnly = false) {
+ IntrinsicEmitter(RK, TargetOnly).run(OS);
+}
+
+} // End llvm namespace
diff --git a/utils/TableGen/IntrinsicEmitter.h b/utils/TableGen/IntrinsicEmitter.h
deleted file mode 100644
index f9bcd5980226..000000000000
--- a/utils/TableGen/IntrinsicEmitter.h
+++ /dev/null
@@ -1,61 +0,0 @@
-//===- IntrinsicEmitter.h - Generate intrinsic information ------*- 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 emits information about intrinsic functions.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef INTRINSIC_EMITTER_H
-#define INTRINSIC_EMITTER_H
-
-#include "CodeGenIntrinsics.h"
-#include "llvm/TableGen/TableGenBackend.h"
-
-namespace llvm {
- class IntrinsicEmitter : public TableGenBackend {
- RecordKeeper &Records;
- bool TargetOnly;
- std::string TargetPrefix;
-
- public:
- IntrinsicEmitter(RecordKeeper &R, bool T = false)
- : Records(R), TargetOnly(T) {}
-
- void run(raw_ostream &OS);
-
- void EmitPrefix(raw_ostream &OS);
-
- void EmitEnumInfo(const std::vector<CodeGenIntrinsic> &Ints,
- raw_ostream &OS);
-
- void EmitFnNameRecognizer(const std::vector<CodeGenIntrinsic> &Ints,
- raw_ostream &OS);
- void EmitIntrinsicToNameTable(const std::vector<CodeGenIntrinsic> &Ints,
- raw_ostream &OS);
- void EmitIntrinsicToOverloadTable(const std::vector<CodeGenIntrinsic> &Ints,
- raw_ostream &OS);
- void EmitVerifier(const std::vector<CodeGenIntrinsic> &Ints,
- raw_ostream &OS);
- void EmitGenerator(const std::vector<CodeGenIntrinsic> &Ints,
- raw_ostream &OS);
- void EmitAttributes(const std::vector<CodeGenIntrinsic> &Ints,
- raw_ostream &OS);
- void EmitModRefBehavior(const std::vector<CodeGenIntrinsic> &Ints,
- raw_ostream &OS);
- void EmitIntrinsicToGCCBuiltinMap(const std::vector<CodeGenIntrinsic> &Ints,
- raw_ostream &OS);
- void EmitSuffix(raw_ostream &OS);
- };
-
-} // End llvm namespace
-
-#endif
-
-
-
diff --git a/utils/TableGen/PseudoLoweringEmitter.cpp b/utils/TableGen/PseudoLoweringEmitter.cpp
index 802d112108fa..8d9d41954485 100644
--- a/utils/TableGen/PseudoLoweringEmitter.cpp
+++ b/utils/TableGen/PseudoLoweringEmitter.cpp
@@ -9,16 +9,62 @@
#define DEBUG_TYPE "pseudo-lowering"
#include "CodeGenInstruction.h"
-#include "PseudoLoweringEmitter.h"
-#include "llvm/TableGen/Error.h"
-#include "llvm/TableGen/Record.h"
+#include "CodeGenTarget.h"
#include "llvm/ADT/IndexedMap.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
-#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/TableGen/Error.h"
+#include "llvm/TableGen/Record.h"
+#include "llvm/TableGen/TableGenBackend.h"
#include <vector>
using namespace llvm;
+namespace {
+class PseudoLoweringEmitter {
+ struct OpData {
+ enum MapKind { Operand, Imm, Reg };
+ MapKind Kind;
+ union {
+ unsigned Operand; // Operand number mapped to.
+ uint64_t Imm; // Integer immedate value.
+ Record *Reg; // Physical register.
+ } Data;
+ };
+ struct PseudoExpansion {
+ CodeGenInstruction Source; // The source pseudo instruction definition.
+ CodeGenInstruction Dest; // The destination instruction to lower to.
+ IndexedMap<OpData> OperandMap;
+
+ PseudoExpansion(CodeGenInstruction &s, CodeGenInstruction &d,
+ IndexedMap<OpData> &m) :
+ Source(s), Dest(d), OperandMap(m) {}
+ };
+
+ RecordKeeper &Records;
+
+ // It's overkill to have an instance of the full CodeGenTarget object,
+ // but it loads everything on demand, not in the constructor, so it's
+ // lightweight in performance, so it works out OK.
+ CodeGenTarget Target;
+
+ SmallVector<PseudoExpansion, 64> Expansions;
+
+ unsigned addDagOperandMapping(Record *Rec, DagInit *Dag,
+ CodeGenInstruction &Insn,
+ IndexedMap<OpData> &OperandMap,
+ unsigned BaseIdx);
+ void evaluateExpansion(Record *Pseudo);
+ void emitLoweringEmitter(raw_ostream &o);
+public:
+ PseudoLoweringEmitter(RecordKeeper &R) : Records(R), Target(R) {}
+
+ /// run - Output the pseudo-lowerings.
+ void run(raw_ostream &o);
+};
+} // End anonymous namespace
+
// FIXME: This pass currently can only expand a pseudo to a single instruction.
// The pseudo expansion really should take a list of dags, not just
// a single dag, so we can do fancier things.
@@ -150,7 +196,7 @@ void PseudoLoweringEmitter::evaluateExpansion(Record *Rec) {
void PseudoLoweringEmitter::emitLoweringEmitter(raw_ostream &o) {
// Emit file header.
- EmitSourceFileHeader("Pseudo-instruction MC lowering Source Fragment", o);
+ emitSourceFileHeader("Pseudo-instruction MC lowering Source Fragment", o);
o << "bool " << Target.getName() + "AsmPrinter" << "::\n"
<< "emitPseudoExpansionLowering(MCStreamer &OutStreamer,\n"
@@ -242,3 +288,10 @@ void PseudoLoweringEmitter::run(raw_ostream &o) {
emitLoweringEmitter(o);
}
+namespace llvm {
+
+void EmitPseudoLowering(RecordKeeper &RK, raw_ostream &OS) {
+ PseudoLoweringEmitter(RK).run(OS);
+}
+
+} // End llvm namespace
diff --git a/utils/TableGen/PseudoLoweringEmitter.h b/utils/TableGen/PseudoLoweringEmitter.h
deleted file mode 100644
index 325bc8be146f..000000000000
--- a/utils/TableGen/PseudoLoweringEmitter.h
+++ /dev/null
@@ -1,65 +0,0 @@
-//===- PseudoLoweringEmitter.h - PseudoLowering Generator -------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef PSEUDOLOWERINGEMITTER_H
-#define PSEUDOLOWERINGEMITTER_H
-
-#include "CodeGenInstruction.h"
-#include "CodeGenTarget.h"
-#include "llvm/TableGen/TableGenBackend.h"
-#include "llvm/ADT/IndexedMap.h"
-#include "llvm/ADT/SmallVector.h"
-
-namespace llvm {
-
-class PseudoLoweringEmitter : public TableGenBackend {
- struct OpData {
- enum MapKind { Operand, Imm, Reg };
- MapKind Kind;
- union {
- unsigned Operand; // Operand number mapped to.
- uint64_t Imm; // Integer immedate value.
- Record *Reg; // Physical register.
- } Data;
- };
- struct PseudoExpansion {
- CodeGenInstruction Source; // The source pseudo instruction definition.
- CodeGenInstruction Dest; // The destination instruction to lower to.
- IndexedMap<OpData> OperandMap;
-
- PseudoExpansion(CodeGenInstruction &s, CodeGenInstruction &d,
- IndexedMap<OpData> &m) :
- Source(s), Dest(d), OperandMap(m) {}
- };
-
- RecordKeeper &Records;
-
- // It's overkill to have an instance of the full CodeGenTarget object,
- // but it loads everything on demand, not in the constructor, so it's
- // lightweight in performance, so it works out OK.
- CodeGenTarget Target;
-
- SmallVector<PseudoExpansion, 64> Expansions;
-
- unsigned addDagOperandMapping(Record *Rec, DagInit *Dag,
- CodeGenInstruction &Insn,
- IndexedMap<OpData> &OperandMap,
- unsigned BaseIdx);
- void evaluateExpansion(Record *Pseudo);
- void emitLoweringEmitter(raw_ostream &o);
-public:
- PseudoLoweringEmitter(RecordKeeper &R) : Records(R), Target(R) {}
-
- /// run - Output the pseudo-lowerings.
- void run(raw_ostream &o);
-};
-
-} // end llvm namespace
-
-#endif
diff --git a/utils/TableGen/RegisterInfoEmitter.cpp b/utils/TableGen/RegisterInfoEmitter.cpp
index 97fcca3a850a..b9138780aa8d 100644
--- a/utils/TableGen/RegisterInfoEmitter.cpp
+++ b/utils/TableGen/RegisterInfoEmitter.cpp
@@ -13,21 +13,58 @@
//
//===----------------------------------------------------------------------===//
-#include "RegisterInfoEmitter.h"
-#include "CodeGenTarget.h"
#include "CodeGenRegisters.h"
+#include "CodeGenTarget.h"
#include "SequenceToOffsetTable.h"
-#include "llvm/TableGen/Error.h"
-#include "llvm/TableGen/Record.h"
#include "llvm/ADT/BitVector.h"
-#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/Format.h"
+#include "llvm/TableGen/Error.h"
+#include "llvm/TableGen/Record.h"
+#include "llvm/TableGen/TableGenBackend.h"
#include <algorithm>
#include <set>
+#include <vector>
using namespace llvm;
+namespace {
+class RegisterInfoEmitter {
+ RecordKeeper &Records;
+public:
+ RegisterInfoEmitter(RecordKeeper &R) : Records(R) {}
+
+ // runEnums - Print out enum values for all of the registers.
+ void runEnums(raw_ostream &o, CodeGenTarget &Target, CodeGenRegBank &Bank);
+
+ // runMCDesc - Print out MC register descriptions.
+ void runMCDesc(raw_ostream &o, CodeGenTarget &Target, CodeGenRegBank &Bank);
+
+ // runTargetHeader - Emit a header fragment for the register info emitter.
+ void runTargetHeader(raw_ostream &o, CodeGenTarget &Target,
+ CodeGenRegBank &Bank);
+
+ // runTargetDesc - Output the target register and register file descriptions.
+ void runTargetDesc(raw_ostream &o, CodeGenTarget &Target,
+ CodeGenRegBank &Bank);
+
+ // run - Output the register file description.
+ void run(raw_ostream &o);
+
+private:
+ void EmitRegMapping(raw_ostream &o,
+ const std::vector<CodeGenRegister*> &Regs, bool isCtor);
+ void EmitRegMappingTables(raw_ostream &o,
+ const std::vector<CodeGenRegister*> &Regs,
+ bool isCtor);
+ void EmitRegClasses(raw_ostream &OS, CodeGenTarget &Target);
+
+ void EmitRegUnitPressure(raw_ostream &OS, const CodeGenRegBank &RegBank,
+ const std::string &ClassName);
+};
+} // End anonymous namespace
+
// runEnums - Print out enum values for all of the registers.
void RegisterInfoEmitter::runEnums(raw_ostream &OS,
CodeGenTarget &Target, CodeGenRegBank &Bank) {
@@ -38,7 +75,7 @@ void RegisterInfoEmitter::runEnums(raw_ostream &OS,
std::string Namespace = Registers[0]->TheDef->getValueAsString("Namespace");
- EmitSourceFileHeader("Target Register Enum Values", OS);
+ emitSourceFileHeader("Target Register Enum Values", OS);
OS << "\n#ifdef GET_REGINFO_ENUM\n";
OS << "#undef GET_REGINFO_ENUM\n";
@@ -151,6 +188,17 @@ EmitRegUnitPressure(raw_ostream &OS, const CodeGenRegBank &RegBank,
<< "unsigned " << ClassName << "::getNumRegPressureSets() const {\n"
<< " return " << NumSets << ";\n}\n\n";
+ OS << "// Get the name of this register unit pressure set.\n"
+ << "const char *" << ClassName << "::\n"
+ << "getRegPressureSetName(unsigned Idx) const {\n"
+ << " static const char *PressureNameTable[] = {\n";
+ for (unsigned i = 0; i < NumSets; ++i ) {
+ OS << " \"" << RegBank.getRegPressureSet(i).Name << "\",\n";
+ }
+ OS << " 0 };\n"
+ << " return PressureNameTable[Idx];\n"
+ << "}\n\n";
+
OS << "// Get the register unit pressure limit for this dimension.\n"
<< "// This limit must be adjusted dynamically for reserved registers.\n"
<< "unsigned " << ClassName << "::\n"
@@ -159,7 +207,7 @@ EmitRegUnitPressure(raw_ostream &OS, const CodeGenRegBank &RegBank,
for (unsigned i = 0; i < NumSets; ++i ) {
const RegUnitSet &RegUnits = RegBank.getRegPressureSet(i);
OS << " " << RegBank.getRegUnitSetWeight(RegUnits.Units)
- << ", \t// " << i << ": " << RegBank.getRegPressureSet(i).Name << "\n";
+ << ", \t// " << i << ": " << RegUnits.Name << "\n";
}
OS << " 0 };\n"
<< " return PressureLimitTable[Idx];\n"
@@ -431,101 +479,203 @@ public:
}
};
-static void printRegister(raw_ostream &OS, const CodeGenRegister *Reg) {
- OS << getQualifiedName(Reg->TheDef);
-}
-
static void printSimpleValueType(raw_ostream &OS, MVT::SimpleValueType VT) {
OS << getEnumName(VT);
}
+static void printSubRegIndex(raw_ostream &OS, const CodeGenSubRegIndex *Idx) {
+ OS << Idx->EnumValue;
+}
+
+// Differentially encoded register and regunit lists allow for better
+// compression on regular register banks. The sequence is computed from the
+// differential list as:
+//
+// out[0] = InitVal;
+// out[n+1] = out[n] + diff[n]; // n = 0, 1, ...
+//
+// The initial value depends on the specific list. The list is terminated by a
+// 0 differential which means we can't encode repeated elements.
+
+typedef SmallVector<uint16_t, 4> DiffVec;
+
+// Differentially encode a sequence of numbers into V. The starting value and
+// terminating 0 are not added to V, so it will have the same size as List.
+static
+DiffVec &diffEncode(DiffVec &V, unsigned InitVal, ArrayRef<unsigned> List) {
+ assert(V.empty() && "Clear DiffVec before diffEncode.");
+ uint16_t Val = uint16_t(InitVal);
+ for (unsigned i = 0; i != List.size(); ++i) {
+ uint16_t Cur = List[i];
+ V.push_back(Cur - Val);
+ Val = Cur;
+ }
+ return V;
+}
+
+template<typename Iter>
+static
+DiffVec &diffEncode(DiffVec &V, unsigned InitVal, Iter Begin, Iter End) {
+ assert(V.empty() && "Clear DiffVec before diffEncode.");
+ uint16_t Val = uint16_t(InitVal);
+ for (Iter I = Begin; I != End; ++I) {
+ uint16_t Cur = (*I)->EnumValue;
+ V.push_back(Cur - Val);
+ Val = Cur;
+ }
+ return V;
+}
+
+static void printDiff16(raw_ostream &OS, uint16_t Val) {
+ OS << Val;
+}
+
//
// runMCDesc - Print out MC register descriptions.
//
void
RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target,
CodeGenRegBank &RegBank) {
- EmitSourceFileHeader("MC Register Information", OS);
+ emitSourceFileHeader("MC Register Information", OS);
OS << "\n#ifdef GET_REGINFO_MC_DESC\n";
OS << "#undef GET_REGINFO_MC_DESC\n";
const std::vector<CodeGenRegister*> &Regs = RegBank.getRegisters();
- std::map<const CodeGenRegister*, CodeGenRegister::Set> Overlaps;
- RegBank.computeOverlaps(Overlaps);
// The lists of sub-registers, super-registers, and overlaps all go in the
// same array. That allows us to share suffixes.
typedef std::vector<const CodeGenRegister*> RegVec;
- SmallVector<RegVec, 4> SubRegLists(Regs.size());
- SmallVector<RegVec, 4> OverlapLists(Regs.size());
- SequenceToOffsetTable<RegVec, CodeGenRegister::Less> RegSeqs;
+
+ // Differentially encoded lists.
+ SequenceToOffsetTable<DiffVec> DiffSeqs;
+ SmallVector<DiffVec, 4> SubRegLists(Regs.size());
+ SmallVector<DiffVec, 4> SuperRegLists(Regs.size());
+ SmallVector<DiffVec, 4> OverlapLists(Regs.size());
+ SmallVector<DiffVec, 4> RegUnitLists(Regs.size());
+ SmallVector<unsigned, 4> RegUnitInitScale(Regs.size());
+
+ // Keep track of sub-register names as well. These are not differentially
+ // encoded.
+ typedef SmallVector<const CodeGenSubRegIndex*, 4> SubRegIdxVec;
+ SequenceToOffsetTable<SubRegIdxVec> SubRegIdxSeqs;
+ SmallVector<SubRegIdxVec, 4> SubRegIdxLists(Regs.size());
+
+ SequenceToOffsetTable<std::string> RegStrings;
// Precompute register lists for the SequenceToOffsetTable.
for (unsigned i = 0, e = Regs.size(); i != e; ++i) {
const CodeGenRegister *Reg = Regs[i];
+ RegStrings.add(Reg->getName());
+
// Compute the ordered sub-register list.
SetVector<const CodeGenRegister*> SR;
Reg->addSubRegsPreOrder(SR, RegBank);
- RegVec &SubRegList = SubRegLists[i];
- SubRegList.assign(SR.begin(), SR.end());
- RegSeqs.add(SubRegList);
+ diffEncode(SubRegLists[i], Reg->EnumValue, SR.begin(), SR.end());
+ DiffSeqs.add(SubRegLists[i]);
+
+ // Compute the corresponding sub-register indexes.
+ SubRegIdxVec &SRIs = SubRegIdxLists[i];
+ for (unsigned j = 0, je = SR.size(); j != je; ++j)
+ SRIs.push_back(Reg->getSubRegIndex(SR[j]));
+ SubRegIdxSeqs.add(SRIs);
// Super-registers are already computed.
const RegVec &SuperRegList = Reg->getSuperRegs();
- RegSeqs.add(SuperRegList);
-
- // The list of overlaps doesn't need to have any particular order, except
- // Reg itself must be the first element. Pick an ordering that has one of
- // the other lists as a suffix.
- RegVec &OverlapList = OverlapLists[i];
- const RegVec &Suffix = SubRegList.size() > SuperRegList.size() ?
- SubRegList : SuperRegList;
- CodeGenRegister::Set Omit(Suffix.begin(), Suffix.end());
-
- // First element is Reg itself.
- OverlapList.push_back(Reg);
- Omit.insert(Reg);
-
- // Any elements not in Suffix.
- const CodeGenRegister::Set &OSet = Overlaps[Reg];
- std::set_difference(OSet.begin(), OSet.end(),
- Omit.begin(), Omit.end(),
- std::back_inserter(OverlapList),
- CodeGenRegister::Less());
-
- // Finally, Suffix itself.
- OverlapList.insert(OverlapList.end(), Suffix.begin(), Suffix.end());
- RegSeqs.add(OverlapList);
+ diffEncode(SuperRegLists[i], Reg->EnumValue,
+ SuperRegList.begin(), SuperRegList.end());
+ DiffSeqs.add(SuperRegLists[i]);
+
+ // The list of overlaps doesn't need to have any particular order, and Reg
+ // itself must be omitted.
+ DiffVec &OverlapList = OverlapLists[i];
+ CodeGenRegister::Set OSet;
+ Reg->computeOverlaps(OSet, RegBank);
+ OSet.erase(Reg);
+ diffEncode(OverlapList, Reg->EnumValue, OSet.begin(), OSet.end());
+ DiffSeqs.add(OverlapList);
+
+ // Differentially encode the register unit list, seeded by register number.
+ // First compute a scale factor that allows more diff-lists to be reused:
+ //
+ // D0 -> (S0, S1)
+ // D1 -> (S2, S3)
+ //
+ // A scale factor of 2 allows D0 and D1 to share a diff-list. The initial
+ // value for the differential decoder is the register number multiplied by
+ // the scale.
+ //
+ // Check the neighboring registers for arithmetic progressions.
+ unsigned ScaleA = ~0u, ScaleB = ~0u;
+ ArrayRef<unsigned> RUs = Reg->getNativeRegUnits();
+ if (i > 0 && Regs[i-1]->getNativeRegUnits().size() == RUs.size())
+ ScaleB = RUs.front() - Regs[i-1]->getNativeRegUnits().front();
+ if (i+1 != Regs.size() &&
+ Regs[i+1]->getNativeRegUnits().size() == RUs.size())
+ ScaleA = Regs[i+1]->getNativeRegUnits().front() - RUs.front();
+ unsigned Scale = std::min(ScaleB, ScaleA);
+ // Default the scale to 0 if it can't be encoded in 4 bits.
+ if (Scale >= 16)
+ Scale = 0;
+ RegUnitInitScale[i] = Scale;
+ DiffSeqs.add(diffEncode(RegUnitLists[i], Scale * Reg->EnumValue, RUs));
}
// Compute the final layout of the sequence table.
- RegSeqs.layout();
+ DiffSeqs.layout();
+ SubRegIdxSeqs.layout();
OS << "namespace llvm {\n\n";
const std::string &TargetName = Target.getName();
- // Emit the shared table of register lists.
- OS << "extern const uint16_t " << TargetName << "RegLists[] = {\n";
- RegSeqs.emit(OS, printRegister);
+ // Emit the shared table of differential lists.
+ OS << "extern const uint16_t " << TargetName << "RegDiffLists[] = {\n";
+ DiffSeqs.emit(OS, printDiff16);
+ OS << "};\n\n";
+
+ // Emit the table of sub-register indexes.
+ OS << "extern const uint16_t " << TargetName << "SubRegIdxLists[] = {\n";
+ SubRegIdxSeqs.emit(OS, printSubRegIndex);
+ OS << "};\n\n";
+
+ // Emit the string table.
+ RegStrings.layout();
+ OS << "extern const char " << TargetName << "RegStrings[] = {\n";
+ RegStrings.emit(OS, printChar);
OS << "};\n\n";
OS << "extern const MCRegisterDesc " << TargetName
<< "RegDesc[] = { // Descriptors\n";
- OS << " { \"NOREG\", 0, 0, 0 },\n";
+ OS << " { " << RegStrings.get("") << ", 0, 0, 0, 0, 0 },\n";
// Emit the register descriptors now.
for (unsigned i = 0, e = Regs.size(); i != e; ++i) {
const CodeGenRegister *Reg = Regs[i];
- OS << " { \"" << Reg->getName() << "\", "
- << RegSeqs.get(OverlapLists[i]) << ", "
- << RegSeqs.get(SubRegLists[i]) << ", "
- << RegSeqs.get(Reg->getSuperRegs()) << " },\n";
+ OS << " { " << RegStrings.get(Reg->getName()) << ", "
+ << DiffSeqs.get(OverlapLists[i]) << ", "
+ << DiffSeqs.get(SubRegLists[i]) << ", "
+ << DiffSeqs.get(SuperRegLists[i]) << ", "
+ << SubRegIdxSeqs.get(SubRegIdxLists[i]) << ", "
+ << (DiffSeqs.get(RegUnitLists[i])*16 + RegUnitInitScale[i]) << " },\n";
}
OS << "};\n\n"; // End of register descriptors...
+ // Emit the table of register unit roots. Each regunit has one or two root
+ // registers.
+ OS << "extern const uint16_t " << TargetName << "RegUnitRoots[][2] = {\n";
+ for (unsigned i = 0, e = RegBank.getNumNativeRegUnits(); i != e; ++i) {
+ ArrayRef<const CodeGenRegister*> Roots = RegBank.getRegUnit(i).getRoots();
+ assert(!Roots.empty() && "All regunits must have a root register.");
+ assert(Roots.size() <= 2 && "More than two roots not supported yet.");
+ OS << " { " << getQualifiedName(Roots.front()->TheDef);
+ for (unsigned r = 1; r != Roots.size(); ++r)
+ OS << ", " << getQualifiedName(Roots[r]->TheDef);
+ OS << " },\n";
+ }
+ OS << "};\n\n";
+
ArrayRef<CodeGenRegisterClass*> RegisterClasses = RegBank.getRegClasses();
// Loop over all of the register classes... emitting each one.
@@ -587,52 +737,41 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target,
OS << "};\n\n";
- // Emit the data table for getSubReg().
ArrayRef<CodeGenSubRegIndex*> SubRegIndices = RegBank.getSubRegIndices();
- if (SubRegIndices.size()) {
- OS << "const uint16_t " << TargetName << "SubRegTable[]["
- << SubRegIndices.size() << "] = {\n";
- for (unsigned i = 0, e = Regs.size(); i != e; ++i) {
- const CodeGenRegister::SubRegMap &SRM = Regs[i]->getSubRegs();
- OS << " /* " << Regs[i]->TheDef->getName() << " */\n";
- if (SRM.empty()) {
- OS << " {0},\n";
- continue;
- }
- OS << " {";
- for (unsigned j = 0, je = SubRegIndices.size(); j != je; ++j) {
- // FIXME: We really should keep this to 80 columns...
- CodeGenRegister::SubRegMap::const_iterator SubReg =
- SRM.find(SubRegIndices[j]);
- if (SubReg != SRM.end())
- OS << getQualifiedName(SubReg->second->TheDef);
- else
- OS << "0";
- if (j != je - 1)
- OS << ", ";
- }
- OS << "}" << (i != e ? "," : "") << "\n";
- }
- OS << "};\n\n";
- OS << "const uint16_t *get" << TargetName
- << "SubRegTable() {\n return (const uint16_t *)" << TargetName
- << "SubRegTable;\n}\n\n";
- }
EmitRegMappingTables(OS, Regs, false);
+ // Emit Reg encoding table
+ OS << "extern const uint16_t " << TargetName;
+ OS << "RegEncodingTable[] = {\n";
+ // Add entry for NoRegister
+ OS << " 0,\n";
+ for (unsigned i = 0, e = Regs.size(); i != e; ++i) {
+ Record *Reg = Regs[i]->TheDef;
+ BitsInit *BI = Reg->getValueAsBitsInit("HWEncoding");
+ uint64_t Value = 0;
+ for (unsigned b = 0, be = BI->getNumBits(); b != be; ++b) {
+ if (BitInit *B = dynamic_cast<BitInit*>(BI->getBit(b)))
+ Value |= (uint64_t)B->getValue() << b;
+ }
+ OS << " " << Value << ",\n";
+ }
+ OS << "};\n"; // End of HW encoding table
+
// MCRegisterInfo initialization routine.
OS << "static inline void Init" << TargetName
<< "MCRegisterInfo(MCRegisterInfo *RI, unsigned RA, "
- << "unsigned DwarfFlavour = 0, unsigned EHFlavour = 0) {\n";
- OS << " RI->InitMCRegisterInfo(" << TargetName << "RegDesc, "
+ << "unsigned DwarfFlavour = 0, unsigned EHFlavour = 0) {\n"
+ << " RI->InitMCRegisterInfo(" << TargetName << "RegDesc, "
<< Regs.size()+1 << ", RA, " << TargetName << "MCRegisterClasses, "
- << RegisterClasses.size() << ", " << TargetName << "RegLists, ";
- if (SubRegIndices.size() != 0)
- OS << "(uint16_t*)" << TargetName << "SubRegTable, "
- << SubRegIndices.size() << ");\n\n";
- else
- OS << "NULL, 0);\n\n";
+ << RegisterClasses.size() << ", "
+ << TargetName << "RegUnitRoots, "
+ << RegBank.getNumNativeRegUnits() << ", "
+ << TargetName << "RegDiffLists, "
+ << TargetName << "RegStrings, "
+ << TargetName << "SubRegIdxLists, "
+ << SubRegIndices.size() << ",\n"
+ << " " << TargetName << "RegEncodingTable);\n\n";
EmitRegMapping(OS, Regs, false);
@@ -645,7 +784,7 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target,
void
RegisterInfoEmitter::runTargetHeader(raw_ostream &OS, CodeGenTarget &Target,
CodeGenRegBank &RegBank) {
- EmitSourceFileHeader("Register Information Header Fragment", OS);
+ emitSourceFileHeader("Register Information Header Fragment", OS);
OS << "\n#ifdef GET_REGINFO_HEADER\n";
OS << "#undef GET_REGINFO_HEADER\n";
@@ -661,16 +800,16 @@ RegisterInfoEmitter::runTargetHeader(raw_ostream &OS, CodeGenTarget &Target,
<< " explicit " << ClassName
<< "(unsigned RA, unsigned D = 0, unsigned E = 0);\n"
<< " virtual bool needsStackRealignment(const MachineFunction &) const\n"
- << " { return false; }\n"
- << " unsigned composeSubRegIndices(unsigned, unsigned) const;\n"
- << " const TargetRegisterClass *"
- "getSubClassWithSubReg(const TargetRegisterClass*, unsigned) const;\n"
- << " const TargetRegisterClass *getMatchingSuperRegClass("
- "const TargetRegisterClass*, const TargetRegisterClass*, "
- "unsigned) const;\n"
- << " const RegClassWeight &getRegClassWeight("
+ << " { return false; }\n";
+ if (!RegBank.getSubRegIndices().empty()) {
+ OS << " unsigned composeSubRegIndices(unsigned, unsigned) const;\n"
+ << " const TargetRegisterClass *"
+ "getSubClassWithSubReg(const TargetRegisterClass*, unsigned) const;\n";
+ }
+ OS << " const RegClassWeight &getRegClassWeight("
<< "const TargetRegisterClass *RC) const;\n"
<< " unsigned getNumRegPressureSets() const;\n"
+ << " const char *getRegPressureSetName(unsigned Idx) const;\n"
<< " unsigned getRegPressureSetLimit(unsigned Idx) const;\n"
<< " const int *getRegClassPressureSets("
<< "const TargetRegisterClass *RC) const;\n"
@@ -688,9 +827,6 @@ RegisterInfoEmitter::runTargetHeader(raw_ostream &OS, CodeGenTarget &Target,
// Output the extern for the instance.
OS << " extern const TargetRegisterClass " << Name << "RegClass;\n";
- // Output the extern for the pointer to the instance (should remove).
- OS << " static const TargetRegisterClass * const " << Name
- << "RegisterClass = &" << Name << "RegClass;\n";
}
OS << "} // end of namespace " << TargetName << "\n\n";
}
@@ -704,7 +840,7 @@ RegisterInfoEmitter::runTargetHeader(raw_ostream &OS, CodeGenTarget &Target,
void
RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
CodeGenRegBank &RegBank){
- EmitSourceFileHeader("Target Register and Register Classes Information", OS);
+ emitSourceFileHeader("Target Register and Register Classes Information", OS);
OS << "\n#ifdef GET_REGINFO_TARGET_DESC\n";
OS << "#undef GET_REGINFO_TARGET_DESC\n";
@@ -717,6 +853,7 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
// Start out by emitting each of the register classes.
ArrayRef<CodeGenRegisterClass*> RegisterClasses = RegBank.getRegClasses();
+ ArrayRef<CodeGenSubRegIndex*> SubRegIndices = RegBank.getSubRegIndices();
// Collect all registers belonging to any allocatable class.
std::set<Record*> AllocatableRegs;
@@ -739,72 +876,85 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
VTSeqs.emit(OS, printSimpleValueType, "MVT::Other");
OS << "};\n";
+ // Emit SubRegIndex names, skipping 0
+ OS << "\nstatic const char *const SubRegIndexTable[] = { \"";
+ for (unsigned i = 0, e = SubRegIndices.size(); i != e; ++i) {
+ OS << SubRegIndices[i]->getName();
+ if (i+1 != e)
+ OS << "\", \"";
+ }
+ OS << "\" };\n\n";
+
+ // Emit names of the anonymous subreg indices.
+ unsigned NamedIndices = RegBank.getNumNamedIndices();
+ if (SubRegIndices.size() > NamedIndices) {
+ OS << " enum {";
+ for (unsigned i = NamedIndices, e = SubRegIndices.size(); i != e; ++i) {
+ OS << "\n " << SubRegIndices[i]->getName() << " = " << i+1;
+ if (i+1 != e)
+ OS << ',';
+ }
+ OS << "\n };\n\n";
+ }
+ OS << "\n";
+
// Now that all of the structs have been emitted, emit the instances.
if (!RegisterClasses.empty()) {
- std::map<unsigned, std::set<unsigned> > SuperRegClassMap;
-
OS << "\nstatic const TargetRegisterClass *const "
<< "NullRegClasses[] = { NULL };\n\n";
- unsigned NumSubRegIndices = RegBank.getSubRegIndices().size();
-
- if (NumSubRegIndices) {
- // Compute the super-register classes for each RegisterClass
- for (unsigned rc = 0, e = RegisterClasses.size(); rc != e; ++rc) {
- const CodeGenRegisterClass &RC = *RegisterClasses[rc];
- for (DenseMap<Record*,Record*>::const_iterator
- i = RC.SubRegClasses.begin(),
- e = RC.SubRegClasses.end(); i != e; ++i) {
- // Find the register class number of i->second for SuperRegClassMap.
- const CodeGenRegisterClass *RC2 = RegBank.getRegClass(i->second);
- assert(RC2 && "Invalid register class in SubRegClasses");
- SuperRegClassMap[RC2->EnumValue].insert(rc);
- }
- }
-
- // Emit the super-register classes for each RegisterClass
- for (unsigned rc = 0, e = RegisterClasses.size(); rc != e; ++rc) {
- const CodeGenRegisterClass &RC = *RegisterClasses[rc];
-
- // Give the register class a legal C name if it's anonymous.
- std::string Name = RC.getName();
-
- OS << "// " << Name
- << " Super-register Classes...\n"
- << "static const TargetRegisterClass *const "
- << Name << "SuperRegClasses[] = {\n ";
-
- bool Empty = true;
- std::map<unsigned, std::set<unsigned> >::iterator I =
- SuperRegClassMap.find(rc);
- if (I != SuperRegClassMap.end()) {
- for (std::set<unsigned>::iterator II = I->second.begin(),
- EE = I->second.end(); II != EE; ++II) {
- const CodeGenRegisterClass &RC2 = *RegisterClasses[*II];
- if (!Empty)
- OS << ", ";
- OS << "&" << RC2.getQualifiedName() << "RegClass";
- Empty = false;
- }
- }
-
- OS << (!Empty ? ", " : "") << "NULL";
- OS << "\n};\n\n";
- }
- }
+ // Emit register class bit mask tables. The first bit mask emitted for a
+ // register class, RC, is the set of sub-classes, including RC itself.
+ //
+ // If RC has super-registers, also create a list of subreg indices and bit
+ // masks, (Idx, Mask). The bit mask has a bit for every superreg regclass,
+ // SuperRC, that satisfies:
+ //
+ // For all SuperReg in SuperRC: SuperReg:Idx in RC
+ //
+ // The 0-terminated list of subreg indices starts at:
+ //
+ // RC->getSuperRegIndices() = SuperRegIdxSeqs + ...
+ //
+ // The corresponding bitmasks follow the sub-class mask in memory. Each
+ // mask has RCMaskWords uint32_t entries.
+ //
+ // Every bit mask present in the list has at least one bit set.
+
+ // Compress the sub-reg index lists.
+ typedef std::vector<const CodeGenSubRegIndex*> IdxList;
+ SmallVector<IdxList, 8> SuperRegIdxLists(RegisterClasses.size());
+ SequenceToOffsetTable<IdxList> SuperRegIdxSeqs;
+ BitVector MaskBV(RegisterClasses.size());
- // Emit the sub-classes array for each RegisterClass
for (unsigned rc = 0, e = RegisterClasses.size(); rc != e; ++rc) {
const CodeGenRegisterClass &RC = *RegisterClasses[rc];
-
- // Give the register class a legal C name if it's anonymous.
- std::string Name = RC.getName();
-
- OS << "static const uint32_t " << Name << "SubclassMask[] = {\n ";
+ OS << "static const uint32_t " << RC.getName() << "SubClassMask[] = {\n ";
printBitVectorAsHex(OS, RC.getSubClasses(), 32);
+
+ // Emit super-reg class masks for any relevant SubRegIndices that can
+ // project into RC.
+ IdxList &SRIList = SuperRegIdxLists[rc];
+ for (unsigned sri = 0, sre = SubRegIndices.size(); sri != sre; ++sri) {
+ CodeGenSubRegIndex *Idx = SubRegIndices[sri];
+ MaskBV.reset();
+ RC.getSuperRegClasses(Idx, MaskBV);
+ if (MaskBV.none())
+ continue;
+ SRIList.push_back(Idx);
+ OS << "\n ";
+ printBitVectorAsHex(OS, MaskBV, 32);
+ OS << "// " << Idx->getName();
+ }
+ SuperRegIdxSeqs.add(SRIList);
OS << "\n};\n\n";
}
+ OS << "static const uint16_t SuperRegIdxSeqs[] = {\n";
+ SuperRegIdxSeqs.layout();
+ SuperRegIdxSeqs.emit(OS, printSubRegIndex);
+ OS << "};\n\n";
+
// Emit NULL terminated super-class lists.
for (unsigned rc = 0, e = RegisterClasses.size(); rc != e; ++rc) {
const CodeGenRegisterClass &RC = *RegisterClasses[rc];
@@ -865,13 +1015,12 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
<< '&' << Target.getName() << "MCRegisterClasses[" << RC.getName()
<< "RegClassID],\n "
<< "VTLists + " << VTSeqs.get(RC.VTs) << ",\n "
- << RC.getName() << "SubclassMask,\n ";
+ << RC.getName() << "SubClassMask,\n SuperRegIdxSeqs + "
+ << SuperRegIdxSeqs.get(SuperRegIdxLists[i]) << ",\n ";
if (RC.getSuperClasses().empty())
OS << "NullRegClasses,\n ";
else
OS << RC.getName() << "Superclasses,\n ";
- OS << (NumSubRegIndices ? RC.getName() + "Super" : std::string("Null"))
- << "RegClasses,\n ";
if (RC.AltOrderSelect.empty())
OS << "0\n";
else
@@ -906,67 +1055,39 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
OS << "};\n"; // End of register descriptors...
- // Calculate the mapping of subregister+index pairs to physical registers.
- // This will also create further anonymous indices.
- unsigned NamedIndices = RegBank.getNumNamedIndices();
-
- // Emit SubRegIndex names, skipping 0
- ArrayRef<CodeGenSubRegIndex*> SubRegIndices = RegBank.getSubRegIndices();
- OS << "\nstatic const char *const " << TargetName
- << "SubRegIndexTable[] = { \"";
- for (unsigned i = 0, e = SubRegIndices.size(); i != e; ++i) {
- OS << SubRegIndices[i]->getName();
- if (i+1 != e)
- OS << "\", \"";
- }
- OS << "\" };\n\n";
-
- // Emit names of the anonymous subreg indices.
- if (SubRegIndices.size() > NamedIndices) {
- OS << " enum {";
- for (unsigned i = NamedIndices, e = SubRegIndices.size(); i != e; ++i) {
- OS << "\n " << SubRegIndices[i]->getName() << " = " << i+1;
- if (i+1 != e)
- OS << ',';
- }
- OS << "\n };\n\n";
- }
- OS << "\n";
-
std::string ClassName = Target.getName() + "GenRegisterInfo";
// Emit composeSubRegIndices
- OS << "unsigned " << ClassName
- << "::composeSubRegIndices(unsigned IdxA, unsigned IdxB) const {\n"
- << " switch (IdxA) {\n"
- << " default:\n return IdxB;\n";
- for (unsigned i = 0, e = SubRegIndices.size(); i != e; ++i) {
- bool Open = false;
- for (unsigned j = 0; j != e; ++j) {
- if (CodeGenSubRegIndex *Comp =
+ if (!SubRegIndices.empty()) {
+ OS << "unsigned " << ClassName
+ << "::composeSubRegIndices(unsigned IdxA, unsigned IdxB) const {\n"
+ << " switch (IdxA) {\n"
+ << " default:\n return IdxB;\n";
+ for (unsigned i = 0, e = SubRegIndices.size(); i != e; ++i) {
+ bool Open = false;
+ for (unsigned j = 0; j != e; ++j) {
+ if (CodeGenSubRegIndex *Comp =
SubRegIndices[i]->compose(SubRegIndices[j])) {
- if (!Open) {
- OS << " case " << SubRegIndices[i]->getQualifiedName()
- << ": switch(IdxB) {\n default: return IdxB;\n";
- Open = true;
+ if (!Open) {
+ OS << " case " << SubRegIndices[i]->getQualifiedName()
+ << ": switch(IdxB) {\n default: return IdxB;\n";
+ Open = true;
+ }
+ OS << " case " << SubRegIndices[j]->getQualifiedName()
+ << ": return " << Comp->getQualifiedName() << ";\n";
}
- OS << " case " << SubRegIndices[j]->getQualifiedName()
- << ": return " << Comp->getQualifiedName() << ";\n";
}
+ if (Open)
+ OS << " }\n";
}
- if (Open)
- OS << " }\n";
+ OS << " }\n}\n\n";
}
- OS << " }\n}\n\n";
// Emit getSubClassWithSubReg.
- OS << "const TargetRegisterClass *" << ClassName
- << "::getSubClassWithSubReg(const TargetRegisterClass *RC, unsigned Idx)"
- " const {\n";
- if (SubRegIndices.empty()) {
- OS << " assert(Idx == 0 && \"Target has no sub-registers\");\n"
- << " return RC;\n";
- } else {
+ if (!SubRegIndices.empty()) {
+ OS << "const TargetRegisterClass *" << ClassName
+ << "::getSubClassWithSubReg(const TargetRegisterClass *RC, unsigned Idx)"
+ << " const {\n";
// Use the smallest type that can hold a regclass ID with room for a
// sentinel.
if (RegisterClasses.size() < UINT8_MAX)
@@ -993,63 +1114,18 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
<< " if (!Idx) return RC;\n --Idx;\n"
<< " assert(Idx < " << SubRegIndices.size() << " && \"Bad subreg\");\n"
<< " unsigned TV = Table[RC->getID()][Idx];\n"
- << " return TV ? getRegClass(TV - 1) : 0;\n";
- }
- OS << "}\n\n";
-
- // Emit getMatchingSuperRegClass.
- OS << "const TargetRegisterClass *" << ClassName
- << "::getMatchingSuperRegClass(const TargetRegisterClass *A,"
- " const TargetRegisterClass *B, unsigned Idx) const {\n";
- if (SubRegIndices.empty()) {
- OS << " llvm_unreachable(\"Target has no sub-registers\");\n";
- } else {
- // We need to find the largest sub-class of A such that every register has
- // an Idx sub-register in B. Map (B, Idx) to a bit-vector of
- // super-register classes that map into B. Then compute the largest common
- // sub-class with A by taking advantage of the register class ordering,
- // like getCommonSubClass().
-
- // Bitvector table is NumRCs x NumSubIndexes x BVWords, where BVWords is
- // the number of 32-bit words required to represent all register classes.
- const unsigned BVWords = (RegisterClasses.size()+31)/32;
- BitVector BV(RegisterClasses.size());
-
- OS << " static const uint32_t Table[" << RegisterClasses.size()
- << "][" << SubRegIndices.size() << "][" << BVWords << "] = {\n";
- for (unsigned rci = 0, rce = RegisterClasses.size(); rci != rce; ++rci) {
- const CodeGenRegisterClass &RC = *RegisterClasses[rci];
- OS << " {\t// " << RC.getName() << "\n";
- for (unsigned sri = 0, sre = SubRegIndices.size(); sri != sre; ++sri) {
- CodeGenSubRegIndex *Idx = SubRegIndices[sri];
- BV.reset();
- RC.getSuperRegClasses(Idx, BV);
- OS << " { ";
- printBitVectorAsHex(OS, BV, 32);
- OS << "},\t// " << Idx->getName() << '\n';
- }
- OS << " },\n";
- }
- OS << " };\n assert(A && B && \"Missing regclass\");\n"
- << " --Idx;\n"
- << " assert(Idx < " << SubRegIndices.size() << " && \"Bad subreg\");\n"
- << " const uint32_t *TV = Table[B->getID()][Idx];\n"
- << " const uint32_t *SC = A->getSubClassMask();\n"
- << " for (unsigned i = 0; i != " << BVWords << "; ++i)\n"
- << " if (unsigned Common = TV[i] & SC[i])\n"
- << " return getRegClass(32*i + CountTrailingZeros_32(Common));\n"
- << " return 0;\n";
+ << " return TV ? getRegClass(TV - 1) : 0;\n}\n\n";
}
- OS << "}\n\n";
EmitRegUnitPressure(OS, RegBank, ClassName);
// Emit the constructor of the class...
OS << "extern const MCRegisterDesc " << TargetName << "RegDesc[];\n";
- OS << "extern const uint16_t " << TargetName << "RegLists[];\n";
- if (SubRegIndices.size() != 0)
- OS << "extern const uint16_t *get" << TargetName
- << "SubRegTable();\n";
+ OS << "extern const uint16_t " << 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";
+ OS << "extern const uint16_t " << TargetName << "RegEncodingTable[];\n";
EmitRegMappingTables(OS, Regs, true);
@@ -1057,17 +1133,17 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
<< "(unsigned RA, unsigned DwarfFlavour, unsigned EHFlavour)\n"
<< " : TargetRegisterInfo(" << TargetName << "RegInfoDesc"
<< ", RegisterClasses, RegisterClasses+" << RegisterClasses.size() <<",\n"
- << " " << TargetName << "SubRegIndexTable) {\n"
+ << " SubRegIndexTable) {\n"
<< " InitMCRegisterInfo(" << TargetName << "RegDesc, "
<< Regs.size()+1 << ", RA,\n " << TargetName
<< "MCRegisterClasses, " << RegisterClasses.size() << ",\n"
- << " " << TargetName << "RegLists,\n"
- << " ";
- if (SubRegIndices.size() != 0)
- OS << "get" << TargetName << "SubRegTable(), "
- << SubRegIndices.size() << ");\n\n";
- else
- OS << "NULL, 0);\n\n";
+ << " " << TargetName << "RegUnitRoots,\n"
+ << " " << RegBank.getNumNativeRegUnits() << ",\n"
+ << " " << TargetName << "RegDiffLists,\n"
+ << " " << TargetName << "RegStrings,\n"
+ << " " << TargetName << "SubRegIdxLists,\n"
+ << " " << SubRegIndices.size() << ",\n"
+ << " " << TargetName << "RegEncodingTable);\n\n";
EmitRegMapping(OS, Regs, true);
@@ -1111,3 +1187,11 @@ void RegisterInfoEmitter::run(raw_ostream &OS) {
runTargetHeader(OS, Target, RegBank);
runTargetDesc(OS, Target, RegBank);
}
+
+namespace llvm {
+
+void EmitRegisterInfo(RecordKeeper &RK, raw_ostream &OS) {
+ RegisterInfoEmitter(RK).run(OS);
+}
+
+} // End llvm namespace
diff --git a/utils/TableGen/RegisterInfoEmitter.h b/utils/TableGen/RegisterInfoEmitter.h
deleted file mode 100644
index ee9903cac7b1..000000000000
--- a/utils/TableGen/RegisterInfoEmitter.h
+++ /dev/null
@@ -1,64 +0,0 @@
-//===- RegisterInfoEmitter.h - Generate a Register File Desc. ---*- 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 a target
-// register file for a code generator. It uses instances of the Register,
-// RegisterAliases, and RegisterClass classes to gather this information.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef REGISTER_INFO_EMITTER_H
-#define REGISTER_INFO_EMITTER_H
-
-#include "llvm/TableGen/TableGenBackend.h"
-#include <vector>
-
-namespace llvm {
-
-class CodeGenRegBank;
-struct CodeGenRegister;
-class CodeGenTarget;
-
-class RegisterInfoEmitter : public TableGenBackend {
- RecordKeeper &Records;
-public:
- RegisterInfoEmitter(RecordKeeper &R) : Records(R) {}
-
- // runEnums - Print out enum values for all of the registers.
- void runEnums(raw_ostream &o, CodeGenTarget &Target, CodeGenRegBank &Bank);
-
- // runMCDesc - Print out MC register descriptions.
- void runMCDesc(raw_ostream &o, CodeGenTarget &Target, CodeGenRegBank &Bank);
-
- // runTargetHeader - Emit a header fragment for the register info emitter.
- void runTargetHeader(raw_ostream &o, CodeGenTarget &Target,
- CodeGenRegBank &Bank);
-
- // runTargetDesc - Output the target register and register file descriptions.
- void runTargetDesc(raw_ostream &o, CodeGenTarget &Target,
- CodeGenRegBank &Bank);
-
- // run - Output the register file description.
- void run(raw_ostream &o);
-
-private:
- void EmitRegMapping(raw_ostream &o,
- const std::vector<CodeGenRegister*> &Regs, bool isCtor);
- void EmitRegMappingTables(raw_ostream &o,
- const std::vector<CodeGenRegister*> &Regs,
- bool isCtor);
- void EmitRegClasses(raw_ostream &OS, CodeGenTarget &Target);
-
- void EmitRegUnitPressure(raw_ostream &OS, const CodeGenRegBank &RegBank,
- const std::string &ClassName);
-};
-
-} // End llvm namespace
-
-#endif
diff --git a/utils/TableGen/SequenceToOffsetTable.h b/utils/TableGen/SequenceToOffsetTable.h
index 97c764e61d56..d8ab2eeb2581 100644
--- a/utils/TableGen/SequenceToOffsetTable.h
+++ b/utils/TableGen/SequenceToOffsetTable.h
@@ -81,6 +81,8 @@ public:
Seqs.erase(I);
}
+ bool empty() const { return Seqs.empty(); }
+
/// layout - Computes the final table layout.
void layout() {
assert(Entries == 0 && "Can only call layout() once");
diff --git a/utils/TableGen/SetTheory.cpp b/utils/TableGen/SetTheory.cpp
index 0649fd1cfaf9..46e6db173ea9 100644
--- a/utils/TableGen/SetTheory.cpp
+++ b/utils/TableGen/SetTheory.cpp
@@ -160,9 +160,17 @@ struct InterleaveOp : public SetTheory::Operator {
// (sequence "Format", From, To) Generate a sequence of records by name.
struct SequenceOp : public SetTheory::Operator {
void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts) {
- if (Expr->arg_size() != 3)
+ int Step = 1;
+ if (Expr->arg_size() > 4)
throw "Bad args to (sequence \"Format\", From, To): " +
Expr->getAsString();
+ else if (Expr->arg_size() == 4) {
+ if (IntInit *II = dynamic_cast<IntInit*>(Expr->arg_begin()[3])) {
+ Step = II->getValue();
+ } else
+ throw "Stride must be an integer: " + Expr->getAsString();
+ }
+
std::string Format;
if (StringInit *SI = dynamic_cast<StringInit*>(Expr->arg_begin()[0]))
Format = SI->getValue();
@@ -187,8 +195,12 @@ struct SequenceOp : public SetTheory::Operator {
RecordKeeper &Records =
dynamic_cast<DefInit&>(*Expr->getOperator()).getDef()->getRecords();
- int Step = From <= To ? 1 : -1;
- for (To += Step; From != To; From += Step) {
+ Step *= From <= To ? 1 : -1;
+ while (true) {
+ if (Step > 0 && From > To)
+ break;
+ else if (Step < 0 && From < To)
+ break;
std::string Name;
raw_string_ostream OS(Name);
OS << format(Format.c_str(), unsigned(From));
@@ -200,6 +212,8 @@ struct SequenceOp : public SetTheory::Operator {
Elts.insert(Result->begin(), Result->end());
else
Elts.insert(Rec);
+
+ From += Step;
}
}
};
diff --git a/utils/TableGen/StringMatcher.cpp b/utils/TableGen/StringMatcher.cpp
deleted file mode 100644
index 6aedcbf458a8..000000000000
--- a/utils/TableGen/StringMatcher.cpp
+++ /dev/null
@@ -1,149 +0,0 @@
-//===- StringMatcher.cpp - Generate a matcher for input strings -----------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements the StringMatcher class.
-//
-//===----------------------------------------------------------------------===//
-
-#include "StringMatcher.h"
-#include "llvm/Support/raw_ostream.h"
-#include <map>
-using namespace llvm;
-
-/// FindFirstNonCommonLetter - Find the first character in the keys of the
-/// string pairs that is not shared across the whole set of strings. All
-/// strings are assumed to have the same length.
-static unsigned
-FindFirstNonCommonLetter(const std::vector<const
- StringMatcher::StringPair*> &Matches) {
- assert(!Matches.empty());
- for (unsigned i = 0, e = Matches[0]->first.size(); i != e; ++i) {
- // Check to see if letter i is the same across the set.
- char Letter = Matches[0]->first[i];
-
- for (unsigned str = 0, e = Matches.size(); str != e; ++str)
- if (Matches[str]->first[i] != Letter)
- return i;
- }
-
- return Matches[0]->first.size();
-}
-
-/// EmitStringMatcherForChar - Given a set of strings that are known to be the
-/// same length and whose characters leading up to CharNo are the same, emit
-/// code to verify that CharNo and later are the same.
-///
-/// \return - True if control can leave the emitted code fragment.
-bool StringMatcher::
-EmitStringMatcherForChar(const std::vector<const StringPair*> &Matches,
- unsigned CharNo, unsigned IndentCount) const {
- assert(!Matches.empty() && "Must have at least one string to match!");
- std::string Indent(IndentCount*2+4, ' ');
-
- // If we have verified that the entire string matches, we're done: output the
- // matching code.
- if (CharNo == Matches[0]->first.size()) {
- assert(Matches.size() == 1 && "Had duplicate keys to match on");
-
- // If the to-execute code has \n's in it, indent each subsequent line.
- StringRef Code = Matches[0]->second;
-
- std::pair<StringRef, StringRef> Split = Code.split('\n');
- OS << Indent << Split.first << "\t // \"" << Matches[0]->first << "\"\n";
-
- Code = Split.second;
- while (!Code.empty()) {
- Split = Code.split('\n');
- OS << Indent << Split.first << "\n";
- Code = Split.second;
- }
- return false;
- }
-
- // Bucket the matches by the character we are comparing.
- std::map<char, std::vector<const StringPair*> > MatchesByLetter;
-
- for (unsigned i = 0, e = Matches.size(); i != e; ++i)
- MatchesByLetter[Matches[i]->first[CharNo]].push_back(Matches[i]);
-
-
- // If we have exactly one bucket to match, see how many characters are common
- // across the whole set and match all of them at once.
- if (MatchesByLetter.size() == 1) {
- unsigned FirstNonCommonLetter = FindFirstNonCommonLetter(Matches);
- unsigned NumChars = FirstNonCommonLetter-CharNo;
-
- // Emit code to break out if the prefix doesn't match.
- if (NumChars == 1) {
- // Do the comparison with if (Str[1] != 'f')
- // FIXME: Need to escape general characters.
- OS << Indent << "if (" << StrVariableName << "[" << CharNo << "] != '"
- << Matches[0]->first[CharNo] << "')\n";
- OS << Indent << " break;\n";
- } else {
- // Do the comparison with if (Str.substr(1, 3) != "foo").
- // FIXME: Need to escape general strings.
- OS << Indent << "if (" << StrVariableName << ".substr(" << CharNo << ", "
- << NumChars << ") != \"";
- OS << Matches[0]->first.substr(CharNo, NumChars) << "\")\n";
- OS << Indent << " break;\n";
- }
-
- return EmitStringMatcherForChar(Matches, FirstNonCommonLetter, IndentCount);
- }
-
- // Otherwise, we have multiple possible things, emit a switch on the
- // character.
- OS << Indent << "switch (" << StrVariableName << "[" << CharNo << "]) {\n";
- OS << Indent << "default: break;\n";
-
- for (std::map<char, std::vector<const StringPair*> >::iterator LI =
- MatchesByLetter.begin(), E = MatchesByLetter.end(); LI != E; ++LI) {
- // TODO: escape hard stuff (like \n) if we ever care about it.
- OS << Indent << "case '" << LI->first << "':\t // "
- << LI->second.size() << " string";
- if (LI->second.size() != 1) OS << 's';
- OS << " to match.\n";
- if (EmitStringMatcherForChar(LI->second, CharNo+1, IndentCount+1))
- OS << Indent << " break;\n";
- }
-
- OS << Indent << "}\n";
- return true;
-}
-
-
-/// Emit - Top level entry point.
-///
-void StringMatcher::Emit(unsigned Indent) const {
- // If nothing to match, just fall through.
- if (Matches.empty()) return;
-
- // First level categorization: group strings by length.
- std::map<unsigned, std::vector<const StringPair*> > MatchesByLength;
-
- for (unsigned i = 0, e = Matches.size(); i != e; ++i)
- MatchesByLength[Matches[i].first.size()].push_back(&Matches[i]);
-
- // Output a switch statement on length and categorize the elements within each
- // bin.
- OS.indent(Indent*2+2) << "switch (" << StrVariableName << ".size()) {\n";
- OS.indent(Indent*2+2) << "default: break;\n";
-
- for (std::map<unsigned, std::vector<const StringPair*> >::iterator LI =
- MatchesByLength.begin(), E = MatchesByLength.end(); LI != E; ++LI) {
- OS.indent(Indent*2+2) << "case " << LI->first << ":\t // "
- << LI->second.size()
- << " string" << (LI->second.size() == 1 ? "" : "s") << " to match.\n";
- if (EmitStringMatcherForChar(LI->second, 0, Indent))
- OS.indent(Indent*2+4) << "break;\n";
- }
-
- OS.indent(Indent*2+2) << "}\n";
-}
diff --git a/utils/TableGen/StringMatcher.h b/utils/TableGen/StringMatcher.h
deleted file mode 100644
index 1dadc76200b0..000000000000
--- a/utils/TableGen/StringMatcher.h
+++ /dev/null
@@ -1,54 +0,0 @@
-//===- StringMatcher.h - Generate a matcher for input strings ---*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements the StringMatcher class.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef STRINGMATCHER_H
-#define STRINGMATCHER_H
-
-#include <vector>
-#include <string>
-#include <utility>
-#include "llvm/ADT/StringRef.h"
-
-namespace llvm {
- class raw_ostream;
-
-/// StringMatcher - Given a list of strings and code to execute when they match,
-/// output a simple switch tree to classify the input string.
-///
-/// If a match is found, the code in Vals[i].second is executed; control must
-/// not exit this code fragment. If nothing matches, execution falls through.
-///
-class StringMatcher {
-public:
- typedef std::pair<std::string, std::string> StringPair;
-private:
- StringRef StrVariableName;
- const std::vector<StringPair> &Matches;
- raw_ostream &OS;
-
-public:
- StringMatcher(StringRef strVariableName,
- const std::vector<StringPair> &matches, raw_ostream &os)
- : StrVariableName(strVariableName), Matches(matches), OS(os) {}
-
- void Emit(unsigned Indent = 0) const;
-
-
-private:
- bool EmitStringMatcherForChar(const std::vector<const StringPair*> &Matches,
- unsigned CharNo, unsigned IndentCount) const;
-};
-
-} // end llvm namespace.
-
-#endif
diff --git a/utils/TableGen/StringToOffsetTable.h b/utils/TableGen/StringToOffsetTable.h
index 803f5bd5cf01..a098d7d744a1 100644
--- a/utils/TableGen/StringToOffsetTable.h
+++ b/utils/TableGen/StringToOffsetTable.h
@@ -14,6 +14,7 @@
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/raw_ostream.h"
+#include <cctype>
namespace llvm {
diff --git a/utils/TableGen/SubtargetEmitter.cpp b/utils/TableGen/SubtargetEmitter.cpp
index 986c50f87865..34723439596e 100644
--- a/utils/TableGen/SubtargetEmitter.cpp
+++ b/utils/TableGen/SubtargetEmitter.cpp
@@ -11,14 +11,60 @@
//
//===----------------------------------------------------------------------===//
-#include "SubtargetEmitter.h"
#include "CodeGenTarget.h"
-#include "llvm/TableGen/Record.h"
+#include "CodeGenSchedule.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/MC/MCInstrItineraries.h"
#include "llvm/Support/Debug.h"
+#include "llvm/TableGen/Record.h"
+#include "llvm/TableGen/TableGenBackend.h"
#include <algorithm>
+#include <map>
+#include <string>
+#include <vector>
using namespace llvm;
+namespace {
+class SubtargetEmitter {
+
+ RecordKeeper &Records;
+ CodeGenSchedModels &SchedModels;
+ std::string Target;
+
+ void Enumeration(raw_ostream &OS, const char *ClassName, bool isBits);
+ unsigned FeatureKeyValues(raw_ostream &OS);
+ unsigned CPUKeyValues(raw_ostream &OS);
+ void FormItineraryStageString(const std::string &Names,
+ Record *ItinData, std::string &ItinString,
+ unsigned &NStages);
+ void FormItineraryOperandCycleString(Record *ItinData, std::string &ItinString,
+ unsigned &NOperandCycles);
+ void FormItineraryBypassString(const std::string &Names,
+ Record *ItinData,
+ std::string &ItinString, unsigned NOperandCycles);
+ void EmitStageAndOperandCycleData(raw_ostream &OS,
+ std::vector<std::vector<InstrItinerary> >
+ &ProcItinLists);
+ void EmitItineraries(raw_ostream &OS,
+ std::vector<std::vector<InstrItinerary> >
+ &ProcItinLists);
+ void EmitProcessorProp(raw_ostream &OS, const Record *R, const char *Name,
+ char Separator);
+ void EmitProcessorModels(raw_ostream &OS);
+ void EmitProcessorLookup(raw_ostream &OS);
+ void EmitSchedModel(raw_ostream &OS);
+ void ParseFeaturesFunction(raw_ostream &OS, unsigned NumFeatures,
+ unsigned NumProcs);
+
+public:
+ SubtargetEmitter(RecordKeeper &R, CodeGenTarget &TGT):
+ Records(R), SchedModels(TGT.getSchedModels()), Target(TGT.getName()) {}
+
+ void run(raw_ostream &o);
+
+};
+} // End anonymous namespace
+
//
// Enumeration - Emit the specified class as an enumeration.
//
@@ -196,28 +242,6 @@ unsigned SubtargetEmitter::CPUKeyValues(raw_ostream &OS) {
}
//
-// CollectAllItinClasses - Gathers and enumerates all the itinerary classes.
-// Returns itinerary class count.
-//
-unsigned SubtargetEmitter::
-CollectAllItinClasses(raw_ostream &OS,
- std::map<std::string, unsigned> &ItinClassesMap,
- std::vector<Record*> &ItinClassList) {
- // For each itinerary class
- unsigned N = ItinClassList.size();
- for (unsigned i = 0; i < N; i++) {
- // Next itinerary class
- const Record *ItinClass = ItinClassList[i];
- // Get name of itinerary class
- // Assign itinerary class a unique number
- ItinClassesMap[ItinClass->getName()] = i;
- }
-
- // Return itinerary class count
- return N;
-}
-
-//
// FormItineraryStageString - Compose a string containing the stage
// data initialization for the specified itinerary. N is the number
// of stages.
@@ -303,32 +327,31 @@ void SubtargetEmitter::FormItineraryBypassString(const std::string &Name,
}
//
-// EmitStageAndOperandCycleData - Generate unique itinerary stages and
-// operand cycle tables. Record itineraries for processors.
+// EmitStageAndOperandCycleData - Generate unique itinerary stages and operand
+// cycle tables. Create a list of InstrItinerary objects (ProcItinLists) indexed
+// by CodeGenSchedClass::Index.
//
-void SubtargetEmitter::EmitStageAndOperandCycleData(raw_ostream &OS,
- unsigned NItinClasses,
- std::map<std::string, unsigned> &ItinClassesMap,
- std::vector<Record*> &ItinClassList,
- std::vector<std::vector<InstrItinerary> > &ProcList) {
- // Gather processor iteraries
- std::vector<Record*> ProcItinList =
- Records.getAllDerivedDefinitions("ProcessorItineraries");
-
- // If just no itinerary then don't bother
- if (ProcItinList.size() < 2) return;
+void SubtargetEmitter::
+EmitStageAndOperandCycleData(raw_ostream &OS,
+ std::vector<std::vector<InstrItinerary> >
+ &ProcItinLists) {
+
+ // Multiple processor models may share an itinerary record. Emit it once.
+ SmallPtrSet<Record*, 8> ItinsDefSet;
// Emit functional units for all the itineraries.
- for (unsigned i = 0, N = ProcItinList.size(); i < N; ++i) {
- // Next record
- Record *Proc = ProcItinList[i];
+ for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(),
+ PE = SchedModels.procModelEnd(); PI != PE; ++PI) {
+
+ if (!ItinsDefSet.insert(PI->ItinsDef))
+ continue;
- std::vector<Record*> FUs = Proc->getValueAsListOfDefs("FU");
+ std::vector<Record*> FUs = PI->ItinsDef->getValueAsListOfDefs("FU");
if (FUs.empty())
continue;
- const std::string &Name = Proc->getName();
- OS << "\n// Functional units for itineraries \"" << Name << "\"\n"
+ const std::string &Name = PI->ItinsDef->getName();
+ OS << "\n// Functional units for \"" << Name << "\"\n"
<< "namespace " << Name << "FU {\n";
for (unsigned j = 0, FUN = FUs.size(); j < FUN; ++j)
@@ -337,7 +360,7 @@ void SubtargetEmitter::EmitStageAndOperandCycleData(raw_ostream &OS,
OS << "}\n";
- std::vector<Record*> BPs = Proc->getValueAsListOfDefs("BP");
+ std::vector<Record*> BPs = PI->ItinsDef->getValueAsListOfDefs("BP");
if (BPs.size()) {
OS << "\n// Pipeline forwarding pathes for itineraries \"" << Name
<< "\"\n" << "namespace " << Name << "Bypass {\n";
@@ -363,47 +386,57 @@ void SubtargetEmitter::EmitStageAndOperandCycleData(raw_ostream &OS,
// Begin pipeline bypass table
std::string BypassTable = "extern const unsigned " + Target +
- "ForwardingPathes[] = {\n";
- BypassTable += " 0, // No itinerary\n";
+ "ForwardingPaths[] = {\n";
+ BypassTable += " 0, // No itinerary\n";
+ // For each Itinerary across all processors, add a unique entry to the stages,
+ // operand cycles, and pipepine bypess tables. Then add the new Itinerary
+ // object with computed offsets to the ProcItinLists result.
unsigned StageCount = 1, OperandCycleCount = 1;
std::map<std::string, unsigned> ItinStageMap, ItinOperandMap;
- for (unsigned i = 0, N = ProcItinList.size(); i < N; i++) {
- // Next record
- Record *Proc = ProcItinList[i];
+ for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(),
+ PE = SchedModels.procModelEnd(); PI != PE; ++PI) {
+ const CodeGenProcModel &ProcModel = *PI;
- // Get processor itinerary name
- const std::string &Name = Proc->getName();
+ // Add process itinerary to the list.
+ ProcItinLists.resize(ProcItinLists.size()+1);
- // Skip default
- if (Name == "NoItineraries") continue;
+ // If this processor defines no itineraries, then leave the itinerary list
+ // empty.
+ std::vector<InstrItinerary> &ItinList = ProcItinLists.back();
+ if (ProcModel.ItinDefList.empty())
+ continue;
- // Create and expand processor itinerary to cover all itinerary classes
- std::vector<InstrItinerary> ItinList;
- ItinList.resize(NItinClasses);
+ // Reserve index==0 for NoItinerary.
+ ItinList.resize(SchedModels.numItineraryClasses()+1);
- // Get itinerary data list
- std::vector<Record*> ItinDataList = Proc->getValueAsListOfDefs("IID");
+ const std::string &Name = ProcModel.ItinsDef->getName();
// For each itinerary data
- for (unsigned j = 0, M = ItinDataList.size(); j < M; j++) {
+ for (unsigned SchedClassIdx = 0,
+ SchedClassEnd = ProcModel.ItinDefList.size();
+ SchedClassIdx < SchedClassEnd; ++SchedClassIdx) {
+
// Next itinerary data
- Record *ItinData = ItinDataList[j];
+ Record *ItinData = ProcModel.ItinDefList[SchedClassIdx];
// Get string and stage count
std::string ItinStageString;
- unsigned NStages;
- FormItineraryStageString(Name, ItinData, ItinStageString, NStages);
+ unsigned NStages = 0;
+ if (ItinData)
+ FormItineraryStageString(Name, ItinData, ItinStageString, NStages);
// Get string and operand cycle count
std::string ItinOperandCycleString;
- unsigned NOperandCycles;
- FormItineraryOperandCycleString(ItinData, ItinOperandCycleString,
- NOperandCycles);
-
+ unsigned NOperandCycles = 0;
std::string ItinBypassString;
- FormItineraryBypassString(Name, ItinData, ItinBypassString,
- NOperandCycles);
+ if (ItinData) {
+ FormItineraryOperandCycleString(ItinData, ItinOperandCycleString,
+ NOperandCycles);
+
+ FormItineraryBypassString(Name, ItinData, ItinBypassString,
+ NOperandCycles);
+ }
// Check to see if stage already exists and create if it doesn't
unsigned FindStage = 0;
@@ -443,33 +476,26 @@ void SubtargetEmitter::EmitStageAndOperandCycleData(raw_ostream &OS,
}
}
- // Locate where to inject into processor itinerary table
- const std::string &Name = ItinData->getValueAsDef("TheClass")->getName();
- unsigned Find = ItinClassesMap[Name];
-
// Set up itinerary as location and location + stage count
- unsigned NumUOps = ItinClassList[Find]->getValueAsInt("NumMicroOps");
+ int NumUOps = ItinData ? ItinData->getValueAsInt("NumMicroOps") : 0;
InstrItinerary Intinerary = { NumUOps, FindStage, FindStage + NStages,
FindOperandCycle,
FindOperandCycle + NOperandCycles};
// Inject - empty slots will be 0, 0
- ItinList[Find] = Intinerary;
+ ItinList[SchedClassIdx] = Intinerary;
}
-
- // Add process itinerary to list
- ProcList.push_back(ItinList);
}
// Closing stage
- StageTable += " { 0, 0, 0, llvm::InstrStage::Required } // End itinerary\n";
+ StageTable += " { 0, 0, 0, llvm::InstrStage::Required } // End stages\n";
StageTable += "};\n";
// Closing operand cycles
- OperandCycleTable += " 0 // End itinerary\n";
+ OperandCycleTable += " 0 // End operand cycles\n";
OperandCycleTable += "};\n";
- BypassTable += " 0 // End itinerary\n";
+ BypassTable += " 0 // End bypass tables\n";
BypassTable += "};\n";
// Emit tables.
@@ -479,61 +505,100 @@ void SubtargetEmitter::EmitStageAndOperandCycleData(raw_ostream &OS,
}
//
-// EmitProcessorData - Generate data for processor itineraries.
+// EmitProcessorData - Generate data for processor itineraries that were
+// computed during EmitStageAndOperandCycleData(). ProcItinLists lists all
+// Itineraries for each processor. The Itinerary lists are indexed on
+// CodeGenSchedClass::Index.
//
void SubtargetEmitter::
-EmitProcessorData(raw_ostream &OS,
- std::vector<Record*> &ItinClassList,
- std::vector<std::vector<InstrItinerary> > &ProcList) {
- // Get an iterator for processor itinerary stages
+EmitItineraries(raw_ostream &OS,
+ std::vector<std::vector<InstrItinerary> > &ProcItinLists) {
+
+ // Multiple processor models may share an itinerary record. Emit it once.
+ SmallPtrSet<Record*, 8> ItinsDefSet;
+
+ // For each processor's machine model
std::vector<std::vector<InstrItinerary> >::iterator
- ProcListIter = ProcList.begin();
+ ProcItinListsIter = ProcItinLists.begin();
+ for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(),
+ PE = SchedModels.procModelEnd(); PI != PE; ++PI) {
- // For each processor itinerary
- std::vector<Record*> Itins =
- Records.getAllDerivedDefinitions("ProcessorItineraries");
- for (unsigned i = 0, N = Itins.size(); i < N; i++) {
- // Next record
- Record *Itin = Itins[i];
+ Record *ItinsDef = PI->ItinsDef;
+ if (!ItinsDefSet.insert(ItinsDef))
+ continue;
// Get processor itinerary name
- const std::string &Name = Itin->getName();
+ const std::string &Name = ItinsDef->getName();
- // Skip default
- if (Name == "NoItineraries") continue;
+ // Get the itinerary list for the processor.
+ assert(ProcItinListsIter != ProcItinLists.end() && "bad iterator");
+ std::vector<InstrItinerary> &ItinList = *ProcItinListsIter++;
- // Begin processor itinerary table
OS << "\n";
- OS << "static const llvm::InstrItinerary " << Name << "[] = {\n";
+ OS << "static const llvm::InstrItinerary ";
+ if (ItinList.empty()) {
+ OS << '*' << Name << " = 0;\n";
+ continue;
+ }
- // For each itinerary class
- std::vector<InstrItinerary> &ItinList = *ProcListIter++;
- assert(ItinList.size() == ItinClassList.size() && "bad itinerary");
+ // Begin processor itinerary table
+ OS << Name << "[] = {\n";
+
+ // For each itinerary class in CodeGenSchedClass::Index order.
for (unsigned j = 0, M = ItinList.size(); j < M; ++j) {
InstrItinerary &Intinerary = ItinList[j];
- // Emit in the form of
+ // Emit Itinerary in the form of
// { firstStage, lastStage, firstCycle, lastCycle } // index
- if (Intinerary.FirstStage == 0) {
- OS << " { 1, 0, 0, 0, 0 }";
- } else {
- OS << " { " <<
- Intinerary.NumMicroOps << ", " <<
- Intinerary.FirstStage << ", " <<
- Intinerary.LastStage << ", " <<
- Intinerary.FirstOperandCycle << ", " <<
- Intinerary.LastOperandCycle << " }";
- }
-
- OS << ", // " << j << " " << ItinClassList[j]->getName() << "\n";
+ OS << " { " <<
+ Intinerary.NumMicroOps << ", " <<
+ Intinerary.FirstStage << ", " <<
+ Intinerary.LastStage << ", " <<
+ Intinerary.FirstOperandCycle << ", " <<
+ Intinerary.LastOperandCycle << " }" <<
+ ", // " << j << " " << SchedModels.getSchedClass(j).Name << "\n";
}
-
// End processor itinerary table
- OS << " { 1, ~0U, ~0U, ~0U, ~0U } // end marker\n";
+ OS << " { 0, ~0U, ~0U, ~0U, ~0U } // end marker\n";
OS << "};\n";
}
}
+// Emit either the value defined in the TableGen Record, or the default
+// value defined in the C++ header. The Record is null if the processor does not
+// define a model.
+void SubtargetEmitter::EmitProcessorProp(raw_ostream &OS, const Record *R,
+ const char *Name, char Separator) {
+ OS << " ";
+ int V = R ? R->getValueAsInt(Name) : -1;
+ if (V >= 0)
+ OS << V << Separator << " // " << Name;
+ else
+ OS << "MCSchedModel::Default" << Name << Separator;
+ OS << '\n';
+}
+
+void SubtargetEmitter::EmitProcessorModels(raw_ostream &OS) {
+ // For each processor model.
+ for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(),
+ PE = SchedModels.procModelEnd(); PI != PE; ++PI) {
+ // Skip default
+ // Begin processor itinerary properties
+ OS << "\n";
+ OS << "static const llvm::MCSchedModel " << PI->ModelName << "(\n";
+ EmitProcessorProp(OS, PI->ModelDef, "IssueWidth", ',');
+ EmitProcessorProp(OS, PI->ModelDef, "MinLatency", ',');
+ EmitProcessorProp(OS, PI->ModelDef, "LoadLatency", ',');
+ EmitProcessorProp(OS, PI->ModelDef, "HighLatency", ',');
+ EmitProcessorProp(OS, PI->ModelDef, "MispredictPenalty", ',');
+ if (SchedModels.hasItineraryClasses())
+ OS << " " << PI->ItinsDef->getName();
+ else
+ OS << " 0";
+ OS << ");\n";
+ }
+}
+
//
// EmitProcessorLookup - generate cpu name to itinerary lookup table.
//
@@ -547,7 +612,7 @@ void SubtargetEmitter::EmitProcessorLookup(raw_ostream &OS) {
OS << "\n";
OS << "// Sorted (by key) array of itineraries for CPU subtype.\n"
<< "extern const llvm::SubtargetInfoKV "
- << Target << "ProcItinKV[] = {\n";
+ << Target << "ProcSchedKV[] = {\n";
// For each processor
for (unsigned i = 0, N = ProcessorList.size(); i < N;) {
@@ -555,13 +620,13 @@ void SubtargetEmitter::EmitProcessorLookup(raw_ostream &OS) {
Record *Processor = ProcessorList[i];
const std::string &Name = Processor->getValueAsString("Name");
- const std::string &ProcItin =
- Processor->getValueAsDef("ProcItin")->getName();
+ const std::string &ProcModelName =
+ SchedModels.getProcModel(Processor).ModelName;
// Emit as { "cpu", procinit },
OS << " { "
<< "\"" << Name << "\", "
- << "(void *)&" << ProcItin;
+ << "(void *)&" << ProcModelName;
OS << " }";
@@ -576,31 +641,19 @@ void SubtargetEmitter::EmitProcessorLookup(raw_ostream &OS) {
}
//
-// EmitData - Emits all stages and itineries, folding common patterns.
+// EmitSchedModel - Emits all scheduling model tables, folding common patterns.
//
-void SubtargetEmitter::EmitData(raw_ostream &OS) {
- std::map<std::string, unsigned> ItinClassesMap;
- // Gather and sort all itinerary classes
- std::vector<Record*> ItinClassList =
- Records.getAllDerivedDefinitions("InstrItinClass");
- std::sort(ItinClassList.begin(), ItinClassList.end(), LessRecord());
-
- // Enumerate all the itinerary classes
- unsigned NItinClasses = CollectAllItinClasses(OS, ItinClassesMap,
- ItinClassList);
- // Make sure the rest is worth the effort
- HasItineraries = NItinClasses != 1; // Ignore NoItinerary.
-
- if (HasItineraries) {
- std::vector<std::vector<InstrItinerary> > ProcList;
+void SubtargetEmitter::EmitSchedModel(raw_ostream &OS) {
+ if (SchedModels.hasItineraryClasses()) {
+ std::vector<std::vector<InstrItinerary> > ProcItinLists;
// Emit the stage data
- EmitStageAndOperandCycleData(OS, NItinClasses, ItinClassesMap,
- ItinClassList, ProcList);
- // Emit the processor itinerary data
- EmitProcessorData(OS, ItinClassList, ProcList);
- // Emit the processor lookup data
- EmitProcessorLookup(OS);
+ EmitStageAndOperandCycleData(OS, ProcItinLists);
+ EmitItineraries(OS, ProcItinLists);
}
+ // Emit the processor machine model
+ EmitProcessorModels(OS);
+ // Emit the processor lookup data
+ EmitProcessorLookup(OS);
}
//
@@ -620,7 +673,7 @@ void SubtargetEmitter::ParseFeaturesFunction(raw_ostream &OS,
OS << Target;
OS << "Subtarget::ParseSubtargetFeatures(StringRef CPU, StringRef FS) {\n"
<< " DEBUG(dbgs() << \"\\nFeatures:\" << FS);\n"
- << " DEBUG(dbgs() << \"\\nCPU:\" << CPU);\n";
+ << " DEBUG(dbgs() << \"\\nCPU:\" << CPU << \"\\n\\n\");\n";
if (Features.empty()) {
OS << "}\n";
@@ -654,9 +707,7 @@ void SubtargetEmitter::ParseFeaturesFunction(raw_ostream &OS,
// SubtargetEmitter::run - Main subtarget enumeration emitter.
//
void SubtargetEmitter::run(raw_ostream &OS) {
- Target = CodeGenTarget(Records).getName();
-
- EmitSourceFileHeader("Subtarget Enumeration Source Fragment", OS);
+ emitSourceFileHeader("Subtarget Enumeration Source Fragment", OS);
OS << "\n#ifdef GET_SUBTARGETINFO_ENUM\n";
OS << "#undef GET_SUBTARGETINFO_ENUM\n";
@@ -677,7 +728,7 @@ void SubtargetEmitter::run(raw_ostream &OS) {
OS << "\n";
unsigned NumProcs = CPUKeyValues(OS);
OS << "\n";
- EmitData(OS);
+ EmitSchedModel(OS);
OS << "\n";
#if 0
OS << "}\n";
@@ -696,11 +747,11 @@ void SubtargetEmitter::run(raw_ostream &OS) {
OS << Target << "SubTypeKV, ";
else
OS << "0, ";
- if (HasItineraries) {
- OS << Target << "ProcItinKV, "
+ if (SchedModels.hasItineraryClasses()) {
+ OS << Target << "ProcSchedKV, "
<< Target << "Stages, "
<< Target << "OperandCycles, "
- << Target << "ForwardingPathes, ";
+ << Target << "ForwardingPaths, ";
} else
OS << "0, 0, 0, 0, ";
OS << NumFeatures << ", " << NumProcs << ");\n}\n\n";
@@ -742,11 +793,11 @@ void SubtargetEmitter::run(raw_ostream &OS) {
OS << "namespace llvm {\n";
OS << "extern const llvm::SubtargetFeatureKV " << Target << "FeatureKV[];\n";
OS << "extern const llvm::SubtargetFeatureKV " << Target << "SubTypeKV[];\n";
- if (HasItineraries) {
- OS << "extern const llvm::SubtargetInfoKV " << Target << "ProcItinKV[];\n";
+ if (SchedModels.hasItineraryClasses()) {
+ OS << "extern const llvm::SubtargetInfoKV " << Target << "ProcSchedKV[];\n";
OS << "extern const llvm::InstrStage " << Target << "Stages[];\n";
OS << "extern const unsigned " << Target << "OperandCycles[];\n";
- OS << "extern const unsigned " << Target << "ForwardingPathes[];\n";
+ OS << "extern const unsigned " << Target << "ForwardingPaths[];\n";
}
OS << ClassName << "::" << ClassName << "(StringRef TT, StringRef CPU, "
@@ -761,11 +812,11 @@ void SubtargetEmitter::run(raw_ostream &OS) {
OS << Target << "SubTypeKV, ";
else
OS << "0, ";
- if (HasItineraries) {
- OS << Target << "ProcItinKV, "
+ if (SchedModels.hasItineraryClasses()) {
+ OS << Target << "ProcSchedKV, "
<< Target << "Stages, "
<< Target << "OperandCycles, "
- << Target << "ForwardingPathes, ";
+ << Target << "ForwardingPaths, ";
} else
OS << "0, 0, 0, 0, ";
OS << NumFeatures << ", " << NumProcs << ");\n}\n\n";
@@ -773,3 +824,12 @@ void SubtargetEmitter::run(raw_ostream &OS) {
OS << "#endif // GET_SUBTARGETINFO_CTOR\n\n";
}
+
+namespace llvm {
+
+void EmitSubtarget(RecordKeeper &RK, raw_ostream &OS) {
+ CodeGenTarget CGTarget(RK);
+ SubtargetEmitter(RK, CGTarget).run(OS);
+}
+
+} // End llvm namespace
diff --git a/utils/TableGen/SubtargetEmitter.h b/utils/TableGen/SubtargetEmitter.h
deleted file mode 100644
index ff01274bd1a7..000000000000
--- a/utils/TableGen/SubtargetEmitter.h
+++ /dev/null
@@ -1,72 +0,0 @@
-//===- SubtargetEmitter.h - Generate subtarget enumerations -----*- 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 emits subtarget enumerations.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef SUBTARGET_EMITTER_H
-#define SUBTARGET_EMITTER_H
-
-#include "llvm/TableGen/TableGenBackend.h"
-#include "llvm/MC/MCInstrItineraries.h"
-#include <vector>
-#include <map>
-#include <string>
-
-
-namespace llvm {
-
-class SubtargetEmitter : public TableGenBackend {
-
- RecordKeeper &Records;
- std::string Target;
- bool HasItineraries;
-
- void Enumeration(raw_ostream &OS, const char *ClassName, bool isBits);
- unsigned FeatureKeyValues(raw_ostream &OS);
- unsigned CPUKeyValues(raw_ostream &OS);
- unsigned CollectAllItinClasses(raw_ostream &OS,
- std::map<std::string,unsigned> &ItinClassesMap,
- std::vector<Record*> &ItinClassList);
- void FormItineraryStageString(const std::string &Names,
- Record *ItinData, std::string &ItinString,
- unsigned &NStages);
- void FormItineraryOperandCycleString(Record *ItinData, std::string &ItinString,
- unsigned &NOperandCycles);
- void FormItineraryBypassString(const std::string &Names,
- Record *ItinData,
- std::string &ItinString, unsigned NOperandCycles);
- void EmitStageAndOperandCycleData(raw_ostream &OS, unsigned NItinClasses,
- std::map<std::string, unsigned> &ItinClassesMap,
- std::vector<Record*> &ItinClassList,
- std::vector<std::vector<InstrItinerary> > &ProcList);
- void EmitProcessorData(raw_ostream &OS,
- std::vector<Record*> &ItinClassList,
- std::vector<std::vector<InstrItinerary> > &ProcList);
- void EmitProcessorLookup(raw_ostream &OS);
- void EmitData(raw_ostream &OS);
- void ParseFeaturesFunction(raw_ostream &OS, unsigned NumFeatures,
- unsigned NumProcs);
-
-public:
- SubtargetEmitter(RecordKeeper &R) : Records(R), HasItineraries(false) {}
-
- // run - Output the subtarget enumerations, returning true on failure.
- void run(raw_ostream &o);
-
-};
-
-
-} // End llvm namespace
-
-#endif
-
-
-
diff --git a/utils/TableGen/TableGen.cpp b/utils/TableGen/TableGen.cpp
index 8c41358e3d85..9695b4a351c7 100644
--- a/utils/TableGen/TableGen.cpp
+++ b/utils/TableGen/TableGen.cpp
@@ -11,22 +11,9 @@
//
//===----------------------------------------------------------------------===//
-#include "AsmMatcherEmitter.h"
-#include "AsmWriterEmitter.h"
-#include "CallingConvEmitter.h"
-#include "CodeEmitterGen.h"
-#include "DAGISelEmitter.h"
-#include "DFAPacketizerEmitter.h"
-#include "DisassemblerEmitter.h"
-#include "EDEmitter.h"
-#include "FastISelEmitter.h"
-#include "InstrInfoEmitter.h"
-#include "IntrinsicEmitter.h"
-#include "PseudoLoweringEmitter.h"
-#include "RegisterInfoEmitter.h"
-#include "SubtargetEmitter.h"
-#include "SetTheory.h"
+#include "TableGenBackends.h" // Declares all backends.
+#include "SetTheory.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Signals.h"
@@ -102,7 +89,7 @@ namespace {
cl::opt<std::string>
Class("class", cl::desc("Print Enum list for this class"),
cl::value_desc("class name"));
-
+
class LLVMTableGenAction : public TableGenAction {
public:
bool operator()(raw_ostream &OS, RecordKeeper &Records) {
@@ -111,49 +98,49 @@ namespace {
OS << Records; // No argument, dump all contents
break;
case GenEmitter:
- CodeEmitterGen(Records).run(OS);
+ EmitCodeEmitter(Records, OS);
break;
case GenRegisterInfo:
- RegisterInfoEmitter(Records).run(OS);
+ EmitRegisterInfo(Records, OS);
break;
case GenInstrInfo:
- InstrInfoEmitter(Records).run(OS);
+ EmitInstrInfo(Records, OS);
break;
case GenCallingConv:
- CallingConvEmitter(Records).run(OS);
+ EmitCallingConv(Records, OS);
break;
case GenAsmWriter:
- AsmWriterEmitter(Records).run(OS);
+ EmitAsmWriter(Records, OS);
break;
case GenAsmMatcher:
- AsmMatcherEmitter(Records).run(OS);
+ EmitAsmMatcher(Records, OS);
break;
case GenDisassembler:
- DisassemblerEmitter(Records).run(OS);
+ EmitDisassembler(Records, OS);
break;
case GenPseudoLowering:
- PseudoLoweringEmitter(Records).run(OS);
+ EmitPseudoLowering(Records, OS);
break;
case GenDAGISel:
- DAGISelEmitter(Records).run(OS);
+ EmitDAGISel(Records, OS);
break;
case GenDFAPacketizer:
- DFAGen(Records).run(OS);
+ EmitDFAPacketizer(Records, OS);
break;
case GenFastISel:
- FastISelEmitter(Records).run(OS);
+ EmitFastISel(Records, OS);
break;
case GenSubtarget:
- SubtargetEmitter(Records).run(OS);
+ EmitSubtarget(Records, OS);
break;
case GenIntrinsic:
- IntrinsicEmitter(Records).run(OS);
+ EmitIntrinsics(Records, OS);
break;
case GenTgtIntrinsic:
- IntrinsicEmitter(Records, true).run(OS);
+ EmitIntrinsics(Records, OS, true);
break;
case GenEDInfo:
- EDEmitter(Records).run(OS);
+ EmitEnhancedDisassemblerInfo(Records, OS);
break;
case PrintEnums:
{
@@ -179,7 +166,7 @@ namespace {
break;
}
}
-
+
return false;
}
};
diff --git a/utils/TableGen/TableGenBackends.h b/utils/TableGen/TableGenBackends.h
new file mode 100644
index 000000000000..2c00c40cfef9
--- /dev/null
+++ b/utils/TableGen/TableGenBackends.h
@@ -0,0 +1,78 @@
+//===- TableGenBackends.h - Declarations for LLVM TableGen Backends -------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the declarations for all of the LLVM TableGen
+// backends. A "TableGen backend" is just a function. See below for a
+// precise description.
+//
+//===----------------------------------------------------------------------===//
+
+
+// A TableGen backend is a function that looks like
+//
+// EmitFoo(RecordKeeper &RK, raw_ostream &OS /*, anything else you need */ )
+//
+// What you do inside of that function is up to you, but it will usually
+// involve generating C++ code to the provided raw_ostream.
+//
+// The RecordKeeper is just a top-level container for an in-memory
+// representation of the data encoded in the TableGen file. What a TableGen
+// backend does is walk around that in-memory representation and generate
+// stuff based on the information it contains.
+//
+// The in-memory representation is a node-graph (think of it like JSON but
+// with a richer ontology of types), where the nodes are subclasses of
+// Record. The methods `getClass`, `getDef` are the basic interface to
+// access the node-graph. RecordKeeper also provides a handy method
+// `getAllDerivedDefinitions`. Consult "include/llvm/TableGen/Record.h" for
+// the exact interfaces provided by Record's and RecordKeeper.
+//
+// A common pattern for TableGen backends is for the EmitFoo function to
+// instantiate a class which holds some context for the generation process,
+// and then have most of the work happen in that class's methods. This
+// pattern partly has historical roots in the previous TableGen backend API
+// that involved a class and an invocation like `FooEmitter(RK).run(OS)`.
+//
+// Remember to wrap private things in an anonymous namespace. For most
+// backends, this means that the EmitFoo function is the only thing not in
+// the anonymous namespace.
+
+
+// FIXME: Reorganize TableGen so that build dependencies can be more
+// accurately expressed. Currently, touching any of the emitters (or
+// anything that they transitively depend on) causes everything dependent
+// on TableGen to be rebuilt (this includes all the targets!). Perhaps have
+// a standalone TableGen binary and have the backends be loadable modules
+// of some sort; then the dependency could be expressed as being on the
+// module, and all the modules would have a common dependency on the
+// TableGen binary with as few dependencies as possible on the rest of
+// LLVM.
+
+
+namespace llvm {
+
+class raw_ostream;
+class RecordKeeper;
+
+void EmitIntrinsics(RecordKeeper &RK, raw_ostream &OS, bool TargetOnly = false);
+void EmitAsmMatcher(RecordKeeper &RK, raw_ostream &OS);
+void EmitAsmWriter(RecordKeeper &RK, raw_ostream &OS);
+void EmitCallingConv(RecordKeeper &RK, raw_ostream &OS);
+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);
+
+} // End llvm namespace
diff --git a/utils/TableGen/X86DisassemblerShared.h b/utils/TableGen/X86DisassemblerShared.h
index 0417e9dece40..c13a0cc467e1 100644
--- a/utils/TableGen/X86DisassemblerShared.h
+++ b/utils/TableGen/X86DisassemblerShared.h
@@ -14,6 +14,7 @@
#include <string.h>
#define INSTRUCTION_SPECIFIER_FIELDS \
+ struct OperandSpecifier operands[X86_MAX_OPERANDS]; \
bool filtered; \
InstructionContext insnContext; \
std::string name; \
diff --git a/utils/TableGen/X86DisassemblerTables.cpp b/utils/TableGen/X86DisassemblerTables.cpp
index 2875168a1083..f3bd373708f7 100644
--- a/utils/TableGen/X86DisassemblerTables.cpp
+++ b/utils/TableGen/X86DisassemblerTables.cpp
@@ -21,10 +21,11 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Format.h"
+#include <map>
using namespace llvm;
using namespace X86Disassembler;
-
+
/// inheritsFrom - Indicates whether all instructions in one class also belong
/// to another class.
///
@@ -36,7 +37,7 @@ static inline bool inheritsFrom(InstructionContext child,
bool VEX_LIG = false) {
if (child == parent)
return true;
-
+
switch (parent) {
case IC:
return(inheritsFrom(child, IC_64BIT) ||
@@ -117,17 +118,17 @@ static inline bool inheritsFrom(InstructionContext child,
/// @param upper - The class that may be preferable
/// @param lower - The class that may be less preferable
/// @return - True if upper is to be preferred, false otherwise.
-static inline bool outranks(InstructionContext upper,
+static inline bool outranks(InstructionContext upper,
InstructionContext lower) {
assert(upper < IC_max);
assert(lower < IC_max);
-
+
#define ENUM_ENTRY(n, r, d) r,
static int ranks[IC_max] = {
INSTRUCTION_CONTEXTS
};
#undef ENUM_ENTRY
-
+
return (ranks[upper] > ranks[lower]);
}
@@ -170,24 +171,22 @@ static inline const char* stringForOperandEncoding(OperandEncoding encoding) {
}
}
-void DisassemblerTables::emitOneID(raw_ostream &o,
- uint32_t &i,
- InstrUID id,
+void DisassemblerTables::emitOneID(raw_ostream &o, unsigned &i, InstrUID id,
bool addComma) const {
if (id)
o.indent(i * 2) << format("0x%hx", id);
else
o.indent(i * 2) << 0;
-
+
if (addComma)
o << ", ";
else
o << " ";
-
+
o << "/* ";
o << InstructionSpecifiers[id].name;
o << "*/";
-
+
o << "\n";
}
@@ -197,8 +196,7 @@ void DisassemblerTables::emitOneID(raw_ostream &o,
///
/// @param o - The output stream on which to emit the table.
/// @param i - The indentation level for that output stream.
-static void emitEmptyTable(raw_ostream &o, uint32_t &i)
-{
+static void emitEmptyTable(raw_ostream &o, unsigned &i) {
o.indent(i * 2) << "0x0, /* EmptyTable */\n";
}
@@ -207,15 +205,12 @@ static void emitEmptyTable(raw_ostream &o, uint32_t &i)
///
/// @param decision - The decision to be compacted.
/// @return - The compactest available representation for the decision.
-static ModRMDecisionType getDecisionType(ModRMDecision &decision)
-{
+static ModRMDecisionType getDecisionType(ModRMDecision &decision) {
bool satisfiesOneEntry = true;
bool satisfiesSplitRM = true;
bool satisfiesSplitReg = true;
- uint16_t index;
-
- for (index = 0; index < 256; ++index) {
+ for (unsigned index = 0; index < 256; ++index) {
if (decision.instructionIDs[index] != decision.instructionIDs[0])
satisfiesOneEntry = false;
@@ -252,27 +247,25 @@ static ModRMDecisionType getDecisionType(ModRMDecision &decision)
/// to a particular decision type.
///
/// @param dt - The decision type.
-/// @return - A pointer to the statically-allocated string (e.g.,
+/// @return - A pointer to the statically-allocated string (e.g.,
/// "MODRM_ONEENTRY" for MODRM_ONEENTRY).
-static const char* stringForDecisionType(ModRMDecisionType dt)
-{
+static const char* stringForDecisionType(ModRMDecisionType dt) {
#define ENUM_ENTRY(n) case n: return #n;
switch (dt) {
default:
- llvm_unreachable("Unknown decision type");
+ llvm_unreachable("Unknown decision type");
MODRMTYPES
- };
+ };
#undef ENUM_ENTRY
}
-
+
/// stringForModifierType - Returns a statically-allocated string corresponding
/// to an opcode modifier type.
///
/// @param mt - The modifier type.
/// @return - A pointer to the statically-allocated string (e.g.,
/// "MODIFIER_NONE" for MODIFIER_NONE).
-static const char* stringForModifierType(ModifierType mt)
-{
+static const char* stringForModifierType(ModifierType mt) {
#define ENUM_ENTRY(n) case n: return #n;
switch(mt) {
default:
@@ -281,35 +274,31 @@ static const char* stringForModifierType(ModifierType mt)
};
#undef ENUM_ENTRY
}
-
+
DisassemblerTables::DisassemblerTables() {
unsigned i;
-
+
for (i = 0; i < array_lengthof(Tables); i++) {
Tables[i] = new ContextDecision;
memset(Tables[i], 0, sizeof(ContextDecision));
}
-
+
HasConflicts = false;
}
-
+
DisassemblerTables::~DisassemblerTables() {
unsigned i;
-
+
for (i = 0; i < array_lengthof(Tables); i++)
delete Tables[i];
}
-
-void DisassemblerTables::emitModRMDecision(raw_ostream &o1,
- raw_ostream &o2,
- uint32_t &i1,
- uint32_t &i2,
- ModRMDecision &decision)
- const {
- static uint64_t sTableNumber = 0;
- static uint64_t sEntryNumber = 1;
+
+void DisassemblerTables::emitModRMDecision(raw_ostream &o1, raw_ostream &o2,
+ unsigned &i1, unsigned &i2,
+ ModRMDecision &decision) const {
+ static uint32_t sTableNumber = 0;
+ static uint32_t sEntryNumber = 1;
ModRMDecisionType dt = getDecisionType(decision);
- uint16_t index;
if (dt == MODRM_ONEENTRY && decision.instructionIDs[0] == 0)
{
@@ -338,13 +327,13 @@ void DisassemblerTables::emitModRMDecision(raw_ostream &o1,
emitOneID(o1, i1, decision.instructionIDs[0xc0], true); // mod = 0b11
break;
case MODRM_SPLITREG:
- for (index = 0; index < 64; index += 8)
+ for (unsigned index = 0; index < 64; index += 8)
emitOneID(o1, i1, decision.instructionIDs[index], true);
- for (index = 0xc0; index < 256; index += 8)
+ for (unsigned index = 0xc0; index < 256; index += 8)
emitOneID(o1, i1, decision.instructionIDs[index], true);
break;
case MODRM_FULL:
- for (index = 0; index < 256; ++index)
+ for (unsigned index = 0; index < 256; ++index)
emitOneID(o1, i1, decision.instructionIDs[index], true);
break;
}
@@ -380,20 +369,15 @@ void DisassemblerTables::emitModRMDecision(raw_ostream &o1,
++sTableNumber;
}
-void DisassemblerTables::emitOpcodeDecision(
- raw_ostream &o1,
- raw_ostream &o2,
- uint32_t &i1,
- uint32_t &i2,
- OpcodeDecision &decision) const {
- uint16_t index;
-
+void DisassemblerTables::emitOpcodeDecision(raw_ostream &o1, raw_ostream &o2,
+ unsigned &i1, unsigned &i2,
+ OpcodeDecision &decision) const {
o2.indent(i2) << "{ /* struct OpcodeDecision */" << "\n";
i2++;
o2.indent(i2) << "{" << "\n";
i2++;
- for (index = 0; index < 256; ++index) {
+ for (unsigned index = 0; index < 256; ++index) {
o2.indent(i2);
o2 << "/* 0x" << format("%02hhx", index) << " */" << "\n";
@@ -412,21 +396,16 @@ void DisassemblerTables::emitOpcodeDecision(
o2.indent(i2) << "}" << "\n";
}
-void DisassemblerTables::emitContextDecision(
- raw_ostream &o1,
- raw_ostream &o2,
- uint32_t &i1,
- uint32_t &i2,
- ContextDecision &decision,
- const char* name) const {
+void DisassemblerTables::emitContextDecision(raw_ostream &o1, raw_ostream &o2,
+ unsigned &i1, unsigned &i2,
+ ContextDecision &decision,
+ const char* name) const {
o2.indent(i2) << "static const struct ContextDecision " << name << " = {\n";
i2++;
o2.indent(i2) << "{ /* opcodeDecisions */" << "\n";
i2++;
- unsigned index;
-
- for (index = 0; index < IC_max; ++index) {
+ for (unsigned index = 0; index < IC_max; ++index) {
o2.indent(i2) << "/* ";
o2 << stringForContext((InstructionContext)index);
o2 << " */";
@@ -444,58 +423,81 @@ void DisassemblerTables::emitContextDecision(
o2.indent(i2) << "};" << "\n";
}
-void DisassemblerTables::emitInstructionInfo(raw_ostream &o, uint32_t &i)
- const {
+void DisassemblerTables::emitInstructionInfo(raw_ostream &o,
+ unsigned &i) const {
+ unsigned NumInstructions = InstructionSpecifiers.size();
+
+ o << "static const struct OperandSpecifier x86OperandSets[]["
+ << X86_MAX_OPERANDS << "] = {\n";
+
+ typedef std::vector<std::pair<const char *, const char *> > OperandListTy;
+ std::map<OperandListTy, unsigned> OperandSets;
+
+ unsigned OperandSetNum = 0;
+ for (unsigned Index = 0; Index < NumInstructions; ++Index) {
+ OperandListTy OperandList;
+
+ for (unsigned OperandIndex = 0; OperandIndex < X86_MAX_OPERANDS;
+ ++OperandIndex) {
+ const char *Encoding =
+ stringForOperandEncoding((OperandEncoding)InstructionSpecifiers[Index]
+ .operands[OperandIndex].encoding);
+ const char *Type =
+ stringForOperandType((OperandType)InstructionSpecifiers[Index]
+ .operands[OperandIndex].type);
+ OperandList.push_back(std::make_pair(Encoding, Type));
+ }
+ unsigned &N = OperandSets[OperandList];
+ if (N != 0) continue;
+
+ N = ++OperandSetNum;
+
+ o << " { /* " << (OperandSetNum - 1) << " */\n";
+ for (unsigned i = 0, e = OperandList.size(); i != e; ++i) {
+ o << " { " << OperandList[i].first << ", "
+ << OperandList[i].second << " },\n";
+ }
+ o << " },\n";
+ }
+ o << "};" << "\n\n";
+
o.indent(i * 2) << "static const struct InstructionSpecifier ";
o << INSTRUCTIONS_STR "[" << InstructionSpecifiers.size() << "] = {\n";
-
- i++;
- uint16_t numInstructions = InstructionSpecifiers.size();
- uint16_t index, operandIndex;
+ i++;
- for (index = 0; index < numInstructions; ++index) {
+ for (unsigned index = 0; index < NumInstructions; ++index) {
o.indent(i * 2) << "{ /* " << index << " */" << "\n";
i++;
o.indent(i * 2) << stringForModifierType(
(ModifierType)InstructionSpecifiers[index].modifierType);
- o << "," << "\n";
+ o << ",\n";
o.indent(i * 2) << "0x";
o << format("%02hhx", (uint16_t)InstructionSpecifiers[index].modifierBase);
- o << "," << "\n";
-
- o.indent(i * 2) << "{" << "\n";
- i++;
-
- for (operandIndex = 0; operandIndex < X86_MAX_OPERANDS; ++operandIndex) {
- o.indent(i * 2) << "{ ";
- o <<stringForOperandEncoding((OperandEncoding)InstructionSpecifiers[index]
- .operands[operandIndex]
- .encoding);
- o << ", ";
- o << stringForOperandType((OperandType)InstructionSpecifiers[index]
- .operands[operandIndex]
- .type);
- o << " }";
-
- if (operandIndex < X86_MAX_OPERANDS - 1)
- o << ",";
-
- o << "\n";
+ o << ",\n";
+
+ OperandListTy OperandList;
+ for (unsigned OperandIndex = 0; OperandIndex < X86_MAX_OPERANDS;
+ ++OperandIndex) {
+ const char *Encoding =
+ stringForOperandEncoding((OperandEncoding)InstructionSpecifiers[index]
+ .operands[OperandIndex].encoding);
+ const char *Type =
+ stringForOperandType((OperandType)InstructionSpecifiers[index]
+ .operands[OperandIndex].type);
+ OperandList.push_back(std::make_pair(Encoding, Type));
}
+ o.indent(i * 2) << (OperandSets[OperandList] - 1) << ",\n";
- i--;
- o.indent(i * 2) << "}," << "\n";
-
o.indent(i * 2) << "/* " << InstructionSpecifiers[index].name << " */";
o << "\n";
i--;
o.indent(i * 2) << "}";
- if (index + 1 < numInstructions)
+ if (index + 1 < NumInstructions)
o << ",";
o << "\n";
@@ -505,14 +507,12 @@ void DisassemblerTables::emitInstructionInfo(raw_ostream &o, uint32_t &i)
o.indent(i * 2) << "};" << "\n";
}
-void DisassemblerTables::emitContextTable(raw_ostream &o, uint32_t &i) const {
- uint16_t index;
-
- o.indent(i * 2) << "static const InstructionContext " CONTEXTS_STR
+void DisassemblerTables::emitContextTable(raw_ostream &o, unsigned &i) const {
+ o.indent(i * 2) << "static const uint8_t " CONTEXTS_STR
"[256] = {\n";
i++;
- for (index = 0; index < 256; ++index) {
+ for (unsigned index = 0; index < 256; ++index) {
o.indent(i * 2);
if ((index & ATTR_VEXL) && (index & ATTR_REXW) && (index & ATTR_OPSIZE))
@@ -545,7 +545,7 @@ void DisassemblerTables::emitContextTable(raw_ostream &o, uint32_t &i) const {
o << "IC_64BIT_REXW_XS";
else if ((index & ATTR_64BIT) && (index & ATTR_REXW) && (index & ATTR_XD))
o << "IC_64BIT_REXW_XD";
- else if ((index & ATTR_64BIT) && (index & ATTR_REXW) &&
+ else if ((index & ATTR_64BIT) && (index & ATTR_REXW) &&
(index & ATTR_OPSIZE))
o << "IC_64BIT_REXW_OPSIZE";
else if ((index & ATTR_64BIT) && (index & ATTR_XD) && (index & ATTR_OPSIZE))
@@ -593,11 +593,8 @@ void DisassemblerTables::emitContextTable(raw_ostream &o, uint32_t &i) const {
o.indent(i * 2) << "};" << "\n";
}
-void DisassemblerTables::emitContextDecisions(raw_ostream &o1,
- raw_ostream &o2,
- uint32_t &i1,
- uint32_t &i2)
- const {
+void DisassemblerTables::emitContextDecisions(raw_ostream &o1, raw_ostream &o2,
+ unsigned &i1, unsigned &i2) const {
emitContextDecision(o1, o2, i1, i2, *Tables[0], ONEBYTE_STR);
emitContextDecision(o1, o2, i1, i2, *Tables[1], TWOBYTE_STR);
emitContextDecision(o1, o2, i1, i2, *Tables[2], THREEBYTE38_STR);
@@ -607,15 +604,15 @@ void DisassemblerTables::emitContextDecisions(raw_ostream &o1,
}
void DisassemblerTables::emit(raw_ostream &o) const {
- uint32_t i1 = 0;
- uint32_t i2 = 0;
-
+ unsigned i1 = 0;
+ unsigned i2 = 0;
+
std::string s1;
std::string s2;
-
+
raw_string_ostream o1(s1);
raw_string_ostream o2(s2);
-
+
emitInstructionInfo(o, i2);
o << "\n";
@@ -641,9 +638,7 @@ void DisassemblerTables::setTableFields(ModRMDecision &decision,
const ModRMFilter &filter,
InstrUID uid,
uint8_t opcode) {
- unsigned index;
-
- for (index = 0; index < 256; ++index) {
+ for (unsigned index = 0; index < 256; ++index) {
if (filter.accepts(index)) {
if (decision.instructionIDs[index] == uid)
continue;
@@ -653,10 +648,10 @@ void DisassemblerTables::setTableFields(ModRMDecision &decision,
InstructionSpecifiers[uid];
InstructionSpecifier &previousInfo =
InstructionSpecifiers[decision.instructionIDs[index]];
-
+
if(newInfo.filtered)
continue; // filtered instructions get lowest priority
-
+
if(previousInfo.name == "NOOP" && (newInfo.name == "XCHG16ar" ||
newInfo.name == "XCHG32ar" ||
newInfo.name == "XCHG32ar64" ||
@@ -665,7 +660,7 @@ void DisassemblerTables::setTableFields(ModRMDecision &decision,
if (outranks(previousInfo.insnContext, newInfo.insnContext))
continue;
-
+
if (previousInfo.insnContext == newInfo.insnContext &&
!previousInfo.filtered) {
errs() << "Error: Primary decode conflict: ";
@@ -690,17 +685,15 @@ void DisassemblerTables::setTableFields(OpcodeType type,
InstrUID uid,
bool is32bit,
bool ignoresVEX_L) {
- unsigned index;
-
ContextDecision &decision = *Tables[type];
- for (index = 0; index < IC_max; ++index) {
+ for (unsigned index = 0; index < IC_max; ++index) {
if (is32bit && inheritsFrom((InstructionContext)index, IC_64BIT))
continue;
- if (inheritsFrom((InstructionContext)index,
+ if (inheritsFrom((InstructionContext)index,
InstructionSpecifiers[uid].insnContext, ignoresVEX_L))
- setTableFields(decision.opcodeDecisions[index].modRMDecisions[opcode],
+ setTableFields(decision.opcodeDecisions[index].modRMDecisions[opcode],
filter,
uid,
opcode);
diff --git a/utils/TableGen/X86DisassemblerTables.h b/utils/TableGen/X86DisassemblerTables.h
index e148cd26e809..ea006c05b991 100644
--- a/utils/TableGen/X86DisassemblerTables.h
+++ b/utils/TableGen/X86DisassemblerTables.h
@@ -42,13 +42,13 @@ private:
/// [4] three-byte opcodes of the form 0f a6 __
/// [5] three-byte opcodes of the form 0f a7 __
ContextDecision* Tables[6];
-
+
/// The instruction information table
std::vector<InstructionSpecifier> InstructionSpecifiers;
-
+
/// True if there are primary decode conflicts in the instruction set
bool HasConflicts;
-
+
/// emitOneID - Emits a table entry for a single instruction entry, at the
/// innermost level of the structure hierarchy. The entry is printed out
/// in the format "nnnn, /* MNEMONIC */" where nnnn is the ID in decimal,
@@ -64,7 +64,7 @@ private:
uint32_t &i,
InstrUID id,
bool addComma) const;
-
+
/// emitModRMDecision - Emits a table of entries corresponding to a single
/// ModR/M decision. Compacts the ModR/M decision if possible. ModR/M
/// decisions are printed as:
@@ -77,12 +77,12 @@ private:
/// where nnnn is a unique ID for the corresponding table of IDs.
/// TYPE indicates whether the table has one entry that is the same
/// regardless of ModR/M byte, two entries - one for bytes 0x00-0xbf and one
- /// for bytes 0xc0-0xff -, or 256 entries, one for each possible byte.
+ /// for bytes 0xc0-0xff -, or 256 entries, one for each possible byte.
/// nnnn is the number of a table for looking up these values. The tables
/// are written separately so that tables consisting entirely of zeros will
/// not be duplicated. (These all have the name modRMEmptyTable.) A table
/// is printed as:
- ///
+ ///
/// InstrUID modRMTablennnn[k] = {
/// nnnn, /* MNEMONIC */
/// ...
@@ -100,7 +100,7 @@ private:
uint32_t &i1,
uint32_t &i2,
ModRMDecision &decision) const;
-
+
/// emitOpcodeDecision - Emits an OpcodeDecision and all its subsidiary ModR/M
/// decisions. An OpcodeDecision is printed as:
///
@@ -129,8 +129,8 @@ private:
uint32_t &i1,
uint32_t &i2,
OpcodeDecision &decision) const;
-
- /// emitContextDecision - Emits a ContextDecision and all its subsidiary
+
+ /// emitContextDecision - Emits a ContextDecision and all its subsidiary
/// Opcode and ModRMDecisions. A ContextDecision is printed as:
///
/// struct ContextDecision NAME = {
@@ -163,10 +163,10 @@ private:
void emitContextDecision(raw_ostream &o1,
raw_ostream &o2,
uint32_t &i1,
- uint32_t &i2,
+ uint32_t &i2,
ContextDecision &decision,
const char* name) const;
-
+
/// emitInstructionInfo - Prints the instruction specifier table, which has
/// one entry for each instruction, and contains name and operand
/// information. This table is printed as:
@@ -187,17 +187,17 @@ private:
/// };
///
/// k is the total number of instructions.
- /// nnnn is the ID of the current instruction (0-based). This table
+ /// nnnn is the ID of the current instruction (0-based). This table
/// includes entries for non-instructions like PHINODE.
/// 0xnn is the lowest possible opcode for the current instruction, used for
/// AddRegFrm instructions to compute the operand's value.
/// ENCODING and TYPE describe the encoding and type for a single operand.
///
- /// @param o - The output stream to which the instruction table should be
+ /// @param o - The output stream to which the instruction table should be
/// written.
/// @param i - The indent level for use with the stream.
void emitInstructionInfo(raw_ostream &o, uint32_t &i) const;
-
+
/// emitContextTable - Prints the table that is used to translate from an
/// instruction attribute mask to an instruction context. This table is
/// printed as:
@@ -213,7 +213,7 @@ private:
/// @param o - The output stream to which the context table should be written.
/// @param i - The indent level for use with the stream.
void emitContextTable(raw_ostream &o, uint32_t &i) const;
-
+
/// emitContextDecisions - Prints all four ContextDecision structures using
/// emitContextDecision().
///
@@ -225,7 +225,7 @@ private:
void emitContextDecisions(raw_ostream &o1,
raw_ostream &o2,
uint32_t &i1,
- uint32_t &i2) const;
+ uint32_t &i2) const;
/// setTableFields - Uses a ModRMFilter to set the appropriate entries in a
/// ModRMDecision to refer to a particular instruction ID.
@@ -241,14 +241,14 @@ private:
public:
/// Constructor - Allocates space for the class decisions and clears them.
DisassemblerTables();
-
+
~DisassemblerTables();
-
+
/// emit - Emits the instruction table, context table, and class decisions.
///
/// @param o - The output stream to print the tables to.
void emit(raw_ostream &o) const;
-
+
/// setTableFields - Uses the opcode type, instruction context, opcode, and a
/// ModRMFilter as criteria to set a particular set of entries in the
/// decode tables to point to a specific uid.
@@ -268,24 +268,24 @@ public:
const ModRMFilter &filter,
InstrUID uid,
bool is32bit,
- bool ignoresVEX_L);
-
+ bool ignoresVEX_L);
+
/// specForUID - Returns the instruction specifier for a given unique
/// instruction ID. Used when resolving collisions.
///
/// @param uid - The unique ID of the instruction.
- /// @return - A reference to the instruction specifier.
+ /// @return - A reference to the instruction specifier.
InstructionSpecifier& specForUID(InstrUID uid) {
if (uid >= InstructionSpecifiers.size())
InstructionSpecifiers.resize(uid + 1);
-
+
return InstructionSpecifiers[uid];
}
-
+
// hasConflicts - Reports whether there were primary decode conflicts
// from any instructions added to the tables.
// @return - true if there were; false otherwise.
-
+
bool hasConflicts() {
return HasConflicts;
}
diff --git a/utils/TableGen/X86RecognizableInstr.cpp b/utils/TableGen/X86RecognizableInstr.cpp
index 6a01cce637e4..7ac2336d7321 100644
--- a/utils/TableGen/X86RecognizableInstr.cpp
+++ b/utils/TableGen/X86RecognizableInstr.cpp
@@ -57,19 +57,19 @@ namespace X86Local {
MRMDestMem = 4,
MRMSrcReg = 5,
MRMSrcMem = 6,
- MRM0r = 16, MRM1r = 17, MRM2r = 18, MRM3r = 19,
+ MRM0r = 16, MRM1r = 17, MRM2r = 18, MRM3r = 19,
MRM4r = 20, MRM5r = 21, MRM6r = 22, MRM7r = 23,
MRM0m = 24, MRM1m = 25, MRM2m = 26, MRM3m = 27,
MRM4m = 28, MRM5m = 29, MRM6m = 30, MRM7m = 31,
MRMInitReg = 32,
+ RawFrmImm8 = 43,
+ RawFrmImm16 = 44,
#define MAP(from, to) MRM_##from = to,
MRM_MAPPING
#undef MAP
- RawFrmImm8 = 43,
- RawFrmImm16 = 44,
lastMRM
};
-
+
enum {
TB = 1,
REP = 2,
@@ -82,17 +82,17 @@ namespace X86Local {
}
// If rows are added to the opcode extension tables, then corresponding entries
-// must be added here.
+// must be added here.
//
// If the row corresponds to a single byte (i.e., 8f), then add an entry for
// that byte to ONE_BYTE_EXTENSION_TABLES.
//
-// If the row corresponds to two bytes where the first is 0f, add an entry for
+// If the row corresponds to two bytes where the first is 0f, add an entry for
// the second byte to TWO_BYTE_EXTENSION_TABLES.
//
// If the row corresponds to some other set of bytes, you will need to modify
// the code in RecognizableInstr::emitDecodePath() as well, and add new prefixes
-// to the X86 TD files, except in two cases: if the first two bytes of such a
+// to the X86 TD files, except in two cases: if the first two bytes of such a
// new combination are 0f 38 or 0f 3a, you just have to add maps called
// THREE_BYTE_38_EXTENSION_TABLES and THREE_BYTE_3A_EXTENSION_TABLES and add a
// switch(Opcode) just below the case X86Local::T8: or case X86Local::TA: line
@@ -116,7 +116,7 @@ namespace X86Local {
EXTENSION_TABLE(f7) \
EXTENSION_TABLE(fe) \
EXTENSION_TABLE(ff)
-
+
#define TWO_BYTE_EXTENSION_TABLES \
EXTENSION_TABLE(00) \
EXTENSION_TABLE(01) \
@@ -134,7 +134,7 @@ namespace X86Local {
using namespace X86Disassembler;
/// needsModRMForDecode - Indicates whether a particular instruction requires a
-/// ModR/M byte for the instruction to be properly decoded. For example, a
+/// ModR/M byte for the instruction to be properly decoded. For example, a
/// MRMDestReg instruction needs the Mod field in the ModR/M byte to be set to
/// 0b11.
///
@@ -213,17 +213,17 @@ RecognizableInstr::RecognizableInstr(DisassemblerTables &tables,
Rec = insn.TheDef;
Name = Rec->getName();
Spec = &tables.specForUID(UID);
-
+
if (!Rec->isSubClassOf("X86Inst")) {
ShouldBeEmitted = false;
return;
}
-
+
Prefix = byteFromRec(Rec, "Prefix");
Opcode = byteFromRec(Rec, "Opcode");
Form = byteFromRec(Rec, "FormBits");
SegOvr = byteFromRec(Rec, "SegOvrBits");
-
+
HasOpSizePrefix = Rec->getValueAsBit("hasOpSizePrefix");
HasAdSizePrefix = Rec->getValueAsBit("hasAdSizePrefix");
HasREX_WPrefix = Rec->getValueAsBit("hasREX_WPrefix");
@@ -235,12 +235,12 @@ RecognizableInstr::RecognizableInstr(DisassemblerTables &tables,
IgnoresVEX_L = Rec->getValueAsBit("ignoresVEX_L");
HasLockPrefix = Rec->getValueAsBit("hasLockPrefix");
IsCodeGenOnly = Rec->getValueAsBit("isCodeGenOnly");
-
+
Name = Rec->getName();
AsmString = Rec->getValueAsString("AsmString");
-
+
Operands = &insn.Operands.OperandList;
-
+
IsSSE = (HasOpSizePrefix && (Name.find("16") == Name.npos)) ||
(Name.find("CRC32") != Name.npos);
HasFROperands = hasFROperands();
@@ -262,32 +262,32 @@ RecognizableInstr::RecognizableInstr(DisassemblerTables &tables,
}
}
// FIXME: These instructions aren't marked as 64-bit in any way
- Is64Bit |= Rec->getName() == "JMP64pcrel32" ||
- Rec->getName() == "MASKMOVDQU64" ||
- Rec->getName() == "POPFS64" ||
- Rec->getName() == "POPGS64" ||
- Rec->getName() == "PUSHFS64" ||
+ Is64Bit |= Rec->getName() == "JMP64pcrel32" ||
+ Rec->getName() == "MASKMOVDQU64" ||
+ Rec->getName() == "POPFS64" ||
+ Rec->getName() == "POPGS64" ||
+ Rec->getName() == "PUSHFS64" ||
Rec->getName() == "PUSHGS64" ||
Rec->getName() == "REX64_PREFIX" ||
- Rec->getName().find("MOV64") != Name.npos ||
+ Rec->getName().find("MOV64") != Name.npos ||
Rec->getName().find("PUSH64") != Name.npos ||
Rec->getName().find("POP64") != Name.npos;
ShouldBeEmitted = true;
}
-
+
void RecognizableInstr::processInstr(DisassemblerTables &tables,
- const CodeGenInstruction &insn,
- InstrUID uid)
+ const CodeGenInstruction &insn,
+ InstrUID uid)
{
// Ignore "asm parser only" instructions.
if (insn.TheDef->getValueAsBit("isAsmParserOnly"))
return;
-
+
RecognizableInstr recogInstr(tables, insn, uid);
-
+
recogInstr.emitInstructionSpecifier(tables);
-
+
if (recogInstr.shouldBeEmitted())
recogInstr.emitDecodePath(tables);
}
@@ -386,55 +386,40 @@ InstructionContext RecognizableInstr::insnContext() const {
return insnContext;
}
-
+
RecognizableInstr::filter_ret RecognizableInstr::filter() const {
///////////////////
// FILTER_STRONG
//
-
+
// Filter out intrinsics
-
- if (!Rec->isSubClassOf("X86Inst"))
- return FILTER_STRONG;
-
+
+ assert(Rec->isSubClassOf("X86Inst") && "Can only filter X86 instructions");
+
if (Form == X86Local::Pseudo ||
(IsCodeGenOnly && Name.find("_REV") == Name.npos))
return FILTER_STRONG;
-
- if (Form == X86Local::MRMInitReg)
- return FILTER_STRONG;
-
-
+
+
// Filter out artificial instructions but leave in the LOCK_PREFIX so it is
// printed as a separate "instruction".
-
+
if (Name.find("_Int") != Name.npos ||
- Name.find("Int_") != Name.npos ||
- Name.find("_NOREX") != Name.npos ||
- Name.find("2SDL") != Name.npos)
+ Name.find("Int_") != Name.npos)
return FILTER_STRONG;
// Filter out instructions with segment override prefixes.
// They're too messy to handle now and we'll special case them if needed.
-
+
if (SegOvr)
return FILTER_STRONG;
-
- // Filter out instructions that can't be printed.
-
- if (AsmString.size() == 0)
- return FILTER_STRONG;
-
- // Filter out instructions with subreg operands.
-
- if (AsmString.find("subreg") != AsmString.npos)
- return FILTER_STRONG;
+
/////////////////
// FILTER_WEAK
//
-
+
// Filter out instructions with a LOCK prefix;
// prefer forms that do not have the prefix
if (HasLockPrefix)
@@ -474,9 +459,9 @@ RecognizableInstr::filter_ret RecognizableInstr::filter() const {
return FILTER_WEAK;
if (HasFROperands && Name.find("MOV") != Name.npos &&
- ((Name.find("2") != Name.npos && Name.find("32") == Name.npos) ||
+ ((Name.find("2") != Name.npos && Name.find("32") == Name.npos) ||
(Name.find("to") != Name.npos)))
- return FILTER_WEAK;
+ return FILTER_STRONG;
return FILTER_NORMAL;
}
@@ -487,7 +472,7 @@ bool RecognizableInstr::hasFROperands() const {
for (unsigned operandIndex = 0; operandIndex < numOperands; ++operandIndex) {
const std::string &recName = OperandList[operandIndex].Rec->getName();
-
+
if (recName.find("FR") != recName.npos)
return true;
}
@@ -497,57 +482,57 @@ bool RecognizableInstr::hasFROperands() const {
bool RecognizableInstr::has256BitOperands() const {
const std::vector<CGIOperandList::OperandInfo> &OperandList = *Operands;
unsigned numOperands = OperandList.size();
-
+
for (unsigned operandIndex = 0; operandIndex < numOperands; ++operandIndex) {
const std::string &recName = OperandList[operandIndex].Rec->getName();
-
- if (!recName.compare("VR256") || !recName.compare("f256mem")) {
+
+ if (!recName.compare("VR256")) {
return true;
}
}
return false;
}
-
-void RecognizableInstr::handleOperand(
- bool optional,
- unsigned &operandIndex,
- unsigned &physicalOperandIndex,
- unsigned &numPhysicalOperands,
- unsigned *operandMapping,
- OperandEncoding (*encodingFromString)(const std::string&, bool hasOpSizePrefix)) {
+
+void RecognizableInstr::handleOperand(bool optional, unsigned &operandIndex,
+ unsigned &physicalOperandIndex,
+ unsigned &numPhysicalOperands,
+ const unsigned *operandMapping,
+ OperandEncoding (*encodingFromString)
+ (const std::string&,
+ bool hasOpSizePrefix)) {
if (optional) {
if (physicalOperandIndex >= numPhysicalOperands)
return;
} else {
assert(physicalOperandIndex < numPhysicalOperands);
}
-
+
while (operandMapping[operandIndex] != operandIndex) {
Spec->operands[operandIndex].encoding = ENCODING_DUP;
Spec->operands[operandIndex].type =
(OperandType)(TYPE_DUP0 + operandMapping[operandIndex]);
++operandIndex;
}
-
+
const std::string &typeName = (*Operands)[operandIndex].Rec->getName();
Spec->operands[operandIndex].encoding = encodingFromString(typeName,
HasOpSizePrefix);
- Spec->operands[operandIndex].type = typeFromString(typeName,
+ Spec->operands[operandIndex].type = typeFromString(typeName,
IsSSE,
HasREX_WPrefix,
HasOpSizePrefix);
-
+
++operandIndex;
++physicalOperandIndex;
}
void RecognizableInstr::emitInstructionSpecifier(DisassemblerTables &tables) {
Spec->name = Name;
-
- if (!Rec->isSubClassOf("X86Inst"))
+
+ if (!ShouldBeEmitted)
return;
-
+
switch (filter()) {
case FILTER_WEAK:
Spec->filtered = true;
@@ -558,29 +543,26 @@ void RecognizableInstr::emitInstructionSpecifier(DisassemblerTables &tables) {
case FILTER_NORMAL:
break;
}
-
+
Spec->insnContext = insnContext();
-
+
const std::vector<CGIOperandList::OperandInfo> &OperandList = *Operands;
-
- unsigned operandIndex;
+
unsigned numOperands = OperandList.size();
unsigned numPhysicalOperands = 0;
-
+
// operandMapping maps from operands in OperandList to their originals.
// If operandMapping[i] != i, then the entry is a duplicate.
unsigned operandMapping[X86_MAX_OPERANDS];
-
- bool hasFROperands = false;
-
assert(numOperands <= X86_MAX_OPERANDS && "X86_MAX_OPERANDS is not large enough");
-
- for (operandIndex = 0; operandIndex < numOperands; ++operandIndex) {
+
+ for (unsigned operandIndex = 0; operandIndex < numOperands; ++operandIndex) {
if (OperandList[operandIndex].Constraints.size()) {
const CGIOperandList::ConstraintInfo &Constraint =
OperandList[operandIndex].Constraints[0];
if (Constraint.isTied()) {
- operandMapping[operandIndex] = Constraint.getTiedOperand();
+ operandMapping[operandIndex] = operandIndex;
+ operandMapping[Constraint.getTiedOperand()] = operandIndex;
} else {
++numPhysicalOperands;
operandMapping[operandIndex] = operandIndex;
@@ -589,20 +571,7 @@ void RecognizableInstr::emitInstructionSpecifier(DisassemblerTables &tables) {
++numPhysicalOperands;
operandMapping[operandIndex] = operandIndex;
}
-
- const std::string &recName = OperandList[operandIndex].Rec->getName();
-
- if (recName.find("FR") != recName.npos)
- hasFROperands = true;
}
-
- if (hasFROperands && Name.find("MOV") != Name.npos &&
- ((Name.find("2") != Name.npos && Name.find("32") == Name.npos) ||
- (Name.find("to") != Name.npos)))
- ShouldBeEmitted = false;
-
- if (!ShouldBeEmitted)
- return;
#define HANDLE_OPERAND(class) \
handleOperand(false, \
@@ -611,7 +580,7 @@ void RecognizableInstr::emitInstructionSpecifier(DisassemblerTables &tables) {
numPhysicalOperands, \
operandMapping, \
class##EncodingFromString);
-
+
#define HANDLE_OPTIONAL(class) \
handleOperand(true, \
operandIndex, \
@@ -619,17 +588,17 @@ void RecognizableInstr::emitInstructionSpecifier(DisassemblerTables &tables) {
numPhysicalOperands, \
operandMapping, \
class##EncodingFromString);
-
+
// operandIndex should always be < numOperands
- operandIndex = 0;
+ unsigned operandIndex = 0;
// physicalOperandIndex should always be < numPhysicalOperands
unsigned physicalOperandIndex = 0;
-
+
switch (Form) {
case X86Local::RawFrm:
// Operand 1 (optional) is an address or immediate.
// Operand 2 (optional) is an immediate.
- assert(numPhysicalOperands <= 2 &&
+ assert(numPhysicalOperands <= 2 &&
"Unexpected number of operands for RawFrm");
HANDLE_OPTIONAL(relocation)
HANDLE_OPTIONAL(immediate)
@@ -653,14 +622,14 @@ void RecognizableInstr::emitInstructionSpecifier(DisassemblerTables &tables) {
else
assert(numPhysicalOperands >= 2 && numPhysicalOperands <= 3 &&
"Unexpected number of operands for MRMDestRegFrm");
-
+
HANDLE_OPERAND(rmRegister)
if (HasVEX_4VPrefix)
// FIXME: In AVX, the register below becomes the one encoded
// in ModRMVEX and the one above the one in the VEX.VVVV field
HANDLE_OPERAND(vvvvRegister)
-
+
HANDLE_OPERAND(roRegister)
HANDLE_OPTIONAL(immediate)
break;
@@ -681,7 +650,7 @@ void RecognizableInstr::emitInstructionSpecifier(DisassemblerTables &tables) {
// FIXME: In AVX, the register below becomes the one encoded
// in ModRMVEX and the one above the one in the VEX.VVVV field
HANDLE_OPERAND(vvvvRegister)
-
+
HANDLE_OPERAND(roRegister)
HANDLE_OPTIONAL(immediate)
break;
@@ -690,14 +659,15 @@ void RecognizableInstr::emitInstructionSpecifier(DisassemblerTables &tables) {
// Operand 2 is a register operand in the R/M field.
// - In AVX, there is a register operand in the VEX.vvvv field here -
// Operand 3 (optional) is an immediate.
+ // Operand 4 (optional) is an immediate.
if (HasVEX_4VPrefix || HasVEX_4VOp3Prefix)
assert(numPhysicalOperands >= 3 && numPhysicalOperands <= 5 &&
- "Unexpected number of operands for MRMSrcRegFrm with VEX_4V");
+ "Unexpected number of operands for MRMSrcRegFrm with VEX_4V");
else
- assert(numPhysicalOperands >= 2 && numPhysicalOperands <= 3 &&
+ assert(numPhysicalOperands >= 2 && numPhysicalOperands <= 4 &&
"Unexpected number of operands for MRMSrcRegFrm");
-
+
HANDLE_OPERAND(roRegister)
if (HasVEX_4VPrefix)
@@ -716,6 +686,7 @@ void RecognizableInstr::emitInstructionSpecifier(DisassemblerTables &tables) {
if (!HasMemOp4Prefix)
HANDLE_OPTIONAL(immediate)
HANDLE_OPTIONAL(immediate) // above might be a register in 7:4
+ HANDLE_OPTIONAL(immediate)
break;
case X86Local::MRMSrcMem:
// Operand 1 is a register operand in the Reg/Opcode field.
@@ -725,11 +696,11 @@ void RecognizableInstr::emitInstructionSpecifier(DisassemblerTables &tables) {
if (HasVEX_4VPrefix || HasVEX_4VOp3Prefix)
assert(numPhysicalOperands >= 3 && numPhysicalOperands <= 5 &&
- "Unexpected number of operands for MRMSrcMemFrm with VEX_4V");
+ "Unexpected number of operands for MRMSrcMemFrm with VEX_4V");
else
assert(numPhysicalOperands >= 2 && numPhysicalOperands <= 3 &&
"Unexpected number of operands for MRMSrcMemFrm");
-
+
HANDLE_OPERAND(roRegister)
if (HasVEX_4VPrefix)
@@ -759,16 +730,18 @@ void RecognizableInstr::emitInstructionSpecifier(DisassemblerTables &tables) {
case X86Local::MRM7r:
// Operand 1 is a register operand in the R/M field.
// Operand 2 (optional) is an immediate or relocation.
+ // Operand 3 (optional) is an immediate.
if (HasVEX_4VPrefix)
assert(numPhysicalOperands <= 3 &&
"Unexpected number of operands for MRMnRFrm with VEX_4V");
else
- assert(numPhysicalOperands <= 2 &&
+ assert(numPhysicalOperands <= 3 &&
"Unexpected number of operands for MRMnRFrm");
if (HasVEX_4VPrefix)
HANDLE_OPERAND(vvvvRegister)
HANDLE_OPTIONAL(rmRegister)
HANDLE_OPTIONAL(relocation)
+ HANDLE_OPTIONAL(immediate)
break;
case X86Local::MRM0m:
case X86Local::MRM1m:
@@ -809,7 +782,7 @@ void RecognizableInstr::emitInstructionSpecifier(DisassemblerTables &tables) {
// Ignored.
break;
}
-
+
#undef HANDLE_OPERAND
#undef HANDLE_OPTIONAL
}
@@ -823,8 +796,8 @@ void RecognizableInstr::emitDecodePath(DisassemblerTables &tables) const {
break;
OpcodeType opcodeType = (OpcodeType)-1;
-
- ModRMFilter* filter = NULL;
+
+ ModRMFilter* filter = NULL;
uint8_t opcodeToSet = 0;
switch (Prefix) {
@@ -1022,26 +995,26 @@ void RecognizableInstr::emitDecodePath(DisassemblerTables &tables) const {
if(Spec->modifierType != MODIFIER_MODRM) {
assert(opcodeToSet < 0xf9 &&
"Not enough room for all ADDREG_FRM operands");
-
+
uint8_t currentOpcode;
for (currentOpcode = opcodeToSet;
currentOpcode < opcodeToSet + 8;
++currentOpcode)
- tables.setTableFields(opcodeType,
- insnContext(),
- currentOpcode,
- *filter,
+ tables.setTableFields(opcodeType,
+ insnContext(),
+ currentOpcode,
+ *filter,
UID, Is32Bit, IgnoresVEX_L);
-
+
Spec->modifierType = MODIFIER_OPCODE;
Spec->modifierBase = opcodeToSet;
} else {
// modifierBase was set where MODIFIER_MODRM was set
- tables.setTableFields(opcodeType,
- insnContext(),
- opcodeToSet,
- *filter,
+ tables.setTableFields(opcodeType,
+ insnContext(),
+ opcodeToSet,
+ *filter,
UID, Is32Bit, IgnoresVEX_L);
}
} else {
@@ -1050,13 +1023,13 @@ void RecognizableInstr::emitDecodePath(DisassemblerTables &tables) const {
opcodeToSet,
*filter,
UID, Is32Bit, IgnoresVEX_L);
-
+
Spec->modifierType = MODIFIER_NONE;
Spec->modifierBase = opcodeToSet;
}
-
+
delete filter;
-
+
#undef MAP
}
@@ -1066,7 +1039,7 @@ OperandType RecognizableInstr::typeFromString(const std::string &s,
bool hasREX_WPrefix,
bool hasOpSizePrefix) {
if (isSSE) {
- // For SSE instructions, we ignore the OpSize prefix and force operand
+ // For SSE instructions, we ignore the OpSize prefix and force operand
// sizes.
TYPE("GR16", TYPE_R16)
TYPE("GR32", TYPE_R32)
@@ -1140,6 +1113,10 @@ OperandType RecognizableInstr::typeFromString(const std::string &s,
TYPE("GR16_NOAX", TYPE_Rv)
TYPE("GR32_NOAX", TYPE_Rv)
TYPE("GR64_NOAX", TYPE_R64)
+ TYPE("vx32mem", TYPE_M32)
+ TYPE("vy32mem", TYPE_M32)
+ TYPE("vx64mem", TYPE_M64)
+ TYPE("vy64mem", TYPE_M64)
errs() << "Unhandled type string " << s << "\n";
llvm_unreachable("Unhandled type string");
}
@@ -1243,6 +1220,10 @@ OperandEncoding RecognizableInstr::memoryEncodingFromString
ENCODING("opaque48mem", ENCODING_RM)
ENCODING("opaque80mem", ENCODING_RM)
ENCODING("opaque512mem", ENCODING_RM)
+ ENCODING("vx32mem", ENCODING_RM)
+ ENCODING("vy32mem", ENCODING_RM)
+ ENCODING("vx64mem", ENCODING_RM)
+ ENCODING("vy64mem", ENCODING_RM)
errs() << "Unhandled memory encoding " << s << "\n";
llvm_unreachable("Unhandled memory encoding");
}
diff --git a/utils/TableGen/X86RecognizableInstr.h b/utils/TableGen/X86RecognizableInstr.h
index 6c0a234b5eff..542e510c6033 100644
--- a/utils/TableGen/X86RecognizableInstr.h
+++ b/utils/TableGen/X86RecognizableInstr.h
@@ -204,7 +204,7 @@ private:
unsigned &operandIndex,
unsigned &physicalOperandIndex,
unsigned &numPhysicalOperands,
- unsigned *operandMapping,
+ const unsigned *operandMapping,
OperandEncoding (*encodingFromString)
(const std::string&,
bool hasOpSizePrefix));
diff --git a/utils/UpdateCMakeLists.pl b/utils/UpdateCMakeLists.pl
index 8f535145de31..d92a767adf32 100755
--- a/utils/UpdateCMakeLists.pl
+++ b/utils/UpdateCMakeLists.pl
@@ -68,8 +68,7 @@ sub UpdateCMake {
while(<IN>) {
if (!$foundLibrary) {
print OUT $_;
- if (/^add_clang_library\(/ || /^add_llvm_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 994fb0696ee9..6aee8310463d 100755
--- a/utils/buildit/build_llvm
+++ b/utils/buildit/build_llvm
@@ -133,7 +133,7 @@ if [ \! -f Makefile.config ]; then
|| exit 1
fi
-SUBVERSION=`echo $RC_ProjectSourceVersion | sed -e 's/[^.]*\.\([0-9]*\).*/\1/'`
+SUBVERSION=`echo $RC_ProjectSourceVersion | sed -e 's/.*\.\([0-9]*\).*/\1/'`
if [ "x$SUBVERSION" != "x$RC_ProjectSourceVersion" ]; then
LLVM_SUBMIT_SUBVERSION=`printf "%02d" $SUBVERSION`
diff --git a/utils/findmisopt b/utils/findmisopt
index f2a872c6dc3e..88f991a634c0 100755
--- a/utils/findmisopt
+++ b/utils/findmisopt
@@ -76,8 +76,7 @@ echo " Optimized program: $optprog"
# Define the list of optimizations to run. This comprises the same set of
# optimizations that opt -std-compile-opts and gccld run, in the same order.
opt_switches=`llvm-as < /dev/null -o - | opt -std-compile-opts -disable-output -debug-pass=Arguments 2>&1 | sed 's/Pass Arguments: //'`
-ld_switches=`llvm-as < /dev/null -o - | llvm-ld - -debug-pass=Arguments 2>&1 | sed 's/Pass Arguments: //'`
-all_switches="$opt_switches $ld_switches"
+all_switches="$opt_switches"
echo "Passes : $all_switches"
# Create output directory if it doesn't exist
diff --git a/utils/lit/lit/TestRunner.py b/utils/lit/lit/TestRunner.py
index b5f7986bfe7c..71882b76f8b9 100644
--- a/utils/lit/lit/TestRunner.py
+++ b/utils/lit/lit/TestRunner.py
@@ -23,62 +23,16 @@ kUseCloseFDs = not kIsWindows
# Use temporary files to replace /dev/null on Windows.
kAvoidDevNull = kIsWindows
-# Negate if win32file is not found.
-kHaveWin32File = kIsWindows
-
-def RemoveForce(f):
- try:
- os.remove(f)
- except OSError:
- pass
-
-def WinWaitReleased(f):
- global kHaveWin32File
- if not kHaveWin32File:
- return
- try:
- import time
- import win32file, pywintypes
- retry_cnt = 256
- while True:
- try:
- h = win32file.CreateFile(
- f,
- win32file.GENERIC_READ,
- 0, # Exclusive
- None,
- win32file.OPEN_EXISTING,
- win32file.FILE_ATTRIBUTE_NORMAL,
- None)
- h.close()
- return
- except WindowsError, (winerror, strerror):
- retry_cnt = retry_cnt - 1
- if retry_cnt <= 0:
- raise
- elif winerror == 32: # ERROR_SHARING_VIOLATION
- pass
- else:
- raise
- except pywintypes.error, e:
- retry_cnt = retry_cnt - 1
- if retry_cnt <= 0:
- raise
- elif e[0]== 32: # ERROR_SHARING_VIOLATION
- pass
- else:
- raise
- time.sleep(0.01)
- except ImportError, e:
- kHaveWin32File = False
- return
-
def executeCommand(command, cwd=None, env=None):
+ # Close extra file handles on UNIX (on Windows this cannot be done while
+ # also redirecting input).
+ close_fds = not kIsWindows
+
p = subprocess.Popen(command, cwd=cwd,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
- env=env)
+ env=env, close_fds=close_fds)
out,err = p.communicate()
exitCode = p.wait()
@@ -165,7 +119,6 @@ def executeShCmd(cmd, cfg, cwd, results):
else:
if r[2] is None:
if kAvoidDevNull and r[0] == '/dev/null':
- r[0] = None
r[2] = tempfile.TemporaryFile(mode=r[1])
else:
r[2] = open(r[0], r[1])
@@ -174,7 +127,7 @@ def executeShCmd(cmd, cfg, cwd, results):
# FIXME: Actually, this is probably an instance of PR6753.
if r[1] == 'a':
r[2].seek(0, 2)
- opened_files.append(r)
+ opened_files.append(r[2])
result = r[2]
final_redirects.append(result)
@@ -236,7 +189,7 @@ def executeShCmd(cmd, cfg, cwd, results):
# on Win32, for example). Since we have already spawned the subprocess, our
# handles have already been transferred so we do not need them anymore.
for f in opened_files:
- f[2].close()
+ f.close()
# FIXME: There is probably still deadlock potential here. Yawn.
procData = [None] * len(procs)
@@ -275,15 +228,12 @@ def executeShCmd(cmd, cfg, cwd, results):
else:
exitCode = res
- # Make sure opened_files is released by other (child) processes.
- if kIsWindows:
- for f in opened_files:
- if f[0] is not None:
- WinWaitReleased(f[0])
-
# Remove any named temporary files we created.
for f in named_temp_files:
- RemoveForce(f)
+ try:
+ os.remove(f)
+ except OSError:
+ pass
if cmd.negate:
exitCode = not exitCode
diff --git a/utils/llvm-build/llvmbuild/main.py b/utils/llvm-build/llvmbuild/main.py
index baecc6d89965..27d23d0855d1 100644
--- a/utils/llvm-build/llvmbuild/main.py
+++ b/utils/llvm-build/llvmbuild/main.py
@@ -55,7 +55,7 @@ def make_install_dir(path):
Create the given directory path for installation, including any parents.
"""
- # os.makedirs considers it an error to be called with an existant path.
+ # os.makedirs considers it an error to be called with an existent path.
if not os.path.exists(path):
os.makedirs(path)
diff --git a/utils/llvm-lit/llvm-lit.in b/utils/llvm-lit/llvm-lit.in
index 1df1747a1cc6..879d18bdc84b 100644
--- a/utils/llvm-lit/llvm-lit.in
+++ b/utils/llvm-lit/llvm-lit.in
@@ -8,7 +8,7 @@ llvm_source_root = "@LLVM_SOURCE_DIR@"
llvm_obj_root = "@LLVM_BINARY_DIR@"
# Make sure we can find the lit package.
-sys.path.append(os.path.join(llvm_source_root, 'utils', 'lit'))
+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.
@@ -18,7 +18,8 @@ builtin_parameters = {
'llvm_site_config' : os.path.join(llvm_obj_root, 'test', 'lit.site.cfg')
}
-clang_site_config = os.path.join(llvm_obj_root, 'tools', 'clang', 'test', 'lit.site.cfg')
+clang_site_config = os.path.join(llvm_obj_root, 'tools', 'clang', 'test',
+ 'lit.site.cfg')
if os.path.exists(clang_site_config):
builtin_parameters['clang_site_config'] = clang_site_config
diff --git a/utils/llvm.grm b/utils/llvm.grm
index 322036b2c209..ad2799f2c596 100644
--- a/utils/llvm.grm
+++ b/utils/llvm.grm
@@ -175,6 +175,7 @@ FuncAttr ::= noreturn
| returns_twice
| nonlazybind
| address_safety
+ | ia_nsdialect
;
OptFuncAttrs ::= + _ | OptFuncAttrs FuncAttr ;
diff --git a/utils/obj2yaml/CMakeLists.txt b/utils/obj2yaml/CMakeLists.txt
new file mode 100644
index 000000000000..d64bf1bad866
--- /dev/null
+++ b/utils/obj2yaml/CMakeLists.txt
@@ -0,0 +1,7 @@
+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
new file mode 100644
index 000000000000..5b96bdd5b9d8
--- /dev/null
+++ b/utils/obj2yaml/Makefile
@@ -0,0 +1,20 @@
+##===- 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
new file mode 100644
index 000000000000..c9a71591ef70
--- /dev/null
+++ b/utils/obj2yaml/coff2yaml.cpp
@@ -0,0 +1,362 @@
+//===------ 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
new file mode 100644
index 000000000000..ff253fa13143
--- /dev/null
+++ b/utils/obj2yaml/obj2yaml.cpp
@@ -0,0 +1,89 @@
+//===------ 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
new file mode 100644
index 000000000000..2a23b49682df
--- /dev/null
+++ b/utils/obj2yaml/obj2yaml.h
@@ -0,0 +1,35 @@
+//===------ 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/release/test-release.sh b/utils/release/test-release.sh
index d2946d8762ac..a62e82974aca 100755
--- a/utils/release/test-release.sh
+++ b/utils/release/test-release.sh
@@ -193,7 +193,7 @@ function check_valid_urls() {
done
}
-# Export sources to the the build directory.
+# Export sources to the build directory.
function export_sources() {
check_valid_urls
diff --git a/utils/test_debuginfo.pl b/utils/test_debuginfo.pl
index fb61fb02616d..0832a330f4a0 100755
--- a/utils/test_debuginfo.pl
+++ b/utils/test_debuginfo.pl
@@ -24,7 +24,7 @@ my $debugger_script_file = "$output_dir/$input_filename.debugger.script";
my $output_file = "$output_dir/$input_filename.gdb.output";
# Extract debugger commands from testcase. They are marked with DEBUGGER:
-# at the beginnign of a comment line.
+# at the beginning of a comment line.
open(INPUT, $testcase_file);
open(OUTPUT, ">$debugger_script_file");
while(<INPUT>) {
@@ -49,7 +49,7 @@ if (!$my_debugger) {
my $debugger_options = "-q -batch -n -x";
# run debugger and capture output.
-system("$my_debugger $debugger_options $debugger_script_file $executable_file >& $output_file");
+system("$my_debugger $debugger_options $debugger_script_file $executable_file > $output_file 2>&1");
# validate output.
system("FileCheck", "-input-file", "$output_file", "$testcase_file");
diff --git a/utils/unittest/CMakeLists.txt b/utils/unittest/CMakeLists.txt
index 73491f0721d5..70ed35df2e6c 100644
--- a/utils/unittest/CMakeLists.txt
+++ b/utils/unittest/CMakeLists.txt
@@ -27,6 +27,12 @@ endif()
set(LLVM_REQUIRES_RTTI 1)
add_definitions( -DGTEST_HAS_RTTI=0 )
+# Visual Studio 2012 only supports up to 8 template parameters in
+# std::tr1::tuple by default, but gtest requires 10
+if(MSVC AND MSVC_VERSION EQUAL 1700)
+ add_definitions(-D_VARIADIC_MAX=10)
+endif ()
+
add_llvm_library(gtest
googletest/gtest.cc
googletest/gtest-death-test.cc
diff --git a/utils/unittest/googletest/gtest.cc b/utils/unittest/googletest/gtest.cc
index 3fdff0a9a355..eb5c68c272c0 100644
--- a/utils/unittest/googletest/gtest.cc
+++ b/utils/unittest/googletest/gtest.cc
@@ -1465,7 +1465,7 @@ char* CodePointToUtf8(UInt32 code_point, char* str) {
return str;
}
-// The following two functions only make sense if the the system
+// The following two functions only make sense if the system
// uses UTF-16 for wide string encoding. All supported systems
// with 16 bit wchar_t (Windows, Cygwin, Symbian OS) do use UTF-16.
diff --git a/utils/unittest/googletest/include/gtest/internal/gtest-internal-inl.h b/utils/unittest/googletest/include/gtest/internal/gtest-internal-inl.h
index 65a2101a4d81..6554cfc07e61 100644
--- a/utils/unittest/googletest/include/gtest/internal/gtest-internal-inl.h
+++ b/utils/unittest/googletest/include/gtest/internal/gtest-internal-inl.h
@@ -203,7 +203,6 @@ class GTestFlagSaver {
bool list_tests_;
String output_;
bool print_time_;
- bool pretty_;
internal::Int32 random_seed_;
internal::Int32 repeat_;
bool shuffle_;
diff --git a/utils/unittest/googletest/include/gtest/internal/gtest-internal.h b/utils/unittest/googletest/include/gtest/internal/gtest-internal.h
index b198a3d97a2e..f8a5cc9447b1 100644
--- a/utils/unittest/googletest/include/gtest/internal/gtest-internal.h
+++ b/utils/unittest/googletest/include/gtest/internal/gtest-internal.h
@@ -102,12 +102,11 @@
// but still find raw_ostream& overloads.
namespace llvm {
class convertible_fwd_ostream : public std::ostream {
- std::ostream& os_;
raw_os_ostream ros_;
public:
convertible_fwd_ostream(std::ostream& os)
- : std::ostream(os.rdbuf()), os_(os), ros_(*this) {}
+ : std::ostream(os.rdbuf()), ros_(*this) {}
operator raw_ostream&() { return ros_; }
};
}
diff --git a/utils/vim/llvm.vim b/utils/vim/llvm.vim
index f35f855cab89..c83e8caf8b19 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: 137806 $
+" Version: $Revision: 156080 $
if version < 600
syntax clear
@@ -14,7 +14,7 @@ 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
+syn keyword llvmType void float double half
syn keyword llvmType x86_fp80 fp128 ppc_fp128
syn keyword llvmType type label opaque
syn match llvmType /\<i\d\+\>/
diff --git a/utils/yaml2obj/CMakeLists.txt b/utils/yaml2obj/CMakeLists.txt
new file mode 100644
index 000000000000..f8b119752462
--- /dev/null
+++ b/utils/yaml2obj/CMakeLists.txt
@@ -0,0 +1,5 @@
+add_llvm_utility(yaml2obj
+ yaml2obj.cpp
+ )
+
+target_link_libraries(yaml2obj LLVMSupport)
diff --git a/utils/yaml2obj/Makefile b/utils/yaml2obj/Makefile
new file mode 100644
index 000000000000..e746d8519008
--- /dev/null
+++ b/utils/yaml2obj/Makefile
@@ -0,0 +1,20 @@
+##===- utils/yaml2obj/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 = yaml2obj
+USEDLIBS = 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/yaml2obj/yaml2obj.cpp b/utils/yaml2obj/yaml2obj.cpp
new file mode 100644
index 000000000000..c3b3e5499cde
--- /dev/null
+++ b/utils/yaml2obj/yaml2obj.cpp
@@ -0,0 +1,879 @@
+//===- yaml2obj - Convert YAML to a binary object file --------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This program takes a YAML description of an object file and outputs the
+// binary equivalent.
+//
+// This is used for writing tests that require binary files.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/COFF.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Endian.h"
+#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/system_error.h"
+#include "llvm/Support/YAMLParser.h"
+
+#include <vector>
+
+using namespace llvm;
+
+static cl::opt<std::string>
+ Input(cl::Positional, cl::desc("<input>"), cl::init("-"));
+
+template<class T>
+typename llvm::enable_if_c<std::numeric_limits<T>::is_integer, bool>::type
+getAs(const llvm::yaml::ScalarNode *SN, T &Result) {
+ SmallString<4> Storage;
+ StringRef Value = SN->getValue(Storage);
+ if (Value.getAsInteger(0, Result))
+ return false;
+ return true;
+}
+
+// Given a container with begin and end with ::value_type of a character type.
+// Iterate through pairs of characters in the the set of [a-fA-F0-9] ignoring
+// all other characters.
+struct hex_pair_iterator {
+ StringRef::const_iterator Current, End;
+ typedef SmallVector<char, 2> value_type;
+ value_type Pair;
+ bool IsDone;
+
+ hex_pair_iterator(StringRef C)
+ : Current(C.begin()), End(C.end()), IsDone(false) {
+ // Initalize Pair.
+ ++*this;
+ }
+
+ // End iterator.
+ hex_pair_iterator() : Current(), End(), IsDone(true) {}
+
+ value_type operator *() const {
+ return Pair;
+ }
+
+ hex_pair_iterator operator ++() {
+ // We're at the end of the input.
+ if (Current == End) {
+ IsDone = true;
+ return *this;
+ }
+ Pair = value_type();
+ for (; Current != End && Pair.size() != 2; ++Current) {
+ // Is a valid hex digit.
+ if ((*Current >= '0' && *Current <= '9') ||
+ (*Current >= 'a' && *Current <= 'f') ||
+ (*Current >= 'A' && *Current <= 'F'))
+ Pair.push_back(*Current);
+ }
+ // Hit the end without getting 2 hex digits. Pair is invalid.
+ if (Pair.size() != 2)
+ IsDone = true;
+ return *this;
+ }
+
+ bool operator ==(const hex_pair_iterator Other) {
+ return (IsDone == Other.IsDone) ||
+ (Current == Other.Current && End == Other.End);
+ }
+
+ bool operator !=(const hex_pair_iterator Other) {
+ return !(*this == Other);
+ }
+};
+
+template <class ContainerOut>
+static bool hexStringToByteArray(StringRef Str, ContainerOut &Out) {
+ for (hex_pair_iterator I(Str), E; I != E; ++I) {
+ typename hex_pair_iterator::value_type Pair = *I;
+ typename ContainerOut::value_type Byte;
+ if (StringRef(Pair.data(), 2).getAsInteger(16, Byte))
+ return false;
+ Out.push_back(Byte);
+ }
+ return true;
+}
+
+/// 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) {
+ 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;
+ }
+ 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;
+ } 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;
+ 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");
+ return false;
+ }
+ }
+ }
+ 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;
+ }
+ }
+ 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");
+ 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) {
+ 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;
+ }
+ 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();
+ }
+ Symbols.push_back(Sym);
+ }
+ return true;
+ }
+
+ 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");
+ 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();
+ }
+
+ unsigned getStringIndex(StringRef Str) {
+ StringMap<unsigned>::iterator i = StringTableMap.find(Str);
+ if (i == StringTableMap.end()) {
+ unsigned Index = StringTable.size();
+ StringTable.append(Str.begin(), Str.end());
+ StringTable.push_back(0);
+ StringTableMap[Str] = Index;
+ return Index;
+ }
+ return i->second;
+ }
+
+ yaml::Stream &YS;
+ COFF::header Header;
+
+ struct Section {
+ COFF::section Header;
+ std::vector<uint8_t> Data;
+ std::vector<COFF::relocation> Relocations;
+ };
+
+ struct Symbol {
+ COFF::symbol Header;
+ std::vector<uint8_t> AuxSymbols;
+ };
+
+ std::vector<Section> Sections;
+ std::vector<Symbol> Symbols;
+ StringMap<unsigned> StringTableMap;
+ std::string StringTable;
+};
+
+// Take a CP and assign addresses and sizes to everything. Returns false if the
+// layout is not valid to do.
+static bool layoutCOFF(COFFParser &CP) {
+ uint32_t SectionTableStart = 0;
+ uint32_t SectionTableSize = 0;
+
+ // The section table starts immediately after the header, including the
+ // optional header.
+ SectionTableStart = sizeof(COFF::header) + CP.Header.SizeOfOptionalHeader;
+ SectionTableSize = sizeof(COFF::section) * CP.Sections.size();
+
+ uint32_t CurrentSectionDataOffset = SectionTableStart + SectionTableSize;
+
+ // Assign each section data address consecutively.
+ for (std::vector<COFFParser::Section>::iterator i = CP.Sections.begin(),
+ e = CP.Sections.end();
+ i != e; ++i) {
+ if (!i->Data.empty()) {
+ i->Header.SizeOfRawData = i->Data.size();
+ i->Header.PointerToRawData = CurrentSectionDataOffset;
+ CurrentSectionDataOffset += i->Header.SizeOfRawData;
+ // TODO: Handle alignment.
+ } else {
+ i->Header.SizeOfRawData = 0;
+ i->Header.PointerToRawData = 0;
+ }
+ }
+
+ uint32_t SymbolTableStart = CurrentSectionDataOffset;
+
+ // Calculate number of symbols.
+ uint32_t NumberOfSymbols = 0;
+ for (std::vector<COFFParser::Symbol>::iterator i = CP.Symbols.begin(),
+ e = CP.Symbols.end();
+ i != e; ++i) {
+ if (i->AuxSymbols.size() % COFF::SymbolSize != 0) {
+ errs() << "AuxillaryData size not a multiple of symbol size!\n";
+ return false;
+ }
+ i->Header.NumberOfAuxSymbols = i->AuxSymbols.size() / COFF::SymbolSize;
+ NumberOfSymbols += 1 + i->Header.NumberOfAuxSymbols;
+ }
+
+ // Store all the allocated start addresses in the header.
+ CP.Header.NumberOfSections = CP.Sections.size();
+ CP.Header.NumberOfSymbols = NumberOfSymbols;
+ CP.Header.PointerToSymbolTable = SymbolTableStart;
+
+ *reinterpret_cast<support::ulittle32_t *>(&CP.StringTable[0])
+ = CP.StringTable.size();
+
+ return true;
+}
+
+template <typename value_type>
+struct binary_le_impl {
+ value_type Value;
+ binary_le_impl(value_type V) : Value(V) {}
+};
+
+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);
+ OS.write(Buffer, sizeof(BLE.Value));
+ return OS;
+}
+
+template <typename value_type>
+binary_le_impl<value_type> binary_le(value_type V) {
+ return binary_le_impl<value_type>(V);
+}
+
+void writeCOFF(COFFParser &CP, raw_ostream &OS) {
+ OS << binary_le(CP.Header.Machine)
+ << binary_le(CP.Header.NumberOfSections)
+ << binary_le(CP.Header.TimeDateStamp)
+ << binary_le(CP.Header.PointerToSymbolTable)
+ << binary_le(CP.Header.NumberOfSymbols)
+ << binary_le(CP.Header.SizeOfOptionalHeader)
+ << binary_le(CP.Header.Characteristics);
+
+ // Output section table.
+ for (std::vector<COFFParser::Section>::const_iterator i = CP.Sections.begin(),
+ e = CP.Sections.end();
+ i != e; ++i) {
+ OS.write(i->Header.Name, COFF::NameSize);
+ OS << binary_le(i->Header.VirtualSize)
+ << binary_le(i->Header.VirtualAddress)
+ << binary_le(i->Header.SizeOfRawData)
+ << binary_le(i->Header.PointerToRawData)
+ << binary_le(i->Header.PointerToRelocations)
+ << binary_le(i->Header.PointerToLineNumbers)
+ << binary_le(i->Header.NumberOfRelocations)
+ << binary_le(i->Header.NumberOfLineNumbers)
+ << binary_le(i->Header.Characteristics);
+ }
+
+ // Output section data.
+ for (std::vector<COFFParser::Section>::const_iterator i = CP.Sections.begin(),
+ e = CP.Sections.end();
+ i != e; ++i) {
+ if (!i->Data.empty())
+ OS.write(reinterpret_cast<const char*>(&i->Data[0]), i->Data.size());
+ }
+
+ // Output symbol table.
+
+ for (std::vector<COFFParser::Symbol>::const_iterator i = CP.Symbols.begin(),
+ e = CP.Symbols.end();
+ i != e; ++i) {
+ OS.write(i->Header.Name, COFF::NameSize);
+ OS << binary_le(i->Header.Value)
+ << binary_le(i->Header.SectionNumber)
+ << binary_le(i->Header.Type)
+ << binary_le(i->Header.StorageClass)
+ << binary_le(i->Header.NumberOfAuxSymbols);
+ if (!i->AuxSymbols.empty())
+ OS.write( reinterpret_cast<const char*>(&i->AuxSymbols[0])
+ , i->AuxSymbols.size());
+ }
+
+ // Output string table.
+ OS.write(&CP.StringTable[0], CP.StringTable.size());
+}
+
+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.
+
+ OwningPtr<MemoryBuffer> Buf;
+ if (MemoryBuffer::getFileOrSTDIN(Input, Buf))
+ return 1;
+
+ SourceMgr SM;
+ yaml::Stream S(Buf->getBuffer(), SM);
+ COFFParser CP(S);
+ 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;
+ }
+ writeCOFF(CP, outs());
+}