diff options
author | Shih-wei Liao <sliao@google.com> | 2012-08-03 00:11:18 -0700 |
---|---|---|
committer | Shih-wei Liao <sliao@google.com> | 2012-08-03 00:11:18 -0700 |
commit | 7744acd1ab73b3eec6f1449f47083abe3fb1b527 (patch) | |
tree | 17ef28b6d1034fdea7f42a19bebe7ad834901d62 /utils | |
parent | 4a05ed708aed4c7a099d924ed3feb604d3e44074 (diff) | |
parent | a94d6e87c4c49f2e81b01d66d8bfb591277f8f96 (diff) | |
download | external_llvm-7744acd1ab73b3eec6f1449f47083abe3fb1b527.zip external_llvm-7744acd1ab73b3eec6f1449f47083abe3fb1b527.tar.gz external_llvm-7744acd1ab73b3eec6f1449f47083abe3fb1b527.tar.bz2 |
Merge with LLVM upstream r160668 (Jul 24th 2012)
Conflicts:
include/llvm/Support/ELF.h
lib/CodeGen/AsmPrinter/AsmPrinter.cpp
lib/Support/Memory.cpp
lib/Transforms/Instrumentation/AddressSanitizer.cpp
Change-Id: Iddd658cf2eadc7165b2805b446d31af2c5c9917f
Diffstat (limited to 'utils')
74 files changed, 3571 insertions, 2398 deletions
diff --git a/utils/GetRepositoryPath b/utils/GetRepositoryPath index 326231c..f3b0cc5 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 cbed7da..b57a6aa 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/TableGen/AsmMatcherEmitter.cpp b/utils/TableGen/AsmMatcherEmitter.cpp index 812d81c..0a8ae46 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,9 +1222,9 @@ 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 indices that can be found for /// that class inside a instruction. @@ -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 e04ac10..0000000 --- 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 d079b45..bd153a8 100644 --- a/utils/TableGen/AsmWriterEmitter.cpp +++ b/utils/TableGen/AsmWriterEmitter.cpp @@ -12,7 +12,6 @@ // //===----------------------------------------------------------------------===// -#include "AsmWriterEmitter.h" #include "AsmWriterInst.h" #include "CodeGenTarget.h" #include "StringToOffsetTable.h" @@ -22,9 +21,41 @@ #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 9719b20..0000000 --- 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 2b70f1c..0e14cba 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 afbb3a8..e9c4bd3 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 7bddd6c..0000000 --- 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 ed8ab79..eaa6789 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(); @@ -307,3 +329,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 7f6ee2a..0000000 --- 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 d4b02fb..34f8a34 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 fb9ad93..33381e9 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 468277a..3ba9f24 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 3f6ba61..6efe952 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 45c5bb8..81bf9ed 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; } @@ -154,14 +188,9 @@ bool CodeGenRegister::inheritRegUnits(CodeGenRegBank &RegBank) { 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)); + if (SR == this) continue; - } // Merge the subregister's units into this register's RegUnits. mergeRegUnits(RegUnits, SR->RegUnits); } @@ -169,27 +198,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 +221,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 +236,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. @@ -267,7 +283,7 @@ CodeGenRegister::getSubRegs(CodeGenRegBank &RegBank) { throw TGError(TheDef->getLoc(), "Invalid SubClassIndex in " + Pat->getAsString()); CodeGenSubRegIndex *Idx = RegBank.getSubRegIdx(IdxInit->getDef()); - const SubRegMap &R2Subs = R2->getSubRegs(RegBank); + const SubRegMap &R2Subs = R2->computeSubRegs(RegBank); SubRegMap::const_iterator ni = R2Subs.find(Idx); if (ni == R2Subs.end()) throw TGError(TheDef->getLoc(), "Composite " + Pat->getAsString() + @@ -296,46 +312,275 @@ 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) { + // Ignore idempotent sub-register indices. + if (SI->second == this) + continue; + // Is is possible to have multiple names for the same sub-register. + // For example, XMM0 appears as sub_xmm, sub_sd, and sub_ss in YMM0. + // Eventually, this degeneration should go away, but for now we simply give + // precedence to the explicit sub-register index over the inherited ones. + SubReg2Idx.insert(std::make_pair(SI->second, SI->first)); + } + + // 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); + + if (I->second == this) + continue; + // 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) + if (I->second != this) + 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 +588,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 +707,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 +735,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 +755,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 +769,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 +866,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 +878,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 +919,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 +1004,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 +1090,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 +1117,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 +1160,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 +1295,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 +1331,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 +1390,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 +1405,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 +1566,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 +1669,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 +1682,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 +1697,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 232a6e7..eb6724e 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 0000000..f57fd18 --- /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 0000000..9da0145 --- /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 cf67935..1dd2efc 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 85463da..2f8cee4 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 7db9003..b47dd71 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 9c9fe42..0000000 --- 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 99ebf98..3ca16f0 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 bd425a9..1445edb 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 2ac7b87..aed222c 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 4abf54e..8bfecea 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 1727150..0000000 --- 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 4650197..826465a 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 63ee552..0000000 --- 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 fe484ca..0c8b28d 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 f268375..0000000 --- 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 e8dad77..ca784d0 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 4f75ac1..0000000 --- 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 9b676f2..2cdde55 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 195297c..0000000 --- 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 8b3efd3..3adb869 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 f8d3ea5..0000000 --- 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 8e1bae8..155d1ab 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 f9bcd59..0000000 --- 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 802d112..8d9d419 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 325bc8b..0000000 --- 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 97fcca3..3d8d515 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" @@ -439,20 +487,52 @@ static void printSimpleValueType(raw_ostream &OS, MVT::SimpleValueType VT) { OS << getEnumName(VT); } +static void printSubRegIndex(raw_ostream &OS, const CodeGenSubRegIndex *Idx) { + OS << Idx->getQualifiedName(); +} + +// 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; +} + +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. @@ -461,10 +541,19 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target, SmallVector<RegVec, 4> OverlapLists(Regs.size()); SequenceToOffsetTable<RegVec, CodeGenRegister::Less> RegSeqs; + // Differentially encoded lists. + SequenceToOffsetTable<DiffVec> DiffSeqs; + SmallVector<DiffVec, 4> RegUnitLists(Regs.size()); + SmallVector<unsigned, 4> RegUnitInitScale(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); @@ -489,7 +578,8 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target, Omit.insert(Reg); // Any elements not in Suffix. - const CodeGenRegister::Set &OSet = Overlaps[Reg]; + CodeGenRegister::Set OSet; + Reg->computeOverlaps(OSet, RegBank); std::set_difference(OSet.begin(), OSet.end(), Omit.begin(), Omit.end(), std::back_inserter(OverlapList), @@ -498,10 +588,36 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target, // Finally, Suffix itself. OverlapList.insert(OverlapList.end(), Suffix.begin(), Suffix.end()); RegSeqs.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(); OS << "namespace llvm {\n\n"; @@ -512,20 +628,46 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target, RegSeqs.emit(OS, printRegister); OS << "};\n\n"; + // Emit the shared table of differential lists. + OS << "extern const uint16_t " << TargetName << "RegDiffLists[] = {\n"; + DiffSeqs.emit(OS, printDiff16); + 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 },\n"; // Emit the register descriptors now. for (unsigned i = 0, e = Regs.size(); i != e; ++i) { const CodeGenRegister *Reg = Regs[i]; - OS << " { \"" << Reg->getName() << "\", " + OS << " { " << RegStrings.get(Reg->getName()) << ", " << RegSeqs.get(OverlapLists[i]) << ", " << RegSeqs.get(SubRegLists[i]) << ", " - << RegSeqs.get(Reg->getSuperRegs()) << " },\n"; + << RegSeqs.get(Reg->getSuperRegs()) << ", " + << (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. @@ -621,18 +763,42 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target, 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, " << Regs.size()+1 << ", RA, " << TargetName << "MCRegisterClasses, " - << RegisterClasses.size() << ", " << TargetName << "RegLists, "; + << RegisterClasses.size() << ", " + << TargetName << "RegUnitRoots, " + << RegBank.getNumNativeRegUnits() << ", " + << TargetName << "RegLists, " + << TargetName << "RegDiffLists, " + << TargetName << "RegStrings, "; if (SubRegIndices.size() != 0) OS << "(uint16_t*)" << TargetName << "SubRegTable, " - << SubRegIndices.size() << ");\n\n"; + << SubRegIndices.size() << ",\n"; else - OS << "NULL, 0);\n\n"; + OS << "NULL, 0,\n"; + + OS << " " << TargetName << "RegEncodingTable);\n\n"; EmitRegMapping(OS, Regs, false); @@ -645,7 +811,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 +827,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 +854,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 +867,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 +880,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 +903,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 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 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 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 +1042,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 +1082,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 +1141,21 @@ 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"; + << " return TV ? getRegClass(TV - 1) : 0;\n}\n\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"; - } - 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"; + OS << "extern const uint16_t " << TargetName << "RegDiffLists[];\n"; + OS << "extern const char " << TargetName << "RegStrings[];\n"; + OS << "extern const uint16_t " << TargetName << "RegUnitRoots[][2];\n"; if (SubRegIndices.size() != 0) OS << "extern const uint16_t *get" << TargetName << "SubRegTable();\n"; + OS << "extern const uint16_t " << TargetName << "RegEncodingTable[];\n"; EmitRegMappingTables(OS, Regs, true); @@ -1057,17 +1163,23 @@ 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 << "RegUnitRoots,\n" + << " " << RegBank.getNumNativeRegUnits() << ",\n" << " " << TargetName << "RegLists,\n" + << " " << TargetName << "RegDiffLists,\n" + << " " << TargetName << "RegStrings,\n" << " "; if (SubRegIndices.size() != 0) OS << "get" << TargetName << "SubRegTable(), " - << SubRegIndices.size() << ");\n\n"; + << SubRegIndices.size() << ",\n"; else - OS << "NULL, 0);\n\n"; + OS << "NULL, 0,\n"; + + OS << " " << TargetName << "RegEncodingTable);\n\n"; EmitRegMapping(OS, Regs, true); @@ -1111,3 +1223,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 ee9903c..0000000 --- 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 97c764e..d8ab2ee 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 0649fd1..46e6db1 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 6aedcbf..0000000 --- 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 1dadc76..0000000 --- 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/SubtargetEmitter.cpp b/utils/TableGen/SubtargetEmitter.cpp index 986c50f..b3bf4aa 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,99 @@ 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", ','); + if (SchedModels.hasItineraryClasses()) + OS << " " << PI->ItinsDef->getName(); + else + OS << " 0"; + OS << ");\n"; + } +} + // // EmitProcessorLookup - generate cpu name to itinerary lookup table. // @@ -547,7 +611,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 +619,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 +640,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 +672,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 +706,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 +727,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 +746,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 +792,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 +811,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 +823,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 ff01274..0000000 --- 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 8c41358..9695b4a 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 0000000..2c00c40 --- /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/X86RecognizableInstr.cpp b/utils/TableGen/X86RecognizableInstr.cpp index 6a01cce..6a685ff 100644 --- a/utils/TableGen/X86RecognizableInstr.cpp +++ b/utils/TableGen/X86RecognizableInstr.cpp @@ -62,11 +62,11 @@ namespace X86Local { 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 }; @@ -277,8 +277,8 @@ RecognizableInstr::RecognizableInstr(DisassemblerTables &tables, } 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")) @@ -508,13 +508,13 @@ bool RecognizableInstr::has256BitOperands() const { 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; @@ -563,7 +563,6 @@ void RecognizableInstr::emitInstructionSpecifier(DisassemblerTables &tables) { const std::vector<CGIOperandList::OperandInfo> &OperandList = *Operands; - unsigned operandIndex; unsigned numOperands = OperandList.size(); unsigned numPhysicalOperands = 0; @@ -575,12 +574,13 @@ void RecognizableInstr::emitInstructionSpecifier(DisassemblerTables &tables) { 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; @@ -621,7 +621,7 @@ void RecognizableInstr::emitInstructionSpecifier(DisassemblerTables &tables) { class##EncodingFromString); // operandIndex should always be < numOperands - operandIndex = 0; + unsigned operandIndex = 0; // physicalOperandIndex should always be < numPhysicalOperands unsigned physicalOperandIndex = 0; @@ -690,12 +690,13 @@ 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"); else - assert(numPhysicalOperands >= 2 && numPhysicalOperands <= 3 && + assert(numPhysicalOperands >= 2 && numPhysicalOperands <= 4 && "Unexpected number of operands for MRMSrcRegFrm"); HANDLE_OPERAND(roRegister) @@ -716,6 +717,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. @@ -759,16 +761,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: @@ -1140,6 +1144,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 +1251,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 6c0a234..542e510 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/findmisopt b/utils/findmisopt index f2a872c..88f991a 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 b5f7986..71882b7 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/componentinfo.py b/utils/llvm-build/llvmbuild/componentinfo.py index 230ae21..e684ac2 100644 --- a/utils/llvm-build/llvmbuild/componentinfo.py +++ b/utils/llvm-build/llvmbuild/componentinfo.py @@ -68,6 +68,21 @@ class ComponentInfo(object): def get_llvmbuild_fragment(self): abstract + def get_parent_target_group(self): + """get_parent_target_group() -> ComponentInfo or None + + Return the nearest parent target group (if any), or None if the + component is not part of any target group. + """ + + # If this is a target group, return it. + if self.type_name == 'TargetGroup': + return self + + # Otherwise recurse on the parent, if any. + if self.parent_instance: + return self.parent_instance.get_parent_target_group() + class GroupComponentInfo(ComponentInfo): """ Group components have no semantics as far as the build system are concerned, @@ -95,16 +110,22 @@ class LibraryComponentInfo(ComponentInfo): type_name = 'Library' @staticmethod - def parse(subpath, items): + def parse_items(items): kwargs = ComponentInfo.parse_items(items) kwargs['library_name'] = items.get_optional_string('library_name') kwargs['required_libraries'] = items.get_list('required_libraries') kwargs['add_to_library_groups'] = items.get_list( 'add_to_library_groups') + kwargs['installed'] = items.get_optional_bool('installed', True) + return kwargs + + @staticmethod + def parse(subpath, items): + kwargs = LibraryComponentInfo.parse_items(items) return LibraryComponentInfo(subpath, **kwargs) def __init__(self, subpath, name, dependencies, parent, library_name, - required_libraries, add_to_library_groups): + required_libraries, add_to_library_groups, installed): ComponentInfo.__init__(self, subpath, name, dependencies, parent) # If given, the name to use for the library instead of deriving it from @@ -119,6 +140,9 @@ class LibraryComponentInfo(ComponentInfo): # considered part of. self.add_to_library_groups = list(add_to_library_groups) + # Whether or not this library is installed. + self.installed = installed + def get_component_references(self): for r in ComponentInfo.get_component_references(self): yield r @@ -140,6 +164,8 @@ class LibraryComponentInfo(ComponentInfo): if self.add_to_library_groups: print >>result, 'add_to_library_groups = %s' % ' '.join( self.add_to_library_groups) + if not self.installed: + print >>result, 'installed = 0' return result.getvalue() def get_library_name(self): @@ -165,6 +191,20 @@ class LibraryComponentInfo(ComponentInfo): def get_llvmconfig_component_name(self): return self.get_library_name().lower() +class OptionalLibraryComponentInfo(LibraryComponentInfo): + type_name = "OptionalLibrary" + + @staticmethod + def parse(subpath, items): + kwargs = LibraryComponentInfo.parse_items(items) + return OptionalLibraryComponentInfo(subpath, **kwargs) + + def __init__(self, subpath, name, dependencies, parent, library_name, + required_libraries, add_to_library_groups, installed): + LibraryComponentInfo.__init__(self, subpath, name, dependencies, parent, + library_name, required_libraries, + add_to_library_groups, installed) + class LibraryGroupComponentInfo(ComponentInfo): type_name = 'LibraryGroup' @@ -375,7 +415,7 @@ _component_type_map = dict( for t in (GroupComponentInfo, LibraryComponentInfo, LibraryGroupComponentInfo, ToolComponentInfo, BuildToolComponentInfo, - TargetGroupComponentInfo)) + TargetGroupComponentInfo, OptionalLibraryComponentInfo)) def load_from_path(path, subpath): # Load the LLVMBuild.txt file as an .ini format file. parser = ConfigParser.RawConfigParser() diff --git a/utils/llvm-build/llvmbuild/main.py b/utils/llvm-build/llvmbuild/main.py index 36bca87..27d23d0 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) @@ -312,15 +312,26 @@ subdirectories = %s f.close() - def write_library_table(self, output_path): + def write_library_table(self, output_path, enabled_optional_components): # Write out the mapping from component names to required libraries. # # We do this in topological order so that we know we can append the # dependencies for added library groups. entries = {} for c in self.ordered_component_infos: + # Skip optional components which are not enabled. + if c.type_name == 'OptionalLibrary' \ + and c.name not in enabled_optional_components: + continue + + # Skip target groups which are not enabled. + tg = c.get_parent_target_group() + if tg and not tg.enabled: + continue + # Only certain components are in the table. - if c.type_name not in ('Library', 'LibraryGroup', 'TargetGroup'): + if c.type_name not in ('Library', 'OptionalLibrary', \ + 'LibraryGroup', 'TargetGroup'): continue # Compute the llvm-config "component name". For historical reasons, @@ -328,10 +339,12 @@ subdirectories = %s llvmconfig_component_name = c.get_llvmconfig_component_name() # Get the library name, or None for LibraryGroups. - if c.type_name == 'Library': + if c.type_name == 'Library' or c.type_name == 'OptionalLibrary': library_name = c.get_prefixed_library_name() + is_installed = c.installed else: library_name = None + is_installed = True # Get the component names of all the required libraries. required_llvmconfig_component_names = [ @@ -344,7 +357,8 @@ subdirectories = %s # Add the entry. entries[c.name] = (llvmconfig_component_name, library_name, - required_llvmconfig_component_names) + required_llvmconfig_component_names, + is_installed) # Convert to a list of entries and sort by name. entries = entries.values() @@ -352,16 +366,16 @@ subdirectories = %s # Create an 'all' pseudo component. We keep the dependency list small by # only listing entries that have no other dependents. root_entries = set(e[0] for e in entries) - for _,_,deps in entries: + for _,_,deps,_ in entries: root_entries -= set(deps) - entries.append(('all', None, root_entries)) + entries.append(('all', None, root_entries, True)) entries.sort() # Compute the maximum number of required libraries, plus one so there is # always a sentinel. max_required_libraries = max(len(deps) - for _,_,deps in entries) + 1 + for _,_,deps,_ in entries) + 1 # Write out the library table. make_install_dir(os.path.dirname(output_path)) @@ -382,18 +396,21 @@ subdirectories = %s print >>f, ' /// The name of the library for this component (or NULL).' print >>f, ' const char *Library;' print >>f, '' + print >>f, ' /// Whether the component is installed.' + print >>f, ' bool IsInstalled;' + print >>f, '' print >>f, '\ /// The list of libraries required when linking this component.' print >>f, ' const char *RequiredLibraries[%d];' % ( max_required_libraries) print >>f, '} AvailableComponents[%d] = {' % len(entries) - for name,library_name,required_names in entries: + for name,library_name,required_names,is_installed in entries: if library_name is None: library_name_as_cstr = '0' else: library_name_as_cstr = '"lib%s.a"' % library_name - print >>f, ' { "%s", %s, { %s } },' % ( - name, library_name_as_cstr, + print >>f, ' { "%s", %s, %d, { %s } },' % ( + name, library_name_as_cstr, is_installed, ', '.join('"%s"' % dep for dep in required_names)) print >>f, '};' @@ -778,6 +795,11 @@ given by --build-root) at the same SUBPATH""", help=("Enable the given space or semi-colon separated " "list of targets, or all targets if not present"), action="store", default=None) + group.add_option("", "--enable-optional-components", + dest="optional_components", metavar="NAMES", + help=("Enable the given space or semi-colon separated " + "list of optional components"), + action="store", default=None) parser.add_option_group(group) (opts, args) = parser.parse_args() @@ -819,7 +841,8 @@ given by --build-root) at the same SUBPATH""", # Write out the required library table, if requested. if opts.write_library_table: - project_info.write_library_table(opts.write_library_table) + project_info.write_library_table(opts.write_library_table, + opts.optional_components) # Write out the make fragment, if requested. if opts.write_make_fragment: diff --git a/utils/llvm-lit/llvm-lit.in b/utils/llvm-lit/llvm-lit.in index 1df1747..879d18b 100755 --- 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/obj2yaml/CMakeLists.txt b/utils/obj2yaml/CMakeLists.txt new file mode 100644 index 0000000..d64bf1b --- /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 0000000..5b96bdd --- /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 0000000..2dbd531 --- /dev/null +++ b/utils/obj2yaml/coff2yaml.cpp @@ -0,0 +1,361 @@ +//===------ 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; + + 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 0000000..ff253fa --- /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 0000000..2a23b49 --- /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/findRegressions-nightly.py b/utils/release/findRegressions-nightly.py index e801dab..ddf8983 100755 --- a/utils/release/findRegressions-nightly.py +++ b/utils/release/findRegressions-nightly.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python import re, string, sys, os, time DEBUG = 0 diff --git a/utils/release/findRegressions-simple.py b/utils/release/findRegressions-simple.py index 7586231..8d3b4cf 100755 --- a/utils/release/findRegressions-simple.py +++ b/utils/release/findRegressions-simple.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python import re, string, sys, os, time, math DEBUG = 0 diff --git a/utils/release/test-release.sh b/utils/release/test-release.sh index d2946d8..a62e829 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 fb61fb0..0832a33 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 73491f0..70ed35d 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/LLVMBuild.txt b/utils/unittest/LLVMBuild.txt index 2810567..c276dd6 100644 --- a/utils/unittest/LLVMBuild.txt +++ b/utils/unittest/LLVMBuild.txt @@ -20,9 +20,11 @@ type = Library name = gtest parent = Libraries required_libraries = Support +installed = 0 [component_1] type = Library name = gtest_main parent = Libraries required_libraries = gtest +installed = 0 diff --git a/utils/unittest/googletest/gtest.cc b/utils/unittest/googletest/gtest.cc index 3fdff0a..eb5c68c 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 65a2101..6554cfc 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 b198a3d..f8a5cc9 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 c9ee28e..9cd483d 100644 --- a/utils/vim/llvm.vim +++ b/utils/vim/llvm.vim @@ -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\+\>/ |