diff options
author | rdivacky <rdivacky@FreeBSD.org> | 2009-10-14 17:57:32 +0000 |
---|---|---|
committer | rdivacky <rdivacky@FreeBSD.org> | 2009-10-14 17:57:32 +0000 |
commit | cd749a9c07f1de2fb8affde90537efa4bc3e7c54 (patch) | |
tree | b21f6de4e08b89bb7931806bab798fc2a5e3a686 /utils/TableGen | |
parent | 72621d11de5b873f1695f391eb95f0b336c3d2d4 (diff) | |
download | FreeBSD-src-cd749a9c07f1de2fb8affde90537efa4bc3e7c54.zip FreeBSD-src-cd749a9c07f1de2fb8affde90537efa4bc3e7c54.tar.gz |
Update llvm to r84119.
Diffstat (limited to 'utils/TableGen')
27 files changed, 2668 insertions, 704 deletions
diff --git a/utils/TableGen/AsmMatcherEmitter.cpp b/utils/TableGen/AsmMatcherEmitter.cpp new file mode 100644 index 0000000..3eac9d2 --- /dev/null +++ b/utils/TableGen/AsmMatcherEmitter.cpp @@ -0,0 +1,1545 @@ +//===- AsmMatcherEmitter.cpp - Generate an assembly matcher ---------------===// +// +// 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. +// +// The input to the target specific matcher is a list of literal tokens and +// operands. The target specific parser should generally eliminate any syntax +// which is not relevant for matching; for example, comma tokens should have +// already been consumed and eliminated by the parser. Most instructions will +// end up with a single literal token (the instruction name) and some number of +// operands. +// +// Some example inputs, for X86: +// 'addl' (immediate ...) (register ...) +// 'add' (immediate ...) (memory ...) +// 'call' '*' %epc +// +// The assembly matcher is responsible for converting this input into a precise +// machine instruction (i.e., an instruction with a well defined encoding). This +// mapping has several properties which complicate matching: +// +// - It may be ambiguous; many architectures can legally encode particular +// variants of an instruction in different ways (for example, using a smaller +// encoding for small immediates). Such ambiguities should never be +// arbitrarily resolved by the assembler, the assembler is always responsible +// for choosing the "best" available instruction. +// +// - It may depend on the subtarget or the assembler context. Instructions +// which are invalid for the current mode, but otherwise unambiguous (e.g., +// an SSE instruction in a file being assembled for i486) should be accepted +// and rejected by the assembler front end. However, if the proper encoding +// for an instruction is dependent on the assembler context then the matcher +// is responsible for selecting the correct machine instruction for the +// current mode. +// +// The core matching algorithm attempts to exploit the regularity in most +// instruction sets to quickly determine the set of possibly matching +// instructions, and the simplify the generated code. Additionally, this helps +// to ensure that the ambiguities are intentionally resolved by the user. +// +// The matching is divided into two distinct phases: +// +// 1. Classification: Each operand is mapped to the unique set which (a) +// contains it, and (b) is the largest such subset for which a single +// instruction could match all members. +// +// For register classes, we can generate these subgroups automatically. For +// arbitrary operands, we expect the user to define the classes and their +// relations to one another (for example, 8-bit signed immediates as a +// subset of 32-bit immediates). +// +// By partitioning the operands in this way, we guarantee that for any +// tuple of classes, any single instruction must match either all or none +// of the sets of operands which could classify to that tuple. +// +// In addition, the subset relation amongst classes induces a partial order +// on such tuples, which we use to resolve ambiguities. +// +// FIXME: What do we do if a crazy case shows up where this is the wrong +// resolution? +// +// 2. The input can now be treated as a tuple of classes (static tokens are +// simple singleton sets). Each such tuple should generally map to a single +// instruction (we currently ignore cases where this isn't true, whee!!!), +// which we can emit a simple matcher for. +// +//===----------------------------------------------------------------------===// + +#include "AsmMatcherEmitter.h" +#include "CodeGenTarget.h" +#include "Record.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include <list> +#include <map> +#include <set> +using namespace llvm; + +static cl::opt<std::string> +MatchPrefix("match-prefix", cl::init(""), + cl::desc("Only match instructions with the given prefix")); + +/// FlattenVariants - Flatten an .td file assembly string by selecting the +/// variant at index \arg N. +static std::string FlattenVariants(const std::string &AsmString, + unsigned N) { + StringRef Cur = AsmString; + std::string Res = ""; + + for (;;) { + // Find the start of the next variant string. + size_t VariantsStart = 0; + for (size_t e = Cur.size(); VariantsStart != e; ++VariantsStart) + if (Cur[VariantsStart] == '{' && + (VariantsStart == 0 || (Cur[VariantsStart-1] != '$' && + Cur[VariantsStart-1] != '\\'))) + break; + + // Add the prefix to the result. + Res += Cur.slice(0, VariantsStart); + if (VariantsStart == Cur.size()) + break; + + ++VariantsStart; // Skip the '{'. + + // Scan to the end of the variants string. + size_t VariantsEnd = VariantsStart; + unsigned NestedBraces = 1; + for (size_t e = Cur.size(); VariantsEnd != e; ++VariantsEnd) { + if (Cur[VariantsEnd] == '}' && Cur[VariantsEnd-1] != '\\') { + if (--NestedBraces == 0) + break; + } else if (Cur[VariantsEnd] == '{') + ++NestedBraces; + } + + // Select the Nth variant (or empty). + StringRef Selection = Cur.slice(VariantsStart, VariantsEnd); + for (unsigned i = 0; i != N; ++i) + Selection = Selection.split('|').second; + Res += Selection.split('|').first; + + assert(VariantsEnd != Cur.size() && + "Unterminated variants in assembly string!"); + Cur = Cur.substr(VariantsEnd + 1); + } + + return Res; +} + +/// TokenizeAsmString - Tokenize a simplified assembly string. +static void TokenizeAsmString(const StringRef &AsmString, + SmallVectorImpl<StringRef> &Tokens) { + unsigned Prev = 0; + bool InTok = true; + for (unsigned i = 0, e = AsmString.size(); i != e; ++i) { + switch (AsmString[i]) { + case '[': + case ']': + case '*': + case '!': + case ' ': + case '\t': + case ',': + if (InTok) { + Tokens.push_back(AsmString.slice(Prev, i)); + InTok = false; + } + if (!isspace(AsmString[i]) && AsmString[i] != ',') + Tokens.push_back(AsmString.substr(i, 1)); + Prev = i + 1; + break; + + case '\\': + if (InTok) { + Tokens.push_back(AsmString.slice(Prev, i)); + InTok = false; + } + ++i; + assert(i != AsmString.size() && "Invalid quoted character"); + Tokens.push_back(AsmString.substr(i, 1)); + Prev = i + 1; + break; + + case '$': { + // If this isn't "${", treat like a normal token. + if (i + 1 == AsmString.size() || AsmString[i + 1] != '{') { + if (InTok) { + Tokens.push_back(AsmString.slice(Prev, i)); + InTok = false; + } + Prev = i; + break; + } + + if (InTok) { + Tokens.push_back(AsmString.slice(Prev, i)); + InTok = false; + } + + StringRef::iterator End = + std::find(AsmString.begin() + i, AsmString.end(), '}'); + assert(End != AsmString.end() && "Missing brace in operand reference!"); + size_t EndPos = End - AsmString.begin(); + Tokens.push_back(AsmString.slice(i, EndPos+1)); + Prev = EndPos + 1; + i = EndPos; + break; + } + + default: + InTok = true; + } + } + if (InTok && Prev != AsmString.size()) + Tokens.push_back(AsmString.substr(Prev)); +} + +static bool IsAssemblerInstruction(const StringRef &Name, + const CodeGenInstruction &CGI, + const SmallVectorImpl<StringRef> &Tokens) { + // Ignore "codegen only" instructions. + if (CGI.TheDef->getValueAsBit("isCodeGenOnly")) + return false; + + // Ignore pseudo ops. + // + // FIXME: This is a hack; can we convert these instructions to set the + // "codegen only" bit instead? + if (const RecordVal *Form = CGI.TheDef->getValue("Form")) + if (Form->getValue()->getAsString() == "Pseudo") + return false; + + // Ignore "Int_*" and "*_Int" instructions, which are internal aliases. + // + // FIXME: This is a total hack. + if (StringRef(Name).startswith("Int_") || StringRef(Name).endswith("_Int")) + return false; + + // Ignore instructions with no .s string. + // + // FIXME: What are these? + if (CGI.AsmString.empty()) + return false; + + // FIXME: Hack; ignore any instructions with a newline in them. + if (std::find(CGI.AsmString.begin(), + CGI.AsmString.end(), '\n') != CGI.AsmString.end()) + return false; + + // Ignore instructions with attributes, these are always fake instructions for + // simplifying codegen. + // + // FIXME: Is this true? + // + // Also, check for instructions which reference the operand multiple times; + // this implies a constraint we would not honor. + std::set<std::string> OperandNames; + for (unsigned i = 1, e = Tokens.size(); i < e; ++i) { + if (Tokens[i][0] == '$' && + std::find(Tokens[i].begin(), + Tokens[i].end(), ':') != Tokens[i].end()) { + DEBUG({ + errs() << "warning: '" << Name << "': " + << "ignoring instruction; operand with attribute '" + << Tokens[i] << "'\n"; + }); + return false; + } + + if (Tokens[i][0] == '$' && !OperandNames.insert(Tokens[i]).second) { + std::string Err = "'" + Name.str() + "': " + + "invalid assembler instruction; tied operand '" + Tokens[i].str() + "'"; + throw TGError(CGI.TheDef->getLoc(), Err); + } + } + + return true; +} + +namespace { + +/// ClassInfo - Helper class for storing the information about a particular +/// class of operands which can be matched. +struct ClassInfo { + enum ClassInfoKind { + /// Invalid kind, for use as a sentinel value. + Invalid = 0, + + /// The class for a particular token. + Token, + + /// The (first) register class, subsequent register classes are + /// RegisterClass0+1, and so on. + RegisterClass0, + + /// The (first) user defined class, subsequent user defined classes are + /// UserClass0+1, and so on. + UserClass0 = 1<<16 + }; + + /// Kind - The class kind, which is either a predefined kind, or (UserClass0 + + /// N) for the Nth user defined class. + unsigned Kind; + + /// SuperClasses - The super classes of this class. Note that for simplicities + /// sake user operands only record their immediate super class, while register + /// operands include all superclasses. + std::vector<ClassInfo*> SuperClasses; + + /// Name - The full class name, suitable for use in an enum. + std::string Name; + + /// ClassName - The unadorned generic name for this class (e.g., Token). + std::string ClassName; + + /// ValueName - The name of the value this class represents; for a token this + /// is the literal token string, for an operand it is the TableGen class (or + /// empty if this is a derived class). + std::string ValueName; + + /// PredicateMethod - The name of the operand method to test whether the + /// operand matches this class; this is not valid for Token or register kinds. + std::string PredicateMethod; + + /// RenderMethod - The name of the operand method to add this operand to an + /// MCInst; this is not valid for Token or register kinds. + std::string RenderMethod; + + /// For register classes, the records for all the registers in this class. + std::set<Record*> Registers; + +public: + /// isRegisterClass() - Check if this is a register class. + bool isRegisterClass() const { + return Kind >= RegisterClass0 && Kind < UserClass0; + } + + /// isUserClass() - Check if this is a user defined class. + bool isUserClass() const { + return Kind >= UserClass0; + } + + /// isRelatedTo - Check whether this class is "related" to \arg RHS. Classes + /// are related if they are in the same class hierarchy. + bool isRelatedTo(const ClassInfo &RHS) const { + // Tokens are only related to tokens. + if (Kind == Token || RHS.Kind == Token) + return Kind == Token && RHS.Kind == Token; + + // Registers classes are only related to registers classes, and only if + // their intersection is non-empty. + if (isRegisterClass() || RHS.isRegisterClass()) { + if (!isRegisterClass() || !RHS.isRegisterClass()) + return false; + + std::set<Record*> Tmp; + std::insert_iterator< std::set<Record*> > II(Tmp, Tmp.begin()); + std::set_intersection(Registers.begin(), Registers.end(), + RHS.Registers.begin(), RHS.Registers.end(), + II); + + return !Tmp.empty(); + } + + // Otherwise we have two users operands; they are related if they are in the + // same class hierarchy. + // + // FIXME: This is an oversimplification, they should only be related if they + // intersect, however we don't have that information. + assert(isUserClass() && RHS.isUserClass() && "Unexpected class!"); + const ClassInfo *Root = this; + while (!Root->SuperClasses.empty()) + Root = Root->SuperClasses.front(); + + const ClassInfo *RHSRoot = &RHS; + while (!RHSRoot->SuperClasses.empty()) + RHSRoot = RHSRoot->SuperClasses.front(); + + return Root == RHSRoot; + } + + /// isSubsetOf - Test whether this class is a subset of \arg RHS; + bool isSubsetOf(const ClassInfo &RHS) const { + // This is a subset of RHS if it is the same class... + if (this == &RHS) + return true; + + // ... or if any of its super classes are a subset of RHS. + for (std::vector<ClassInfo*>::const_iterator it = SuperClasses.begin(), + ie = SuperClasses.end(); it != ie; ++it) + if ((*it)->isSubsetOf(RHS)) + return true; + + return false; + } + + /// operator< - Compare two classes. + bool operator<(const ClassInfo &RHS) const { + // Unrelated classes can be ordered by kind. + if (!isRelatedTo(RHS)) + return Kind < RHS.Kind; + + switch (Kind) { + case Invalid: + assert(0 && "Invalid kind!"); + case Token: + // Tokens are comparable by value. + // + // FIXME: Compare by enum value. + return ValueName < RHS.ValueName; + + default: + // This class preceeds the RHS if it is a proper subset of the RHS. + return this != &RHS && isSubsetOf(RHS); + } + } +}; + +/// InstructionInfo - Helper class for storing the necessary information for an +/// instruction which is capable of being matched. +struct InstructionInfo { + struct Operand { + /// The unique class instance this operand should match. + ClassInfo *Class; + + /// The original operand this corresponds to, if any. + const CodeGenInstruction::OperandInfo *OperandInfo; + }; + + /// InstrName - The target name for this instruction. + std::string InstrName; + + /// Instr - The instruction this matches. + const CodeGenInstruction *Instr; + + /// AsmString - The assembly string for this instruction (with variants + /// removed). + std::string AsmString; + + /// Tokens - The tokenized assembly pattern that this instruction matches. + SmallVector<StringRef, 4> Tokens; + + /// Operands - The operands that this instruction matches. + SmallVector<Operand, 4> Operands; + + /// ConversionFnKind - The enum value which is passed to the generated + /// ConvertToMCInst to convert parsed operands into an MCInst for this + /// function. + std::string ConversionFnKind; + + /// operator< - Compare two instructions. + bool operator<(const InstructionInfo &RHS) const { + if (Operands.size() != RHS.Operands.size()) + return Operands.size() < RHS.Operands.size(); + + // Compare lexicographically by operand. The matcher validates that other + // orderings wouldn't be ambiguous using \see CouldMatchAmiguouslyWith(). + for (unsigned i = 0, e = Operands.size(); i != e; ++i) { + if (*Operands[i].Class < *RHS.Operands[i].Class) + return true; + if (*RHS.Operands[i].Class < *Operands[i].Class) + return false; + } + + return false; + } + + /// CouldMatchAmiguouslyWith - Check whether this instruction could + /// ambiguously match the same set of operands as \arg RHS (without being a + /// strictly superior match). + bool CouldMatchAmiguouslyWith(const InstructionInfo &RHS) { + // The number of operands is unambiguous. + if (Operands.size() != RHS.Operands.size()) + return false; + + // Tokens and operand kinds are unambiguous (assuming a correct target + // specific parser). + for (unsigned i = 0, e = Operands.size(); i != e; ++i) + if (Operands[i].Class->Kind != RHS.Operands[i].Class->Kind || + Operands[i].Class->Kind == ClassInfo::Token) + if (*Operands[i].Class < *RHS.Operands[i].Class || + *RHS.Operands[i].Class < *Operands[i].Class) + return false; + + // Otherwise, this operand could commute if all operands are equivalent, or + // there is a pair of operands that compare less than and a pair that + // compare greater than. + bool HasLT = false, HasGT = false; + for (unsigned i = 0, e = Operands.size(); i != e; ++i) { + if (*Operands[i].Class < *RHS.Operands[i].Class) + HasLT = true; + if (*RHS.Operands[i].Class < *Operands[i].Class) + HasGT = true; + } + + return !(HasLT ^ HasGT); + } + +public: + void dump(); +}; + +class AsmMatcherInfo { +public: + /// The tablegen AsmParser record. + Record *AsmParser; + + /// The AsmParser "CommentDelimiter" value. + std::string CommentDelimiter; + + /// The AsmParser "RegisterPrefix" value. + std::string RegisterPrefix; + + /// The classes which are needed for matching. + std::vector<ClassInfo*> Classes; + + /// The information on the instruction to match. + std::vector<InstructionInfo*> Instructions; + + /// Map of Register records to their class information. + std::map<Record*, ClassInfo*> RegisterClasses; + +private: + /// Map of token to class information which has already been constructed. + std::map<std::string, ClassInfo*> TokenClasses; + + /// 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(const StringRef &Token); + + /// getOperandClass - Lookup or create the class for the given operand. + ClassInfo *getOperandClass(const StringRef &Token, + const CodeGenInstruction::OperandInfo &OI); + + /// BuildRegisterClasses - Build the ClassInfo* instances for register + /// classes. + void BuildRegisterClasses(CodeGenTarget &Target, + std::set<std::string> &SingletonRegisterNames); + + /// BuildOperandClasses - Build the ClassInfo* instances for user defined + /// operand classes. + void BuildOperandClasses(CodeGenTarget &Target); + +public: + AsmMatcherInfo(Record *_AsmParser); + + /// BuildInfo - Construct the various tables used during matching. + void BuildInfo(CodeGenTarget &Target); +}; + +} + +void InstructionInfo::dump() { + errs() << InstrName << " -- " << "flattened:\"" << AsmString << '\"' + << ", tokens:["; + for (unsigned i = 0, e = Tokens.size(); i != e; ++i) { + errs() << Tokens[i]; + if (i + 1 != e) + errs() << ", "; + } + errs() << "]\n"; + + for (unsigned i = 0, e = Operands.size(); i != e; ++i) { + Operand &Op = Operands[i]; + errs() << " op[" << i << "] = " << Op.Class->ClassName << " - "; + if (Op.Class->Kind == ClassInfo::Token) { + errs() << '\"' << Tokens[i] << "\"\n"; + continue; + } + + if (!Op.OperandInfo) { + errs() << "(singleton register)\n"; + continue; + } + + const CodeGenInstruction::OperandInfo &OI = *Op.OperandInfo; + errs() << OI.Name << " " << OI.Rec->getName() + << " (" << OI.MIOperandNo << ", " << OI.MINumOperands << ")\n"; + } +} + +static std::string getEnumNameForToken(const StringRef &Str) { + std::string Res; + + for (StringRef::iterator it = Str.begin(), ie = Str.end(); it != ie; ++it) { + switch (*it) { + case '*': Res += "_STAR_"; break; + case '%': Res += "_PCT_"; break; + case ':': Res += "_COLON_"; break; + + default: + if (isalnum(*it)) { + Res += *it; + } else { + Res += "_" + utostr((unsigned) *it) + "_"; + } + } + } + + return Res; +} + +/// getRegisterRecord - Get the register record for \arg name, or 0. +static Record *getRegisterRecord(CodeGenTarget &Target, const StringRef &Name) { + for (unsigned i = 0, e = Target.getRegisters().size(); i != e; ++i) { + const CodeGenRegister &Reg = Target.getRegisters()[i]; + if (Name == Reg.TheDef->getValueAsString("AsmName")) + return Reg.TheDef; + } + + return 0; +} + +ClassInfo *AsmMatcherInfo::getTokenClass(const StringRef &Token) { + ClassInfo *&Entry = TokenClasses[Token]; + + if (!Entry) { + Entry = new ClassInfo(); + Entry->Kind = ClassInfo::Token; + Entry->ClassName = "Token"; + Entry->Name = "MCK_" + getEnumNameForToken(Token); + Entry->ValueName = Token; + Entry->PredicateMethod = "<invalid>"; + Entry->RenderMethod = "<invalid>"; + Classes.push_back(Entry); + } + + return Entry; +} + +ClassInfo * +AsmMatcherInfo::getOperandClass(const StringRef &Token, + const CodeGenInstruction::OperandInfo &OI) { + if (OI.Rec->isSubClassOf("RegisterClass")) { + ClassInfo *CI = RegisterClassClasses[OI.Rec]; + + if (!CI) { + PrintError(OI.Rec->getLoc(), "register class has no class info!"); + throw std::string("ERROR: Missing register class!"); + } + + return CI; + } + + assert(OI.Rec->isSubClassOf("Operand") && "Unexpected operand!"); + Record *MatchClass = OI.Rec->getValueAsDef("ParserMatchClass"); + ClassInfo *CI = AsmOperandClasses[MatchClass]; + + if (!CI) { + PrintError(OI.Rec->getLoc(), "operand has no match class!"); + throw std::string("ERROR: Missing match class!"); + } + + return CI; +} + +void AsmMatcherInfo::BuildRegisterClasses(CodeGenTarget &Target, + std::set<std::string> + &SingletonRegisterNames) { + std::vector<CodeGenRegisterClass> RegisterClasses; + std::vector<CodeGenRegister> Registers; + + RegisterClasses = Target.getRegisterClasses(); + Registers = Target.getRegisters(); + + // The register sets used for matching. + std::set< std::set<Record*> > RegisterSets; + + // Gather the defined sets. + for (std::vector<CodeGenRegisterClass>::iterator it = RegisterClasses.begin(), + ie = RegisterClasses.end(); it != ie; ++it) + RegisterSets.insert(std::set<Record*>(it->Elements.begin(), + it->Elements.end())); + + // Add any required singleton sets. + for (std::set<std::string>::iterator it = SingletonRegisterNames.begin(), + ie = SingletonRegisterNames.end(); it != ie; ++it) + if (Record *Rec = getRegisterRecord(Target, *it)) + RegisterSets.insert(std::set<Record*>(&Rec, &Rec + 1)); + + // Introduce derived sets where necessary (when a register does not determine + // a unique register set class), and build the mapping of registers to the set + // they should classify to. + std::map<Record*, std::set<Record*> > RegisterMap; + for (std::vector<CodeGenRegister>::iterator it = Registers.begin(), + ie = Registers.end(); it != ie; ++it) { + CodeGenRegister &CGR = *it; + // Compute the intersection of all sets containing this register. + std::set<Record*> ContainingSet; + + for (std::set< std::set<Record*> >::iterator it = RegisterSets.begin(), + ie = RegisterSets.end(); it != ie; ++it) { + if (!it->count(CGR.TheDef)) + continue; + + if (ContainingSet.empty()) { + ContainingSet = *it; + } else { + std::set<Record*> Tmp; + std::swap(Tmp, ContainingSet); + std::insert_iterator< std::set<Record*> > II(ContainingSet, + ContainingSet.begin()); + std::set_intersection(Tmp.begin(), Tmp.end(), it->begin(), it->end(), + II); + } + } + + if (!ContainingSet.empty()) { + RegisterSets.insert(ContainingSet); + RegisterMap.insert(std::make_pair(CGR.TheDef, ContainingSet)); + } + } + + // Construct the register classes. + std::map<std::set<Record*>, ClassInfo*> RegisterSetClasses; + unsigned Index = 0; + for (std::set< std::set<Record*> >::iterator it = RegisterSets.begin(), + ie = RegisterSets.end(); it != ie; ++it, ++Index) { + ClassInfo *CI = new ClassInfo(); + CI->Kind = ClassInfo::RegisterClass0 + Index; + CI->ClassName = "Reg" + utostr(Index); + CI->Name = "MCK_Reg" + utostr(Index); + CI->ValueName = ""; + CI->PredicateMethod = ""; // unused + CI->RenderMethod = "addRegOperands"; + CI->Registers = *it; + Classes.push_back(CI); + RegisterSetClasses.insert(std::make_pair(*it, CI)); + } + + // Find the superclasses; we could compute only the subgroup lattice edges, + // but there isn't really a point. + for (std::set< std::set<Record*> >::iterator it = RegisterSets.begin(), + ie = RegisterSets.end(); it != ie; ++it) { + ClassInfo *CI = RegisterSetClasses[*it]; + for (std::set< std::set<Record*> >::iterator it2 = RegisterSets.begin(), + ie2 = RegisterSets.end(); it2 != ie2; ++it2) + if (*it != *it2 && + std::includes(it2->begin(), it2->end(), it->begin(), it->end())) + CI->SuperClasses.push_back(RegisterSetClasses[*it2]); + } + + // Name the register classes which correspond to a user defined RegisterClass. + for (std::vector<CodeGenRegisterClass>::iterator it = RegisterClasses.begin(), + ie = RegisterClasses.end(); it != ie; ++it) { + ClassInfo *CI = RegisterSetClasses[std::set<Record*>(it->Elements.begin(), + it->Elements.end())]; + if (CI->ValueName.empty()) { + CI->ClassName = it->getName(); + CI->Name = "MCK_" + it->getName(); + CI->ValueName = it->getName(); + } else + CI->ValueName = CI->ValueName + "," + it->getName(); + + RegisterClassClasses.insert(std::make_pair(it->TheDef, CI)); + } + + // Populate the map for individual registers. + for (std::map<Record*, std::set<Record*> >::iterator it = RegisterMap.begin(), + ie = RegisterMap.end(); it != ie; ++it) + this->RegisterClasses[it->first] = RegisterSetClasses[it->second]; + + // Name the register classes which correspond to singleton registers. + for (std::set<std::string>::iterator it = SingletonRegisterNames.begin(), + ie = SingletonRegisterNames.end(); it != ie; ++it) { + if (Record *Rec = getRegisterRecord(Target, *it)) { + ClassInfo *CI = this->RegisterClasses[Rec]; + assert(CI && "Missing singleton register class info!"); + + if (CI->ValueName.empty()) { + CI->ClassName = Rec->getName(); + CI->Name = "MCK_" + Rec->getName(); + CI->ValueName = Rec->getName(); + } else + CI->ValueName = CI->ValueName + "," + Rec->getName(); + } + } +} + +void AsmMatcherInfo::BuildOperandClasses(CodeGenTarget &Target) { + std::vector<Record*> AsmOperands; + AsmOperands = Records.getAllDerivedDefinitions("AsmOperandClass"); + unsigned Index = 0; + for (std::vector<Record*>::iterator it = AsmOperands.begin(), + ie = AsmOperands.end(); it != ie; ++it, ++Index) { + ClassInfo *CI = new ClassInfo(); + CI->Kind = ClassInfo::UserClass0 + Index; + + Init *Super = (*it)->getValueInit("SuperClass"); + if (DefInit *DI = dynamic_cast<DefInit*>(Super)) { + ClassInfo *SC = AsmOperandClasses[DI->getDef()]; + if (!SC) + PrintError((*it)->getLoc(), "Invalid super class reference!"); + else + CI->SuperClasses.push_back(SC); + } else { + assert(dynamic_cast<UnsetInit*>(Super) && "Unexpected SuperClass field!"); + } + CI->ClassName = (*it)->getValueAsString("Name"); + CI->Name = "MCK_" + CI->ClassName; + CI->ValueName = (*it)->getName(); + + // Get or construct the predicate method name. + Init *PMName = (*it)->getValueInit("PredicateMethod"); + if (StringInit *SI = dynamic_cast<StringInit*>(PMName)) { + CI->PredicateMethod = SI->getValue(); + } else { + assert(dynamic_cast<UnsetInit*>(PMName) && + "Unexpected PredicateMethod field!"); + CI->PredicateMethod = "is" + CI->ClassName; + } + + // Get or construct the render method name. + Init *RMName = (*it)->getValueInit("RenderMethod"); + if (StringInit *SI = dynamic_cast<StringInit*>(RMName)) { + CI->RenderMethod = SI->getValue(); + } else { + assert(dynamic_cast<UnsetInit*>(RMName) && + "Unexpected RenderMethod field!"); + CI->RenderMethod = "add" + CI->ClassName + "Operands"; + } + + AsmOperandClasses[*it] = CI; + Classes.push_back(CI); + } +} + +AsmMatcherInfo::AsmMatcherInfo(Record *_AsmParser) + : AsmParser(_AsmParser), + CommentDelimiter(AsmParser->getValueAsString("CommentDelimiter")), + RegisterPrefix(AsmParser->getValueAsString("RegisterPrefix")) +{ +} + +void AsmMatcherInfo::BuildInfo(CodeGenTarget &Target) { + // Parse the instructions; we need to do this first so that we can gather the + // singleton register classes. + std::set<std::string> SingletonRegisterNames; + for (std::map<std::string, CodeGenInstruction>::const_iterator + it = Target.getInstructions().begin(), + ie = Target.getInstructions().end(); + it != ie; ++it) { + const CodeGenInstruction &CGI = it->second; + + if (!StringRef(it->first).startswith(MatchPrefix)) + continue; + + OwningPtr<InstructionInfo> II(new InstructionInfo); + + II->InstrName = it->first; + II->Instr = &it->second; + II->AsmString = FlattenVariants(CGI.AsmString, 0); + + // Remove comments from the asm string. + if (!CommentDelimiter.empty()) { + size_t Idx = StringRef(II->AsmString).find(CommentDelimiter); + if (Idx != StringRef::npos) + II->AsmString = II->AsmString.substr(0, Idx); + } + + TokenizeAsmString(II->AsmString, II->Tokens); + + // Ignore instructions which shouldn't be matched. + if (!IsAssemblerInstruction(it->first, CGI, II->Tokens)) + continue; + + // Collect singleton registers, if used. + if (!RegisterPrefix.empty()) { + for (unsigned i = 0, e = II->Tokens.size(); i != e; ++i) { + if (II->Tokens[i].startswith(RegisterPrefix)) { + StringRef RegName = II->Tokens[i].substr(RegisterPrefix.size()); + Record *Rec = getRegisterRecord(Target, RegName); + + if (!Rec) { + std::string Err = "unable to find register for '" + RegName.str() + + "' (which matches register prefix)"; + throw TGError(CGI.TheDef->getLoc(), Err); + } + + SingletonRegisterNames.insert(RegName); + } + } + } + + Instructions.push_back(II.take()); + } + + // Build info for the register classes. + BuildRegisterClasses(Target, SingletonRegisterNames); + + // Build info for the user defined assembly operand classes. + BuildOperandClasses(Target); + + // Build the instruction information. + for (std::vector<InstructionInfo*>::iterator it = Instructions.begin(), + ie = Instructions.end(); it != ie; ++it) { + InstructionInfo *II = *it; + + for (unsigned i = 0, e = II->Tokens.size(); i != e; ++i) { + StringRef Token = II->Tokens[i]; + + // Check for singleton registers. + if (!RegisterPrefix.empty() && Token.startswith(RegisterPrefix)) { + StringRef RegName = II->Tokens[i].substr(RegisterPrefix.size()); + InstructionInfo::Operand Op; + Op.Class = RegisterClasses[getRegisterRecord(Target, RegName)]; + Op.OperandInfo = 0; + assert(Op.Class && Op.Class->Registers.size() == 1 && + "Unexpected class for singleton register"); + II->Operands.push_back(Op); + continue; + } + + // Check for simple tokens. + if (Token[0] != '$') { + InstructionInfo::Operand Op; + Op.Class = getTokenClass(Token); + Op.OperandInfo = 0; + II->Operands.push_back(Op); + continue; + } + + // Otherwise this is an operand reference. + StringRef OperandName; + if (Token[1] == '{') + OperandName = Token.substr(2, Token.size() - 3); + else + OperandName = Token.substr(1); + + // Map this token to an operand. FIXME: Move elsewhere. + unsigned Idx; + try { + Idx = II->Instr->getOperandNamed(OperandName); + } catch(...) { + throw std::string("error: unable to find operand: '" + + OperandName.str() + "'"); + } + + const CodeGenInstruction::OperandInfo &OI = II->Instr->OperandList[Idx]; + InstructionInfo::Operand Op; + Op.Class = getOperandClass(Token, OI); + Op.OperandInfo = &OI; + II->Operands.push_back(Op); + } + } + + // Reorder classes so that classes preceed super classes. + std::sort(Classes.begin(), Classes.end(), less_ptr<ClassInfo>()); +} + +static void EmitConvertToMCInst(CodeGenTarget &Target, + std::vector<InstructionInfo*> &Infos, + raw_ostream &OS) { + // Write the convert function to a separate stream, so we can drop it after + // the enum. + std::string ConvertFnBody; + raw_string_ostream CvtOS(ConvertFnBody); + + // Function we have already generated. + std::set<std::string> GeneratedFns; + + // Start the unified conversion function. + + CvtOS << "static bool ConvertToMCInst(ConversionKind Kind, MCInst &Inst, " + << "unsigned Opcode,\n" + << " SmallVectorImpl<" + << Target.getName() << "Operand> &Operands) {\n"; + CvtOS << " Inst.setOpcode(Opcode);\n"; + CvtOS << " switch (Kind) {\n"; + CvtOS << " default:\n"; + + // Start the enum, which we will generate inline. + + OS << "// Unified function for converting operants to MCInst instances.\n\n"; + OS << "enum ConversionKind {\n"; + + for (std::vector<InstructionInfo*>::const_iterator it = Infos.begin(), + ie = Infos.end(); it != ie; ++it) { + InstructionInfo &II = **it; + + // Order the (class) operands by the order to convert them into an MCInst. + SmallVector<std::pair<unsigned, unsigned>, 4> MIOperandList; + for (unsigned i = 0, e = II.Operands.size(); i != e; ++i) { + InstructionInfo::Operand &Op = II.Operands[i]; + if (Op.OperandInfo) + MIOperandList.push_back(std::make_pair(Op.OperandInfo->MIOperandNo, i)); + } + std::sort(MIOperandList.begin(), MIOperandList.end()); + + // Compute the total number of operands. + unsigned NumMIOperands = 0; + for (unsigned i = 0, e = II.Instr->OperandList.size(); i != e; ++i) { + const CodeGenInstruction::OperandInfo &OI = II.Instr->OperandList[i]; + NumMIOperands = std::max(NumMIOperands, + OI.MIOperandNo + OI.MINumOperands); + } + + // Build the conversion function signature. + std::string Signature = "Convert"; + unsigned CurIndex = 0; + for (unsigned i = 0, e = MIOperandList.size(); i != e; ++i) { + InstructionInfo::Operand &Op = II.Operands[MIOperandList[i].second]; + assert(CurIndex <= Op.OperandInfo->MIOperandNo && + "Duplicate match for instruction operand!"); + + Signature += "_"; + + // Skip operands which weren't matched by anything, this occurs when the + // .td file encodes "implicit" operands as explicit ones. + // + // FIXME: This should be removed from the MCInst structure. + for (; CurIndex != Op.OperandInfo->MIOperandNo; ++CurIndex) + Signature += "Imp"; + + // Registers are always converted the same, don't duplicate the conversion + // function based on them. + // + // FIXME: We could generalize this based on the render method, if it + // mattered. + if (Op.Class->isRegisterClass()) + Signature += "Reg"; + else + Signature += Op.Class->ClassName; + Signature += utostr(Op.OperandInfo->MINumOperands); + Signature += "_" + utostr(MIOperandList[i].second); + + CurIndex += Op.OperandInfo->MINumOperands; + } + + // Add any trailing implicit operands. + for (; CurIndex != NumMIOperands; ++CurIndex) + Signature += "Imp"; + + II.ConversionFnKind = Signature; + + // Check if we have already generated this signature. + if (!GeneratedFns.insert(Signature).second) + continue; + + // If not, emit it now. + + // Add to the enum list. + OS << " " << Signature << ",\n"; + + // And to the convert function. + CvtOS << " case " << Signature << ":\n"; + CurIndex = 0; + for (unsigned i = 0, e = MIOperandList.size(); i != e; ++i) { + InstructionInfo::Operand &Op = II.Operands[MIOperandList[i].second]; + + // Add the implicit operands. + for (; CurIndex != Op.OperandInfo->MIOperandNo; ++CurIndex) + CvtOS << " Inst.addOperand(MCOperand::CreateReg(0));\n"; + + CvtOS << " Operands[" << MIOperandList[i].second + << "]." << Op.Class->RenderMethod + << "(Inst, " << Op.OperandInfo->MINumOperands << ");\n"; + CurIndex += Op.OperandInfo->MINumOperands; + } + + // And add trailing implicit operands. + for (; CurIndex != NumMIOperands; ++CurIndex) + CvtOS << " Inst.addOperand(MCOperand::CreateReg(0));\n"; + CvtOS << " break;\n"; + } + + // Finish the convert function. + + CvtOS << " }\n"; + CvtOS << " return false;\n"; + CvtOS << "}\n\n"; + + // Finish the enum, and drop the convert function after it. + + OS << " NumConversionVariants\n"; + OS << "};\n\n"; + + OS << CvtOS.str(); +} + +/// EmitMatchClassEnumeration - Emit the enumeration for match class kinds. +static void EmitMatchClassEnumeration(CodeGenTarget &Target, + std::vector<ClassInfo*> &Infos, + raw_ostream &OS) { + OS << "namespace {\n\n"; + + OS << "/// MatchClassKind - The kinds of classes which participate in\n" + << "/// instruction matching.\n"; + OS << "enum MatchClassKind {\n"; + OS << " InvalidMatchClass = 0,\n"; + for (std::vector<ClassInfo*>::iterator it = Infos.begin(), + ie = Infos.end(); it != ie; ++it) { + ClassInfo &CI = **it; + OS << " " << CI.Name << ", // "; + if (CI.Kind == ClassInfo::Token) { + OS << "'" << CI.ValueName << "'\n"; + } else if (CI.isRegisterClass()) { + if (!CI.ValueName.empty()) + OS << "register class '" << CI.ValueName << "'\n"; + else + OS << "derived register class\n"; + } else { + OS << "user defined class '" << CI.ValueName << "'\n"; + } + } + OS << " NumMatchClassKinds\n"; + OS << "};\n\n"; + + OS << "}\n\n"; +} + +/// EmitClassifyOperand - Emit the function to classify an operand. +static void EmitClassifyOperand(CodeGenTarget &Target, + AsmMatcherInfo &Info, + raw_ostream &OS) { + OS << "static MatchClassKind ClassifyOperand(" + << Target.getName() << "Operand &Operand) {\n"; + + // Classify tokens. + OS << " if (Operand.isToken())\n"; + OS << " return MatchTokenString(Operand.getToken());\n\n"; + + // Classify registers. + // + // FIXME: Don't hardcode isReg, getReg. + OS << " if (Operand.isReg()) {\n"; + OS << " switch (Operand.getReg()) {\n"; + OS << " default: return InvalidMatchClass;\n"; + for (std::map<Record*, ClassInfo*>::iterator + it = Info.RegisterClasses.begin(), ie = Info.RegisterClasses.end(); + it != ie; ++it) + OS << " case " << Target.getName() << "::" + << it->first->getName() << ": return " << it->second->Name << ";\n"; + OS << " }\n"; + OS << " }\n\n"; + + // Classify user defined operands. + for (std::vector<ClassInfo*>::iterator it = Info.Classes.begin(), + ie = Info.Classes.end(); it != ie; ++it) { + ClassInfo &CI = **it; + + if (!CI.isUserClass()) + continue; + + OS << " // '" << CI.ClassName << "' class"; + if (!CI.SuperClasses.empty()) { + OS << ", subclass of "; + for (unsigned i = 0, e = CI.SuperClasses.size(); i != e; ++i) { + if (i) OS << ", "; + OS << "'" << CI.SuperClasses[i]->ClassName << "'"; + assert(CI < *CI.SuperClasses[i] && "Invalid class relation!"); + } + } + OS << "\n"; + + OS << " if (Operand." << CI.PredicateMethod << "()) {\n"; + + // Validate subclass relationships. + if (!CI.SuperClasses.empty()) { + for (unsigned i = 0, e = CI.SuperClasses.size(); i != e; ++i) + OS << " assert(Operand." << CI.SuperClasses[i]->PredicateMethod + << "() && \"Invalid class relationship!\");\n"; + } + + OS << " return " << CI.Name << ";\n"; + OS << " }\n\n"; + } + OS << " return InvalidMatchClass;\n"; + OS << "}\n\n"; +} + +/// 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"; + OS << "static bool IsSubclass(MatchClassKind A, MatchClassKind B) {\n"; + OS << " if (A == B)\n"; + OS << " return true;\n\n"; + + OS << " switch (A) {\n"; + OS << " default:\n"; + OS << " return false;\n"; + for (std::vector<ClassInfo*>::iterator it = Infos.begin(), + ie = Infos.end(); it != ie; ++it) { + ClassInfo &A = **it; + + if (A.Kind != ClassInfo::Token) { + std::vector<StringRef> SuperClasses; + for (std::vector<ClassInfo*>::iterator it = Infos.begin(), + ie = Infos.end(); it != ie; ++it) { + ClassInfo &B = **it; + + if (&A != &B && A.isSubsetOf(B)) + SuperClasses.push_back(B.Name); + } + + if (SuperClasses.empty()) + continue; + + OS << "\n case " << A.Name << ":\n"; + + if (SuperClasses.size() == 1) { + OS << " return B == " << SuperClasses.back() << ";\n"; + continue; + } + + OS << " switch (B) {\n"; + OS << " default: return false;\n"; + for (unsigned i = 0, e = SuperClasses.size(); i != e; ++i) + OS << " case " << SuperClasses[i] << ": return true;\n"; + OS << " }\n"; + } + } + OS << " }\n"; + OS << "}\n\n"; +} + +typedef std::pair<std::string, std::string> StringPair; + +/// 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 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. +static bool EmitStringMatcherForChar(const std::string &StrVariableName, + const std::vector<const StringPair*> &Matches, + unsigned CharNo, unsigned IndentCount, + raw_ostream &OS) { + 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"); + + // FIXME: If Matches[0].first has embeded \n, this will be bad. + OS << Indent << Matches[0]->second << "\t // \"" << Matches[0]->first + << "\"\n"; + 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(StrVariableName, Matches, + FirstNonCommonLetter, IndentCount, OS); + } + + // 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() << " strings to match.\n"; + if (EmitStringMatcherForChar(StrVariableName, LI->second, CharNo+1, + IndentCount+1, OS)) + OS << Indent << " break;\n"; + } + + OS << Indent << "}\n"; + return true; +} + + +/// EmitStringMatcher - 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. +/// +/// \param StrVariableName - The name of the variable to test. +static void EmitStringMatcher(const std::string &StrVariableName, + const std::vector<StringPair> &Matches, + raw_ostream &OS) { + // 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 << " switch (" << StrVariableName << ".size()) {\n"; + OS << " default: break;\n"; + + for (std::map<unsigned, std::vector<const StringPair*> >::iterator LI = + MatchesByLength.begin(), E = MatchesByLength.end(); LI != E; ++LI) { + OS << " case " << LI->first << ":\t // " << LI->second.size() + << " strings to match.\n"; + if (EmitStringMatcherForChar(StrVariableName, LI->second, 0, 0, OS)) + OS << " break;\n"; + } + + OS << " }\n"; +} + + +/// EmitMatchTokenString - Emit the function to match a token string to the +/// appropriate match class value. +static void EmitMatchTokenString(CodeGenTarget &Target, + std::vector<ClassInfo*> &Infos, + raw_ostream &OS) { + // Construct the match list. + std::vector<StringPair> Matches; + for (std::vector<ClassInfo*>::iterator it = Infos.begin(), + ie = Infos.end(); it != ie; ++it) { + ClassInfo &CI = **it; + + if (CI.Kind == ClassInfo::Token) + Matches.push_back(StringPair(CI.ValueName, "return " + CI.Name + ";")); + } + + OS << "static MatchClassKind MatchTokenString(const StringRef &Name) {\n"; + + EmitStringMatcher("Name", Matches, OS); + + OS << " return InvalidMatchClass;\n"; + OS << "}\n\n"; +} + +/// EmitMatchRegisterName - Emit the function to match a string to the target +/// specific register enum. +static void EmitMatchRegisterName(CodeGenTarget &Target, Record *AsmParser, + raw_ostream &OS) { + // Construct the match list. + std::vector<StringPair> Matches; + for (unsigned i = 0, e = Target.getRegisters().size(); i != e; ++i) { + const CodeGenRegister &Reg = Target.getRegisters()[i]; + if (Reg.TheDef->getValueAsString("AsmName").empty()) + continue; + + Matches.push_back(StringPair(Reg.TheDef->getValueAsString("AsmName"), + "return " + utostr(i + 1) + ";")); + } + + OS << "unsigned " << Target.getName() + << AsmParser->getValueAsString("AsmParserClassName") + << "::MatchRegisterName(const StringRef &Name) {\n"; + + EmitStringMatcher("Name", Matches, OS); + + OS << " return 0;\n"; + OS << "}\n\n"; +} + +void AsmMatcherEmitter::run(raw_ostream &OS) { + CodeGenTarget Target; + Record *AsmParser = Target.getAsmParser(); + std::string ClassName = AsmParser->getValueAsString("AsmParserClassName"); + + // Compute the information on the instructions to match. + AsmMatcherInfo Info(AsmParser); + Info.BuildInfo(Target); + + // Sort the instruction table using the partial order on classes. + std::sort(Info.Instructions.begin(), Info.Instructions.end(), + less_ptr<InstructionInfo>()); + + DEBUG_WITH_TYPE("instruction_info", { + for (std::vector<InstructionInfo*>::iterator + it = Info.Instructions.begin(), ie = Info.Instructions.end(); + it != ie; ++it) + (*it)->dump(); + }); + + // Check for ambiguous instructions. + unsigned NumAmbiguous = 0; + for (unsigned i = 0, e = Info.Instructions.size(); i != e; ++i) { + for (unsigned j = i + 1; j != e; ++j) { + InstructionInfo &A = *Info.Instructions[i]; + InstructionInfo &B = *Info.Instructions[j]; + + if (A.CouldMatchAmiguouslyWith(B)) { + DEBUG_WITH_TYPE("ambiguous_instrs", { + errs() << "warning: ambiguous instruction match:\n"; + A.dump(); + errs() << "\nis incomparable with:\n"; + B.dump(); + errs() << "\n\n"; + }); + ++NumAmbiguous; + } + } + } + if (NumAmbiguous) + DEBUG_WITH_TYPE("ambiguous_instrs", { + errs() << "warning: " << NumAmbiguous + << " ambiguous instructions!\n"; + }); + + // Write the output. + + EmitSourceFileHeader("Assembly Matcher Source Fragment", OS); + + // Emit the function to match a register name to number. + EmitMatchRegisterName(Target, AsmParser, OS); + + // Generate the unified function to convert operands into an MCInst. + EmitConvertToMCInst(Target, Info.Instructions, OS); + + // Emit the enumeration for classes which participate in matching. + EmitMatchClassEnumeration(Target, Info.Classes, OS); + + // Emit the routine to match token strings to their match class. + EmitMatchTokenString(Target, Info.Classes, OS); + + // Emit the routine to classify an operand. + EmitClassifyOperand(Target, Info, OS); + + // Emit the subclass predicate routine. + EmitIsSubclass(Target, Info.Classes, OS); + + // Finally, build the match function. + + size_t MaxNumOperands = 0; + for (std::vector<InstructionInfo*>::const_iterator it = + Info.Instructions.begin(), ie = Info.Instructions.end(); + it != ie; ++it) + MaxNumOperands = std::max(MaxNumOperands, (*it)->Operands.size()); + + OS << "bool " << Target.getName() << ClassName + << "::MatchInstruction(" + << "SmallVectorImpl<" << Target.getName() << "Operand> &Operands, " + << "MCInst &Inst) {\n"; + + // Emit the static match table; unused classes get initalized to 0 which is + // guaranteed to be InvalidMatchClass. + // + // FIXME: We can reduce the size of this table very easily. First, we change + // it so that store the kinds in separate bit-fields for each index, which + // only needs to be the max width used for classes at that index (we also need + // to reject based on this during classification). If we then make sure to + // order the match kinds appropriately (putting mnemonics last), then we + // should only end up using a few bits for each class, especially the ones + // following the mnemonic. + OS << " static const struct MatchEntry {\n"; + OS << " unsigned Opcode;\n"; + OS << " ConversionKind ConvertFn;\n"; + OS << " MatchClassKind Classes[" << MaxNumOperands << "];\n"; + OS << " } MatchTable[" << Info.Instructions.size() << "] = {\n"; + + for (std::vector<InstructionInfo*>::const_iterator it = + Info.Instructions.begin(), ie = Info.Instructions.end(); + it != ie; ++it) { + InstructionInfo &II = **it; + + OS << " { " << Target.getName() << "::" << II.InstrName + << ", " << II.ConversionFnKind << ", { "; + for (unsigned i = 0, e = II.Operands.size(); i != e; ++i) { + InstructionInfo::Operand &Op = II.Operands[i]; + + if (i) OS << ", "; + OS << Op.Class->Name; + } + OS << " } },\n"; + } + + OS << " };\n\n"; + + // Emit code to compute the class list for this operand vector. + OS << " // Eliminate obvious mismatches.\n"; + OS << " if (Operands.size() > " << MaxNumOperands << ")\n"; + OS << " return true;\n\n"; + + OS << " // Compute the class list for this operand vector.\n"; + OS << " MatchClassKind Classes[" << MaxNumOperands << "];\n"; + OS << " for (unsigned i = 0, e = Operands.size(); i != e; ++i) {\n"; + OS << " Classes[i] = ClassifyOperand(Operands[i]);\n\n"; + + OS << " // Check for invalid operands before matching.\n"; + OS << " if (Classes[i] == InvalidMatchClass)\n"; + OS << " return true;\n"; + OS << " }\n\n"; + + OS << " // Mark unused classes.\n"; + OS << " for (unsigned i = Operands.size(), e = " << MaxNumOperands << "; " + << "i != e; ++i)\n"; + OS << " Classes[i] = InvalidMatchClass;\n\n"; + + // Emit code to search the table. + OS << " // Search the table.\n"; + OS << " for (const MatchEntry *it = MatchTable, " + << "*ie = MatchTable + " << Info.Instructions.size() + << "; it != ie; ++it) {\n"; + for (unsigned i = 0; i != MaxNumOperands; ++i) { + OS << " if (!IsSubclass(Classes[" + << i << "], it->Classes[" << i << "]))\n"; + OS << " continue;\n"; + } + OS << "\n"; + OS << " return ConvertToMCInst(it->ConvertFn, Inst, " + << "it->Opcode, Operands);\n"; + OS << " }\n\n"; + + OS << " return true;\n"; + OS << "}\n\n"; +} diff --git a/utils/TableGen/AsmMatcherEmitter.h b/utils/TableGen/AsmMatcherEmitter.h new file mode 100644 index 0000000..729c938 --- /dev/null +++ b/utils/TableGen/AsmMatcherEmitter.h @@ -0,0 +1,33 @@ +//===- 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 "TableGenBackend.h" +#include <map> +#include <vector> +#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 f34feef..84a647b 100644 --- a/utils/TableGen/AsmWriterEmitter.cpp +++ b/utils/TableGen/AsmWriterEmitter.cpp @@ -15,13 +15,14 @@ #include "AsmWriterEmitter.h" #include "CodeGenTarget.h" #include "Record.h" +#include "StringToOffsetTable.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/Debug.h" #include "llvm/Support/MathExtras.h" #include <algorithm> -#include <iostream> using namespace llvm; + static bool isIdentChar(char C) { return (C >= 'a' && C <= 'z') || (C >= 'A' && C <= 'Z') || @@ -32,10 +33,20 @@ static bool isIdentChar(char C) { // This should be an anon namespace, this works around a GCC warning. namespace llvm { struct AsmWriterOperand { - enum { isLiteralTextOperand, isMachineInstrOperand } OperandType; + enum OpType { + // Output this text surrounded by quotes to the asm. + isLiteralTextOperand, + // This is the name of a routine to call to print the operand. + isMachineInstrOperand, + // Output this text verbatim to the asm writer. It is code that + // will output some text to the asm. + isLiteralStatementOperand + } OperandType; /// Str - For isLiteralTextOperand, this IS the literal text. For - /// isMachineInstrOperand, this is the PrinterMethodName for the operand. + /// isMachineInstrOperand, this is the PrinterMethodName for the operand.. + /// For isLiteralStatementOperand, this is the code to insert verbatim + /// into the asm writer. std::string Str; /// MiOpNo - For isMachineInstrOperand, this is the operand number of the @@ -47,14 +58,16 @@ namespace llvm { std::string MiModifier; // To make VS STL happy - AsmWriterOperand():OperandType(isLiteralTextOperand) {} + AsmWriterOperand(OpType op = isLiteralTextOperand):OperandType(op) {} - explicit AsmWriterOperand(const std::string &LitStr) - : OperandType(isLiteralTextOperand), Str(LitStr) {} + AsmWriterOperand(const std::string &LitStr, + OpType op = isLiteralTextOperand) + : OperandType(op), Str(LitStr) {} AsmWriterOperand(const std::string &Printer, unsigned OpNo, - const std::string &Modifier) - : OperandType(isMachineInstrOperand), Str(Printer), MIOpNo(OpNo), + const std::string &Modifier, + OpType op = isMachineInstrOperand) + : OperandType(op), Str(Printer), MIOpNo(OpNo), MiModifier(Modifier) {} bool operator!=(const AsmWriterOperand &Other) const { @@ -78,7 +91,7 @@ namespace llvm { std::vector<AsmWriterOperand> Operands; const CodeGenInstruction *CGI; - AsmWriterInst(const CodeGenInstruction &CGI, unsigned Variant); + AsmWriterInst(const CodeGenInstruction &CGI, Record *AsmWriter); /// MatchesAllButOneOp - If this instruction is exactly identical to the /// specified instruction except for one differing operand, return the @@ -100,8 +113,14 @@ namespace llvm { std::string AsmWriterOperand::getCode() const { - if (OperandType == isLiteralTextOperand) + if (OperandType == isLiteralTextOperand) { + if (Str.size() == 1) + return "O << '" + Str + "'; "; return "O << \"" + Str + "\"; "; + } + + if (OperandType == isLiteralStatementOperand) + return Str; std::string Result = Str + "(MI"; if (MIOpNo != ~0U) @@ -115,10 +134,19 @@ std::string AsmWriterOperand::getCode() const { /// ParseAsmString - Parse the specified Instruction's AsmString into this /// AsmWriterInst. /// -AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, unsigned Variant) { +AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, Record *AsmWriter) { this->CGI = &CGI; + + unsigned Variant = AsmWriter->getValueAsInt("Variant"); + int FirstOperandColumn = AsmWriter->getValueAsInt("FirstOperandColumn"); + int OperandSpacing = AsmWriter->getValueAsInt("OperandSpacing"); + unsigned CurVariant = ~0U; // ~0 if we are outside a {.|.|.} region, other #. + // This is the number of tabs we've seen if we're doing columnar layout. + unsigned CurColumn = 0; + + // NOTE: Any extensions to this code need to be mirrored in the // AsmPrinter::printInlineAsm code that executes as compile time (assuming // that inline asm strings should also get the new feature)! @@ -130,14 +158,35 @@ AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, unsigned Variant) { if (DollarPos == std::string::npos) DollarPos = AsmString.size(); // Emit a constant string fragment. + if (DollarPos != LastEmitted) { if (CurVariant == Variant || CurVariant == ~0U) { for (; LastEmitted != DollarPos; ++LastEmitted) switch (AsmString[LastEmitted]) { - case '\n': AddLiteralString("\\n"); break; - case '\t': AddLiteralString("\\t"); break; - case '"': AddLiteralString("\\\""); break; - case '\\': AddLiteralString("\\\\"); break; + case '\n': + AddLiteralString("\\n"); + break; + case '\t': + // If the asm writer is not using a columnar layout, \t is not + // magic. + if (FirstOperandColumn == -1 || OperandSpacing == -1) { + AddLiteralString("\\t"); + } else { + // We recognize a tab as an operand delimeter. + unsigned DestColumn = FirstOperandColumn + + CurColumn++ * OperandSpacing; + Operands.push_back( + AsmWriterOperand("O.PadToColumn(" + + utostr(DestColumn) + ");\n", + AsmWriterOperand::isLiteralStatementOperand)); + } + break; + case '"': + AddLiteralString("\\\""); + break; + case '\\': + AddLiteralString("\\\\"); + break; default: AddLiteralString(std::string(1, AsmString[LastEmitted])); break; @@ -151,7 +200,20 @@ AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, unsigned Variant) { if (AsmString[DollarPos+1] == 'n') { AddLiteralString("\\n"); } else if (AsmString[DollarPos+1] == 't') { - AddLiteralString("\\t"); + // If the asm writer is not using a columnar layout, \t is not + // magic. + if (FirstOperandColumn == -1 || OperandSpacing == -1) { + AddLiteralString("\\t"); + break; + } + + // We recognize a tab as an operand delimeter. + unsigned DestColumn = FirstOperandColumn + + CurColumn++ * OperandSpacing; + Operands.push_back( + AsmWriterOperand("O.PadToColumn(" + utostr(DestColumn) + ");\n", + AsmWriterOperand::isLiteralStatementOperand)); + break; } else if (std::string("${|}\\").find(AsmString[DollarPos+1]) != std::string::npos) { AddLiteralString(std::string(1, AsmString[DollarPos+1])); @@ -182,13 +244,14 @@ AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, unsigned Variant) { CurVariant = ~0U; } else if (DollarPos+1 != AsmString.size() && AsmString[DollarPos+1] == '$') { - if (CurVariant == Variant || CurVariant == ~0U) + if (CurVariant == Variant || CurVariant == ~0U) { AddLiteralString("$"); // "$$" -> $ + } LastEmitted = DollarPos+2; } else { // Get the name of the variable. std::string::size_type VarEnd = DollarPos+1; - + // handle ${foo}bar as $foo by detecting whether the character following // the dollar sign is a curly brace. If so, advance VarEnd and DollarPos // so the variable name does not contain the leading curly brace. @@ -259,8 +322,9 @@ AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, unsigned Variant) { LastEmitted = VarEnd; } } - - AddLiteralString("\\n"); + + Operands.push_back(AsmWriterOperand("return;", + AsmWriterOperand::isLiteralStatementOperand)); } /// MatchesAllButOneOp - If this instruction is exactly identical to the @@ -357,7 +421,6 @@ static void EmitInstructions(std::vector<AsmWriterInst> &Insts, } O << "\n"; } - O << " break;\n"; } @@ -384,10 +447,6 @@ FindUniqueOperandCommands(std::vector<std::string> &UniqueOperandCommands, Command = " " + Inst->Operands[0].getCode() + "\n"; - // If this is the last operand, emit a return. - if (Inst->Operands.size() == 1) - Command += " return true;\n"; - // Check to see if we already have 'Command' in UniqueOperandCommands. // If not, add it. bool FoundIt = false; @@ -431,7 +490,10 @@ FindUniqueOperandCommands(std::vector<std::string> &UniqueOperandCommands, // Otherwise, scan to see if all of the other instructions in this command // set share the operand. bool AllSame = true; - + // Keep track of the maximum, number of operands or any + // instruction we see in the group. + size_t MaxSize = FirstInst->Operands.size(); + for (NIT = std::find(NIT+1, InstIdxs.end(), CommandIdx); NIT != InstIdxs.end(); NIT = std::find(NIT+1, InstIdxs.end(), CommandIdx)) { @@ -439,6 +501,11 @@ FindUniqueOperandCommands(std::vector<std::string> &UniqueOperandCommands, // matches, we're ok, otherwise bail out. const AsmWriterInst *OtherInst = getAsmWriterInstByID(NIT-InstIdxs.begin()); + + if (OtherInst && + OtherInst->Operands.size() > FirstInst->Operands.size()) + MaxSize = std::max(MaxSize, OtherInst->Operands.size()); + if (!OtherInst || OtherInst->Operands.size() == Op || OtherInst->Operands[Op] != FirstInst->Operands[Op]) { AllSame = false; @@ -451,10 +518,6 @@ FindUniqueOperandCommands(std::vector<std::string> &UniqueOperandCommands, // to UniqueOperandCommands and remember that it was consumed. std::string Command = " " + FirstInst->Operands[Op].getCode() + "\n"; - // If this is the last operand, emit a return after the code. - if (FirstInst->Operands.size() == Op+1) - Command += " return true;\n"; - UniqueOperandCommands[CommandIdx] += Command; InstOpsUsed[CommandIdx]++; } @@ -475,29 +538,26 @@ FindUniqueOperandCommands(std::vector<std::string> &UniqueOperandCommands, } - -void AsmWriterEmitter::run(raw_ostream &O) { - EmitSourceFileHeader("Assembly Writer Source Fragment", O); - +/// EmitPrintInstruction - Generate the code for the "printInstruction" method +/// implementation. +void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) { CodeGenTarget Target; Record *AsmWriter = Target.getAsmWriter(); std::string ClassName = AsmWriter->getValueAsString("AsmWriterClassName"); - unsigned Variant = AsmWriter->getValueAsInt("Variant"); - + O << "/// printInstruction - This method is automatically generated by tablegen\n" - "/// from the instruction set description. This method returns true if the\n" - "/// machine instruction was sufficiently described to print it, otherwise\n" - "/// it returns false.\n" - "bool " << Target.getName() << ClassName + "/// from the instruction set description.\n" + "void " << Target.getName() << ClassName << "::printInstruction(const MachineInstr *MI) {\n"; std::vector<AsmWriterInst> Instructions; for (CodeGenTarget::inst_iterator I = Target.inst_begin(), E = Target.inst_end(); I != E; ++I) - if (!I->second.AsmString.empty()) - Instructions.push_back(AsmWriterInst(I->second, Variant)); + if (!I->second.AsmString.empty() && + I->second.TheDef->getName() != "PHI") + Instructions.push_back(AsmWriterInst(I->second, AsmWriter)); // Get the instruction numbering. Target.getInstructionsByEnumValue(NumberedInstructions); @@ -509,10 +569,7 @@ void AsmWriterEmitter::run(raw_ostream &O) { CGIAWIMap.insert(std::make_pair(Instructions[i].CGI, &Instructions[i])); // Build an aggregate string, and build a table of offsets into it. - std::map<std::string, unsigned> StringOffset; - std::string AggregateString; - AggregateString.push_back(0); // "\0" - AggregateString.push_back(0); // "\0" + StringToOffsetTable StringTable; /// OpcodeInfo - This encodes the index of the string to use for the first /// chunk of the output as well as indices used for operand printing. @@ -524,32 +581,28 @@ void AsmWriterEmitter::run(raw_ostream &O) { unsigned Idx; if (AWI == 0) { // Something not handled by the asmwriter printer. - Idx = 0; + Idx = ~0U; } else if (AWI->Operands[0].OperandType != AsmWriterOperand::isLiteralTextOperand || AWI->Operands[0].Str.empty()) { // Something handled by the asmwriter printer, but with no leading string. - Idx = 1; + Idx = StringTable.GetOrAddStringOffset(""); } else { - unsigned &Entry = StringOffset[AWI->Operands[0].Str]; - if (Entry == 0) { - // Add the string to the aggregate if this is the first time found. - MaxStringIdx = Entry = AggregateString.size(); - std::string Str = AWI->Operands[0].Str; - UnescapeString(Str); - AggregateString += Str; - AggregateString += '\0'; - } - Idx = Entry; - + std::string Str = AWI->Operands[0].Str; + UnescapeString(Str); + Idx = StringTable.GetOrAddStringOffset(Str); + MaxStringIdx = std::max(MaxStringIdx, Idx); + // Nuke the string from the operand list. It is now handled! AWI->Operands.erase(AWI->Operands.begin()); } - OpcodeInfo.push_back(Idx); + + // Bias offset by one since we want 0 as a sentinel. + OpcodeInfo.push_back(Idx+1); } // Figure out how many bits we used for the string index. - unsigned AsmStrBits = Log2_32_Ceil(MaxStringIdx+1); + unsigned AsmStrBits = Log2_32_Ceil(MaxStringIdx+2); // To reduce code size, we compactify common instructions into a few bits // in the opcode-indexed table. @@ -557,17 +610,8 @@ void AsmWriterEmitter::run(raw_ostream &O) { std::vector<std::vector<std::string> > TableDrivenOperandPrinters; - bool isFirst = true; while (1) { std::vector<std::string> UniqueOperandCommands; - - // For the first operand check, add a default value for instructions with - // just opcode strings to use. - if (isFirst) { - UniqueOperandCommands.push_back(" return true;\n"); - isFirst = false; - } - std::vector<unsigned> InstIdxs; std::vector<unsigned> NumInstOpsHandled; FindUniqueOperandCommands(UniqueOperandCommands, InstIdxs, @@ -582,8 +626,8 @@ void AsmWriterEmitter::run(raw_ostream &O) { // If we don't have enough bits for this operand, don't include it. if (NumBits > BitsLeft) { - DOUT << "Not enough bits to densely encode " << NumBits - << " more bits\n"; + DEBUG(errs() << "Not enough bits to densely encode " << NumBits + << " more bits\n"); break; } @@ -621,52 +665,24 @@ void AsmWriterEmitter::run(raw_ostream &O) { O << " };\n\n"; // Emit the string itself. - O << " const char *AsmStrs = \n \""; - unsigned CharsPrinted = 0; - EscapeString(AggregateString); - for (unsigned i = 0, e = AggregateString.size(); i != e; ++i) { - if (CharsPrinted > 70) { - O << "\"\n \""; - CharsPrinted = 0; - } - O << AggregateString[i]; - ++CharsPrinted; - - // Print escape sequences all together. - if (AggregateString[i] == '\\') { - assert(i+1 < AggregateString.size() && "Incomplete escape sequence!"); - if (isdigit(AggregateString[i+1])) { - assert(isdigit(AggregateString[i+2]) && isdigit(AggregateString[i+3]) && - "Expected 3 digit octal escape!"); - O << AggregateString[++i]; - O << AggregateString[++i]; - O << AggregateString[++i]; - CharsPrinted += 3; - } else { - O << AggregateString[++i]; - ++CharsPrinted; - } - } - } - O << "\";\n\n"; - - O << " processDebugLoc(MI->getDebugLoc());\n\n"; + O << " const char *AsmStrs = \n"; + StringTable.EmitString(O); + O << ";\n\n"; O << "\n#ifndef NO_ASM_WRITER_BOILERPLATE\n"; O << " if (MI->getOpcode() == TargetInstrInfo::INLINEASM) {\n" << " O << \"\\t\";\n" << " printInlineAsm(MI);\n" - << " return true;\n" + << " return;\n" << " } else if (MI->isLabel()) {\n" << " printLabel(MI);\n" - << " return true;\n" - << " } else if (MI->getOpcode() == TargetInstrInfo::DECLARE) {\n" - << " printDeclare(MI);\n" - << " return true;\n" + << " return;\n" << " } else if (MI->getOpcode() == TargetInstrInfo::IMPLICIT_DEF) {\n" << " printImplicitDef(MI);\n" - << " return true;\n" + << " return;\n" + << " } else if (MI->getOpcode() == TargetInstrInfo::KILL) {\n" + << " return;\n" << " }\n\n"; O << "\n#endif\n"; @@ -675,8 +691,8 @@ void AsmWriterEmitter::run(raw_ostream &O) { O << " // Emit the opcode for the instruction.\n" << " unsigned Bits = OpInfo[MI->getOpcode()];\n" - << " if (Bits == 0) return false;\n" - << " O << AsmStrs+(Bits & " << (1 << AsmStrBits)-1 << ");\n\n"; + << " assert(Bits != 0 && \"Cannot print this instruction.\");\n" + << " O << AsmStrs+(Bits & " << (1 << AsmStrBits)-1 << ")-1;\n\n"; // Output the table driven operand information. BitsLeft = 32-AsmStrBits; @@ -732,6 +748,11 @@ void AsmWriterEmitter::run(raw_ostream &O) { // elements in the vector. std::reverse(Instructions.begin(), Instructions.end()); + + // Now that we've emitted all of the operand info that fit into 32 bits, emit + // information for those instructions that are left. This is a less dense + // encoding, but we expect the main 32-bit table to handle the majority of + // instructions. if (!Instructions.empty()) { // Find the opcode # of inline asm. O << " switch (MI->getOpcode()) {\n"; @@ -739,8 +760,61 @@ void AsmWriterEmitter::run(raw_ostream &O) { EmitInstructions(Instructions, O); O << " }\n"; - O << " return true;\n"; + O << " return;\n"; } - + + O << " return;\n"; O << "}\n"; } + + +void AsmWriterEmitter::EmitGetRegisterName(raw_ostream &O) { + CodeGenTarget Target; + Record *AsmWriter = Target.getAsmWriter(); + std::string ClassName = AsmWriter->getValueAsString("AsmWriterClassName"); + const std::vector<CodeGenRegister> &Registers = Target.getRegisters(); + + StringToOffsetTable StringTable; + O << + "\n\n/// getRegisterName - This method is automatically generated by tblgen\n" + "/// from the register set description. This returns the assembler name\n" + "/// for the specified register.\n" + "const char *" << Target.getName() << ClassName + << "::getRegisterName(unsigned RegNo) {\n" + << " assert(RegNo && RegNo < " << (Registers.size()+1) + << " && \"Invalid register number!\");\n" + << "\n" + << " static const unsigned RegAsmOffset[] = {"; + for (unsigned i = 0, e = Registers.size(); i != e; ++i) { + const CodeGenRegister &Reg = Registers[i]; + + std::string AsmName = Reg.TheDef->getValueAsString("AsmName"); + if (AsmName.empty()) + AsmName = Reg.getName(); + + + if ((i % 14) == 0) + O << "\n "; + + O << StringTable.GetOrAddStringOffset(AsmName) << ", "; + } + O << "0\n" + << " };\n" + << "\n"; + + O << " const char *AsmStrs =\n"; + StringTable.EmitString(O); + O << ";\n"; + + O << " return AsmStrs+RegAsmOffset[RegNo-1];\n" + << "}\n"; +} + + +void AsmWriterEmitter::run(raw_ostream &O) { + EmitSourceFileHeader("Assembly Writer Source Fragment", O); + + EmitPrintInstruction(O); + EmitGetRegisterName(O); +} + diff --git a/utils/TableGen/AsmWriterEmitter.h b/utils/TableGen/AsmWriterEmitter.h index 75e6996..7862caa 100644 --- a/utils/TableGen/AsmWriterEmitter.h +++ b/utils/TableGen/AsmWriterEmitter.h @@ -35,6 +35,9 @@ namespace llvm { void run(raw_ostream &o); private: + void EmitPrintInstruction(raw_ostream &o); + void EmitGetRegisterName(raw_ostream &o); + AsmWriterInst *getAsmWriterInstByID(unsigned ID) const { assert(ID < NumberedInstructions.size()); std::map<const CodeGenInstruction*, AsmWriterInst*>::const_iterator I = diff --git a/utils/TableGen/CMakeLists.txt b/utils/TableGen/CMakeLists.txt index 6ec1d99..e568c62 100644 --- a/utils/TableGen/CMakeLists.txt +++ b/utils/TableGen/CMakeLists.txt @@ -1,4 +1,5 @@ add_executable(tblgen + AsmMatcherEmitter.cpp AsmWriterEmitter.cpp CallingConvEmitter.cpp ClangDiagnosticsEmitter.cpp diff --git a/utils/TableGen/CallingConvEmitter.cpp b/utils/TableGen/CallingConvEmitter.cpp index a14be0b..28ba2ed 100644 --- a/utils/TableGen/CallingConvEmitter.cpp +++ b/utils/TableGen/CallingConvEmitter.cpp @@ -26,9 +26,9 @@ void CallingConvEmitter::run(raw_ostream &O) { // other. for (unsigned i = 0, e = CCs.size(); i != e; ++i) { O << "static bool " << CCs[i]->getName() - << "(unsigned ValNo, MVT ValVT,\n" + << "(unsigned ValNo, EVT ValVT,\n" << std::string(CCs[i]->getName().size()+13, ' ') - << "MVT LocVT, CCValAssign::LocInfo LocInfo,\n" + << "EVT LocVT, CCValAssign::LocInfo LocInfo,\n" << std::string(CCs[i]->getName().size()+13, ' ') << "ISD::ArgFlagsTy ArgFlags, CCState &State);\n"; } @@ -44,9 +44,9 @@ void CallingConvEmitter::EmitCallingConv(Record *CC, raw_ostream &O) { Counter = 0; O << "\n\nstatic bool " << CC->getName() - << "(unsigned ValNo, MVT ValVT,\n" + << "(unsigned ValNo, EVT ValVT,\n" << std::string(CC->getName().size()+13, ' ') - << "MVT LocVT, CCValAssign::LocInfo LocInfo,\n" + << "EVT LocVT, CCValAssign::LocInfo LocInfo,\n" << std::string(CC->getName().size()+13, ' ') << "ISD::ArgFlagsTy ArgFlags, CCState &State) {\n"; // Emit all of the actions, in order. @@ -163,12 +163,12 @@ void CallingConvEmitter::EmitAction(Record *Action, O << Size << ", "; else O << "\n" << IndentStr << " State.getTarget().getTargetData()" - "->getTypeAllocSize(LocVT.getTypeForMVT()), "; + "->getTypeAllocSize(LocVT.getTypeForEVT(State.getContext())), "; if (Align) O << Align; else O << "\n" << IndentStr << " State.getTarget().getTargetData()" - "->getABITypeAlignment(LocVT.getTypeForMVT())"; + "->getABITypeAlignment(LocVT.getTypeForEVT(State.getContext()))"; O << ");\n" << IndentStr << "State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset" << Counter << ", LocVT, LocInfo));\n"; @@ -186,6 +186,10 @@ void CallingConvEmitter::EmitAction(Record *Action, Record *DestTy = Action->getValueAsDef("DestTy"); O << IndentStr << "LocVT = " << getEnumName(getValueType(DestTy)) <<";\n"; O << IndentStr << "LocInfo = CCValAssign::BCvt;\n"; + } else if (Action->isSubClassOf("CCPassIndirect")) { + Record *DestTy = Action->getValueAsDef("DestTy"); + O << IndentStr << "LocVT = " << getEnumName(getValueType(DestTy)) <<";\n"; + O << IndentStr << "LocInfo = CCValAssign::Indirect;\n"; } else if (Action->isSubClassOf("CCPassByVal")) { int Size = Action->getValueAsInt("Size"); int Align = Action->getValueAsInt("Align"); diff --git a/utils/TableGen/CodeEmitterGen.cpp b/utils/TableGen/CodeEmitterGen.cpp index 6466025..7e6c769 100644 --- a/utils/TableGen/CodeEmitterGen.cpp +++ b/utils/TableGen/CodeEmitterGen.cpp @@ -29,7 +29,7 @@ void CodeEmitterGen::reverseBits(std::vector<Record*> &Insts) { R->getName() == "DBG_LABEL" || R->getName() == "EH_LABEL" || R->getName() == "GC_LABEL" || - R->getName() == "DECLARE" || + R->getName() == "KILL" || R->getName() == "EXTRACT_SUBREG" || R->getName() == "INSERT_SUBREG" || R->getName() == "IMPLICIT_DEF" || @@ -106,7 +106,7 @@ void CodeEmitterGen::run(raw_ostream &o) { R->getName() == "DBG_LABEL" || R->getName() == "EH_LABEL" || R->getName() == "GC_LABEL" || - R->getName() == "DECLARE" || + R->getName() == "KILL" || R->getName() == "EXTRACT_SUBREG" || R->getName() == "INSERT_SUBREG" || R->getName() == "IMPLICIT_DEF" || @@ -144,7 +144,7 @@ void CodeEmitterGen::run(raw_ostream &o) { InstName == "DBG_LABEL"|| InstName == "EH_LABEL"|| InstName == "GC_LABEL"|| - InstName == "DECLARE"|| + InstName == "KILL"|| InstName == "EXTRACT_SUBREG" || InstName == "INSERT_SUBREG" || InstName == "IMPLICIT_DEF" || @@ -243,8 +243,10 @@ void CodeEmitterGen::run(raw_ostream &o) { // Default case: unhandled opcode o << " default:\n" - << " cerr << \"Not supported instr: \" << MI << \"\\n\";\n" - << " abort();\n" + << " std::string msg;\n" + << " raw_string_ostream Msg(msg);\n" + << " Msg << \"Not supported instr: \" << MI;\n" + << " llvm_report_error(Msg.str());\n" << " }\n" << " return Value;\n" << "}\n\n"; diff --git a/utils/TableGen/CodeGenDAGPatterns.cpp b/utils/TableGen/CodeGenDAGPatterns.cpp index 2289ae7..6b8ceae 100644 --- a/utils/TableGen/CodeGenDAGPatterns.cpp +++ b/utils/TableGen/CodeGenDAGPatterns.cpp @@ -55,15 +55,15 @@ ConvertVTs(const std::vector<MVT::SimpleValueType> &InVTs) { } static inline bool isInteger(MVT::SimpleValueType VT) { - return MVT(VT).isInteger(); + return EVT(VT).isInteger(); } static inline bool isFloatingPoint(MVT::SimpleValueType VT) { - return MVT(VT).isFloatingPoint(); + return EVT(VT).isFloatingPoint(); } static inline bool isVector(MVT::SimpleValueType VT) { - return MVT(VT).isVector(); + return EVT(VT).isVector(); } static bool LHSIsSubsetOfRHS(const std::vector<unsigned char> &LHS, @@ -76,23 +76,33 @@ static bool LHSIsSubsetOfRHS(const std::vector<unsigned char> &LHS, } namespace llvm { -namespace EMVT { +namespace EEVT { /// isExtIntegerInVTs - Return true if the specified extended value type vector -/// contains isInt or an integer value type. +/// contains iAny or an integer value type. bool isExtIntegerInVTs(const std::vector<unsigned char> &EVTs) { assert(!EVTs.empty() && "Cannot check for integer in empty ExtVT list!"); - return EVTs[0] == isInt || !(FilterEVTs(EVTs, isInteger).empty()); + return EVTs[0] == MVT::iAny || !(FilterEVTs(EVTs, isInteger).empty()); } /// isExtFloatingPointInVTs - Return true if the specified extended value type -/// vector contains isFP or a FP value type. +/// vector contains fAny or a FP value type. bool isExtFloatingPointInVTs(const std::vector<unsigned char> &EVTs) { - assert(!EVTs.empty() && "Cannot check for integer in empty ExtVT list!"); - return EVTs[0] == isFP || !(FilterEVTs(EVTs, isFloatingPoint).empty()); + assert(!EVTs.empty() && "Cannot check for FP in empty ExtVT list!"); + return EVTs[0] == MVT::fAny || !(FilterEVTs(EVTs, isFloatingPoint).empty()); +} + +/// isExtVectorInVTs - Return true if the specified extended value type +/// vector contains vAny or a vector value type. +bool isExtVectorInVTs(const std::vector<unsigned char> &EVTs) { + assert(!EVTs.empty() && "Cannot check for vector in empty ExtVT list!"); + return EVTs[0] == MVT::vAny || !(FilterEVTs(EVTs, isVector).empty()); } -} // end namespace EMVT. +} // end namespace EEVT. } // end namespace llvm. +bool RecordPtrCmp::operator()(const Record *LHS, const Record *RHS) const { + return LHS->getID() < RHS->getID(); +} /// Dependent variable map for CodeGenDAGPattern variant generation typedef std::map<std::string, int> DepVarMap; @@ -128,14 +138,14 @@ void FindDepVars(TreePatternNode *N, MultipleUseVarSet &DepVars) { //! Dump the dependent variable set: void DumpDepVars(MultipleUseVarSet &DepVars) { if (DepVars.empty()) { - DOUT << "<empty set>"; + DEBUG(errs() << "<empty set>"); } else { - DOUT << "[ "; + DEBUG(errs() << "[ "); for (MultipleUseVarSet::const_iterator i = DepVars.begin(), e = DepVars.end(); i != e; ++i) { - DOUT << (*i) << " "; + DEBUG(errs() << (*i) << " "); } - DOUT << "]"; + DEBUG(errs() << "]"); } } } @@ -183,6 +193,8 @@ SDTypeConstraint::SDTypeConstraint(Record *R) { ConstraintType = SDTCisInt; } else if (R->isSubClassOf("SDTCisFP")) { ConstraintType = SDTCisFP; + } else if (R->isSubClassOf("SDTCisVec")) { + ConstraintType = SDTCisVec; } else if (R->isSubClassOf("SDTCisSameAs")) { ConstraintType = SDTCisSameAs; x.SDTCisSameAs_Info.OtherOperandNum = R->getValueAsInt("OtherOperandNum"); @@ -264,7 +276,7 @@ bool SDTypeConstraint::ApplyTypeConstraint(TreePatternNode *N, // If we found exactly one supported integer type, apply it. if (IntVTs.size() == 1) return NodeToApply->UpdateNodeType(IntVTs[0], TP); - return NodeToApply->UpdateNodeType(EMVT::isInt, TP); + return NodeToApply->UpdateNodeType(MVT::iAny, TP); } case SDTCisFP: { // If there is only one FP type supported, this must be it. @@ -274,7 +286,17 @@ bool SDTypeConstraint::ApplyTypeConstraint(TreePatternNode *N, // If we found exactly one supported FP type, apply it. if (FPVTs.size() == 1) return NodeToApply->UpdateNodeType(FPVTs[0], TP); - return NodeToApply->UpdateNodeType(EMVT::isFP, TP); + return NodeToApply->UpdateNodeType(MVT::fAny, TP); + } + case SDTCisVec: { + // If there is only one vector type supported, this must be it. + std::vector<MVT::SimpleValueType> VecVTs = + FilterVTs(CGT.getLegalValueTypes(), isVector); + + // If we found exactly one supported vector type, apply it. + if (VecVTs.size() == 1) + return NodeToApply->UpdateNodeType(VecVTs[0], TP); + return NodeToApply->UpdateNodeType(MVT::vAny, TP); } case SDTCisSameAs: { TreePatternNode *OtherNode = @@ -300,7 +322,7 @@ bool SDTypeConstraint::ApplyTypeConstraint(TreePatternNode *N, // It must be integer. bool MadeChange = false; - MadeChange |= OtherNode->UpdateNodeType(EMVT::isInt, TP); + MadeChange |= OtherNode->UpdateNodeType(MVT::iAny, TP); // This code only handles nodes that have one type set. Assert here so // that we can change this if we ever need to deal with multiple value @@ -320,25 +342,25 @@ bool SDTypeConstraint::ApplyTypeConstraint(TreePatternNode *N, // This code does not currently handle nodes which have multiple types, // where some types are integer, and some are fp. Assert that this is not // the case. - assert(!(EMVT::isExtIntegerInVTs(NodeToApply->getExtTypes()) && - EMVT::isExtFloatingPointInVTs(NodeToApply->getExtTypes())) && - !(EMVT::isExtIntegerInVTs(BigOperand->getExtTypes()) && - EMVT::isExtFloatingPointInVTs(BigOperand->getExtTypes())) && + assert(!(EEVT::isExtIntegerInVTs(NodeToApply->getExtTypes()) && + EEVT::isExtFloatingPointInVTs(NodeToApply->getExtTypes())) && + !(EEVT::isExtIntegerInVTs(BigOperand->getExtTypes()) && + EEVT::isExtFloatingPointInVTs(BigOperand->getExtTypes())) && "SDTCisOpSmallerThanOp does not handle mixed int/fp types!"); - if (EMVT::isExtIntegerInVTs(NodeToApply->getExtTypes())) - MadeChange |= BigOperand->UpdateNodeType(EMVT::isInt, TP); - else if (EMVT::isExtFloatingPointInVTs(NodeToApply->getExtTypes())) - MadeChange |= BigOperand->UpdateNodeType(EMVT::isFP, TP); - if (EMVT::isExtIntegerInVTs(BigOperand->getExtTypes())) - MadeChange |= NodeToApply->UpdateNodeType(EMVT::isInt, TP); - else if (EMVT::isExtFloatingPointInVTs(BigOperand->getExtTypes())) - MadeChange |= NodeToApply->UpdateNodeType(EMVT::isFP, TP); + if (EEVT::isExtIntegerInVTs(NodeToApply->getExtTypes())) + MadeChange |= BigOperand->UpdateNodeType(MVT::iAny, TP); + else if (EEVT::isExtFloatingPointInVTs(NodeToApply->getExtTypes())) + MadeChange |= BigOperand->UpdateNodeType(MVT::fAny, TP); + if (EEVT::isExtIntegerInVTs(BigOperand->getExtTypes())) + MadeChange |= NodeToApply->UpdateNodeType(MVT::iAny, TP); + else if (EEVT::isExtFloatingPointInVTs(BigOperand->getExtTypes())) + MadeChange |= NodeToApply->UpdateNodeType(MVT::fAny, TP); std::vector<MVT::SimpleValueType> VTs = CGT.getLegalValueTypes(); - if (EMVT::isExtIntegerInVTs(NodeToApply->getExtTypes())) { + if (EEVT::isExtIntegerInVTs(NodeToApply->getExtTypes())) { VTs = FilterVTs(VTs, isInteger); - } else if (EMVT::isExtFloatingPointInVTs(NodeToApply->getExtTypes())) { + } else if (EEVT::isExtFloatingPointInVTs(NodeToApply->getExtTypes())) { VTs = FilterVTs(VTs, isFloatingPoint); } else { VTs.clear(); @@ -368,9 +390,9 @@ bool SDTypeConstraint::ApplyTypeConstraint(TreePatternNode *N, if (OtherOperand->hasTypeSet()) { if (!isVector(OtherOperand->getTypeNum(0))) TP.error(N->getOperator()->getName() + " VT operand must be a vector!"); - MVT IVT = OtherOperand->getTypeNum(0); + EVT IVT = OtherOperand->getTypeNum(0); IVT = IVT.getVectorElementType(); - return NodeToApply->UpdateNodeType(IVT.getSimpleVT(), TP); + return NodeToApply->UpdateNodeType(IVT.getSimpleVT().SimpleTy, TP); } return false; } @@ -445,7 +467,7 @@ bool TreePatternNode::UpdateNodeType(const std::vector<unsigned char> &ExtVTs, TreePattern &TP) { assert(!ExtVTs.empty() && "Cannot update node type with empty type vector!"); - if (ExtVTs[0] == EMVT::isUnknown || LHSIsSubsetOfRHS(getExtTypes(), ExtVTs)) + if (ExtVTs[0] == EEVT::isUnknown || LHSIsSubsetOfRHS(getExtTypes(), ExtVTs)) return false; if (isTypeCompletelyUnknown() || LHSIsSubsetOfRHS(ExtVTs, getExtTypes())) { setTypes(ExtVTs); @@ -454,9 +476,9 @@ bool TreePatternNode::UpdateNodeType(const std::vector<unsigned char> &ExtVTs, if (getExtTypeNum(0) == MVT::iPTR || getExtTypeNum(0) == MVT::iPTRAny) { if (ExtVTs[0] == MVT::iPTR || ExtVTs[0] == MVT::iPTRAny || - ExtVTs[0] == EMVT::isInt) + ExtVTs[0] == MVT::iAny) return false; - if (EMVT::isExtIntegerInVTs(ExtVTs)) { + if (EEVT::isExtIntegerInVTs(ExtVTs)) { std::vector<unsigned char> FVTs = FilterEVTs(ExtVTs, isInteger); if (FVTs.size()) { setTypes(ExtVTs); @@ -465,8 +487,19 @@ bool TreePatternNode::UpdateNodeType(const std::vector<unsigned char> &ExtVTs, } } - if ((ExtVTs[0] == EMVT::isInt || ExtVTs[0] == MVT::iAny) && - EMVT::isExtIntegerInVTs(getExtTypes())) { + // Merge vAny with iAny/fAny. The latter include vector types so keep them + // as the more specific information. + if (ExtVTs[0] == MVT::vAny && + (getExtTypeNum(0) == MVT::iAny || getExtTypeNum(0) == MVT::fAny)) + return false; + if (getExtTypeNum(0) == MVT::vAny && + (ExtVTs[0] == MVT::iAny || ExtVTs[0] == MVT::fAny)) { + setTypes(ExtVTs); + return true; + } + + if (ExtVTs[0] == MVT::iAny && + EEVT::isExtIntegerInVTs(getExtTypes())) { assert(hasTypeSet() && "should be handled above!"); std::vector<unsigned char> FVTs = FilterEVTs(getExtTypes(), isInteger); if (getExtTypes() == FVTs) @@ -475,7 +508,7 @@ bool TreePatternNode::UpdateNodeType(const std::vector<unsigned char> &ExtVTs, return true; } if ((ExtVTs[0] == MVT::iPTR || ExtVTs[0] == MVT::iPTRAny) && - EMVT::isExtIntegerInVTs(getExtTypes())) { + EEVT::isExtIntegerInVTs(getExtTypes())) { //assert(hasTypeSet() && "should be handled above!"); std::vector<unsigned char> FVTs = FilterEVTs(getExtTypes(), isInteger); if (getExtTypes() == FVTs) @@ -485,8 +518,8 @@ bool TreePatternNode::UpdateNodeType(const std::vector<unsigned char> &ExtVTs, return true; } } - if ((ExtVTs[0] == EMVT::isFP || ExtVTs[0] == MVT::fAny) && - EMVT::isExtFloatingPointInVTs(getExtTypes())) { + if (ExtVTs[0] == MVT::fAny && + EEVT::isExtFloatingPointInVTs(getExtTypes())) { assert(hasTypeSet() && "should be handled above!"); std::vector<unsigned char> FVTs = FilterEVTs(getExtTypes(), isFloatingPoint); @@ -495,20 +528,31 @@ bool TreePatternNode::UpdateNodeType(const std::vector<unsigned char> &ExtVTs, setTypes(FVTs); return true; } - - // If we know this is an int or fp type, and we are told it is a specific one, - // take the advice. + if (ExtVTs[0] == MVT::vAny && + EEVT::isExtVectorInVTs(getExtTypes())) { + assert(hasTypeSet() && "should be handled above!"); + std::vector<unsigned char> FVTs = FilterEVTs(getExtTypes(), isVector); + if (getExtTypes() == FVTs) + return false; + setTypes(FVTs); + return true; + } + + // If we know this is an int, FP, or vector type, and we are told it is a + // specific one, take the advice. // // Similarly, we should probably set the type here to the intersection of - // {isInt|isFP} and ExtVTs - if (((getExtTypeNum(0) == EMVT::isInt || getExtTypeNum(0) == MVT::iAny) && - EMVT::isExtIntegerInVTs(ExtVTs)) || - ((getExtTypeNum(0) == EMVT::isFP || getExtTypeNum(0) == MVT::fAny) && - EMVT::isExtFloatingPointInVTs(ExtVTs))) { + // {iAny|fAny|vAny} and ExtVTs + if ((getExtTypeNum(0) == MVT::iAny && + EEVT::isExtIntegerInVTs(ExtVTs)) || + (getExtTypeNum(0) == MVT::fAny && + EEVT::isExtFloatingPointInVTs(ExtVTs)) || + (getExtTypeNum(0) == MVT::vAny && + EEVT::isExtVectorInVTs(ExtVTs))) { setTypes(ExtVTs); return true; } - if (getExtTypeNum(0) == EMVT::isInt && + if (getExtTypeNum(0) == MVT::iAny && (ExtVTs[0] == MVT::iPTR || ExtVTs[0] == MVT::iPTRAny)) { setTypes(ExtVTs); return true; @@ -537,14 +581,15 @@ void TreePatternNode::print(raw_ostream &OS) const { // nodes that are multiply typed. switch (getExtTypeNum(0)) { case MVT::Other: OS << ":Other"; break; - case EMVT::isInt: OS << ":isInt"; break; - case EMVT::isFP : OS << ":isFP"; break; - case EMVT::isUnknown: ; /*OS << ":?";*/ break; + case MVT::iAny: OS << ":iAny"; break; + case MVT::fAny : OS << ":fAny"; break; + case MVT::vAny: OS << ":vAny"; break; + case EEVT::isUnknown: ; /*OS << ":?";*/ break; case MVT::iPTR: OS << ":iPTR"; break; case MVT::iPTRAny: OS << ":iPTRAny"; break; default: { std::string VTName = llvm::getName(getTypeNum(0)); - // Strip off MVT:: prefix if present. + // Strip off EVT:: prefix if present. if (VTName.substr(0,5) == "MVT::") VTName = VTName.substr(5); OS << ":" << VTName; @@ -726,7 +771,7 @@ TreePatternNode *TreePatternNode::InlinePatternFragments(TreePattern &TP) { static std::vector<unsigned char> getImplicitType(Record *R, bool NotRegisters, TreePattern &TP) { // Some common return values - std::vector<unsigned char> Unknown(1, EMVT::isUnknown); + std::vector<unsigned char> Unknown(1, EEVT::isUnknown); std::vector<unsigned char> Other(1, MVT::Other); // Check to see if this is a register or a register class... @@ -753,7 +798,7 @@ static std::vector<unsigned char> getImplicitType(Record *R, bool NotRegisters, std::vector<unsigned char> ComplexPat(1, TP.getDAGPatterns().getComplexPattern(R).getValueType()); return ComplexPat; - } else if (R->getName() == "ptr_rc") { + } else if (R->isSubClassOf("PointerLikeRegClass")) { Other[0] = MVT::iPTR; return Other; } else if (R->getName() == "node" || R->getName() == "srcvalue" || @@ -803,7 +848,7 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) { return UpdateNodeType(getImplicitType(DI->getDef(), NotRegisters, TP),TP); } else if (IntInit *II = dynamic_cast<IntInit*>(getLeafValue())) { // Int inits are always integers. :) - bool MadeChange = UpdateNodeType(EMVT::isInt, TP); + bool MadeChange = UpdateNodeType(MVT::iAny, TP); if (hasTypeSet()) { // At some point, it may make sense for this tree pattern to have @@ -816,7 +861,7 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) { VT = getTypeNum(0); if (VT != MVT::iPTR && VT != MVT::iPTRAny) { - unsigned Size = MVT(VT).getSizeInBits(); + unsigned Size = EVT(VT).getSizeInBits(); // Make sure that the value is representable for this type. if (Size < 32) { int Val = (II->getValue() << (32-Size)) >> (32-Size); @@ -924,13 +969,13 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) { } else { Record *ResultNode = Inst.getResult(0); - if (ResultNode->getName() == "ptr_rc") { + if (ResultNode->isSubClassOf("PointerLikeRegClass")) { std::vector<unsigned char> VT; VT.push_back(MVT::iPTR); MadeChange = UpdateNodeType(VT, TP); } else if (ResultNode->getName() == "unknown") { std::vector<unsigned char> VT; - VT.push_back(EMVT::isUnknown); + VT.push_back(EEVT::isUnknown); MadeChange = UpdateNodeType(VT, TP); } else { assert(ResultNode->isSubClassOf("RegisterClass") && @@ -968,10 +1013,10 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) { } else if (OperandNode->isSubClassOf("Operand")) { VT = getValueType(OperandNode->getValueAsDef("Type")); MadeChange |= Child->UpdateNodeType(VT, TP); - } else if (OperandNode->getName() == "ptr_rc") { + } else if (OperandNode->isSubClassOf("PointerLikeRegClass")) { MadeChange |= Child->UpdateNodeType(MVT::iPTR, TP); } else if (OperandNode->getName() == "unknown") { - MadeChange |= Child->UpdateNodeType(EMVT::isUnknown, TP); + MadeChange |= Child->UpdateNodeType(EEVT::isUnknown, TP); } else { assert(0 && "Unknown operand type!"); abort(); @@ -1297,7 +1342,7 @@ CodeGenDAGPatterns::CodeGenDAGPatterns(RecordKeeper &R) : Records(R) { } CodeGenDAGPatterns::~CodeGenDAGPatterns() { - for (std::map<Record*, TreePattern*>::iterator I = PatternFragments.begin(), + for (pf_iterator I = PatternFragments.begin(), E = PatternFragments.end(); I != E; ++I) delete I->second; } @@ -1602,7 +1647,7 @@ FindPatternInputsAndOutputs(TreePattern *I, TreePatternNode *Pat, I->error("set destination should be a register!"); if (Val->getDef()->isSubClassOf("RegisterClass") || - Val->getDef()->getName() == "ptr_rc") { + Val->getDef()->isSubClassOf("PointerLikeRegClass")) { if (Dest->getName().empty()) I->error("set destination must have a name!"); if (InstResults.count(Dest->getName())) @@ -1949,7 +1994,8 @@ void CodeGenDAGPatterns::ParseInstructions() { } // If we can, convert the instructions to be patterns that are matched! - for (std::map<Record*, DAGInstruction>::iterator II = Instructions.begin(), + for (std::map<Record*, DAGInstruction, RecordPtrCmp>::iterator II = + Instructions.begin(), E = Instructions.end(); II != E; ++II) { DAGInstruction &TheInst = II->second; const TreePattern *I = TheInst.getPattern(); @@ -2350,7 +2396,7 @@ static void GenerateVariantsOf(TreePatternNode *N, // GenerateVariants - Generate variants. For example, commutative patterns can // match multiple ways. Add them to PatternsToMatch as well. void CodeGenDAGPatterns::GenerateVariants() { - DOUT << "Generating instruction variants.\n"; + DEBUG(errs() << "Generating instruction variants.\n"); // Loop over all of the patterns we've collected, checking to see if we can // generate variants of the instruction, through the exploitation of @@ -2365,9 +2411,9 @@ void CodeGenDAGPatterns::GenerateVariants() { MultipleUseVarSet DepVars; std::vector<TreePatternNode*> Variants; FindDepVars(PatternsToMatch[i].getSrcPattern(), DepVars); - DOUT << "Dependent/multiply used variables: "; + DEBUG(errs() << "Dependent/multiply used variables: "); DEBUG(DumpDepVars(DepVars)); - DOUT << "\n"; + DEBUG(errs() << "\n"); GenerateVariantsOf(PatternsToMatch[i].getSrcPattern(), Variants, *this, DepVars); assert(!Variants.empty() && "Must create at least original variant!"); @@ -2376,16 +2422,16 @@ void CodeGenDAGPatterns::GenerateVariants() { if (Variants.empty()) // No variants for this pattern. continue; - DOUT << "FOUND VARIANTS OF: "; - DEBUG(PatternsToMatch[i].getSrcPattern()->dump()); - DOUT << "\n"; + DEBUG(errs() << "FOUND VARIANTS OF: "; + PatternsToMatch[i].getSrcPattern()->dump(); + errs() << "\n"); for (unsigned v = 0, e = Variants.size(); v != e; ++v) { TreePatternNode *Variant = Variants[v]; - DOUT << " VAR#" << v << ": "; - DEBUG(Variant->dump()); - DOUT << "\n"; + DEBUG(errs() << " VAR#" << v << ": "; + Variant->dump(); + errs() << "\n"); // Scan to see if an instruction or explicit pattern already matches this. bool AlreadyExists = false; @@ -2396,7 +2442,7 @@ void CodeGenDAGPatterns::GenerateVariants() { continue; // Check to see if this variant already exists. if (Variant->isIsomorphicTo(PatternsToMatch[p].getSrcPattern(), DepVars)) { - DOUT << " *** ALREADY EXISTS, ignoring variant.\n"; + DEBUG(errs() << " *** ALREADY EXISTS, ignoring variant.\n"); AlreadyExists = true; break; } @@ -2412,7 +2458,7 @@ void CodeGenDAGPatterns::GenerateVariants() { PatternsToMatch[i].getAddedComplexity())); } - DOUT << "\n"; + DEBUG(errs() << "\n"); } } diff --git a/utils/TableGen/CodeGenDAGPatterns.h b/utils/TableGen/CodeGenDAGPatterns.h index d398006..9b53ecc5 100644 --- a/utils/TableGen/CodeGenDAGPatterns.h +++ b/utils/TableGen/CodeGenDAGPatterns.h @@ -33,22 +33,27 @@ namespace llvm { class CodeGenDAGPatterns; class ComplexPattern; -/// EMVT::DAGISelGenValueType - These are some extended forms of +/// EEVT::DAGISelGenValueType - These are some extended forms of /// MVT::SimpleValueType that we use as lattice values during type inference. -namespace EMVT { +/// The existing MVT iAny, fAny and vAny types suffice to represent +/// arbitrary integer, floating-point, and vector types, so only an unknown +/// value is needed. +namespace EEVT { enum DAGISelGenValueType { - isFP = MVT::LAST_VALUETYPE, - isInt, - isUnknown + isUnknown = MVT::LAST_VALUETYPE }; - /// isExtIntegerVT - Return true if the specified extended value type vector - /// contains isInt or an integer value type. + /// isExtIntegerInVTs - Return true if the specified extended value type + /// vector contains iAny or an integer value type. bool isExtIntegerInVTs(const std::vector<unsigned char> &EVTs); - /// isExtFloatingPointVT - Return true if the specified extended value type - /// vector contains isFP or a FP value type. + /// isExtFloatingPointInVTs - Return true if the specified extended value + /// type vector contains fAny or a FP value type. bool isExtFloatingPointInVTs(const std::vector<unsigned char> &EVTs); + + /// isExtVectorinVTs - Return true if the specified extended value type + /// vector contains vAny or a vector value type. + bool isExtVectorInVTs(const std::vector<unsigned char> &EVTs); } /// Set type used to track multiply used variables in patterns @@ -61,7 +66,7 @@ struct SDTypeConstraint { unsigned OperandNo; // The operand # this constraint applies to. enum { - SDTCisVT, SDTCisPtrTy, SDTCisInt, SDTCisFP, SDTCisSameAs, + SDTCisVT, SDTCisPtrTy, SDTCisInt, SDTCisFP, SDTCisVec, SDTCisSameAs, SDTCisVTSmallerThanOp, SDTCisOpSmallerThanOp, SDTCisEltOfVec } ConstraintType; @@ -140,7 +145,7 @@ public: /// patterns), and as such should be ref counted. We currently just leak all /// TreePatternNode objects! class TreePatternNode { - /// The inferred type for this node, or EMVT::isUnknown if it hasn't + /// The inferred type for this node, or EEVT::isUnknown if it hasn't /// been determined yet. This is a std::vector because during inference /// there may be multiple possible types. std::vector<unsigned char> Types; @@ -169,10 +174,10 @@ class TreePatternNode { public: TreePatternNode(Record *Op, const std::vector<TreePatternNode*> &Ch) : Types(), Operator(Op), Val(0), TransformFn(0), - Children(Ch) { Types.push_back(EMVT::isUnknown); } + Children(Ch) { Types.push_back(EEVT::isUnknown); } TreePatternNode(Init *val) // leaf ctor : Types(), Operator(0), Val(val), TransformFn(0) { - Types.push_back(EMVT::isUnknown); + Types.push_back(EEVT::isUnknown); } ~TreePatternNode(); @@ -185,7 +190,7 @@ public: (Types[0] == MVT::iPTRAny); } bool isTypeCompletelyUnknown() const { - return Types[0] == EMVT::isUnknown; + return Types[0] == EEVT::isUnknown; } bool isTypeDynamicallyResolved() const { return (Types[0] == MVT::iPTR) || (Types[0] == MVT::iPTRAny); @@ -201,7 +206,7 @@ public: } const std::vector<unsigned char> &getExtTypes() const { return Types; } void setTypes(const std::vector<unsigned char> &T) { Types = T; } - void removeTypes() { Types = std::vector<unsigned char>(1, EMVT::isUnknown); } + void removeTypes() { Types = std::vector<unsigned char>(1, EEVT::isUnknown); } Init *getLeafValue() const { assert(isLeaf()); return Val; } Record *getOperator() const { assert(!isLeaf()); return Operator; } @@ -457,6 +462,10 @@ struct PatternToMatch { std::string getPredicateCheck() const; }; +// Deterministic comparison of Record*. +struct RecordPtrCmp { + bool operator()(const Record *LHS, const Record *RHS) const; +}; class CodeGenDAGPatterns { RecordKeeper &Records; @@ -464,12 +473,12 @@ class CodeGenDAGPatterns { std::vector<CodeGenIntrinsic> Intrinsics; std::vector<CodeGenIntrinsic> TgtIntrinsics; - std::map<Record*, SDNodeInfo> SDNodes; - std::map<Record*, std::pair<Record*, std::string> > SDNodeXForms; - std::map<Record*, ComplexPattern> ComplexPatterns; - std::map<Record*, TreePattern*> PatternFragments; - std::map<Record*, DAGDefaultOperand> DefaultOperands; - std::map<Record*, DAGInstruction> Instructions; + std::map<Record*, SDNodeInfo, RecordPtrCmp> SDNodes; + std::map<Record*, std::pair<Record*, std::string>, RecordPtrCmp> SDNodeXForms; + std::map<Record*, ComplexPattern, RecordPtrCmp> ComplexPatterns; + std::map<Record*, TreePattern*, RecordPtrCmp> PatternFragments; + std::map<Record*, DAGDefaultOperand, RecordPtrCmp> DefaultOperands; + std::map<Record*, DAGInstruction, RecordPtrCmp> Instructions; // Specific SDNode definitions: Record *intrinsic_void_sdnode; @@ -500,7 +509,8 @@ public: return SDNodeXForms.find(R)->second; } - typedef std::map<Record*, NodeXForm>::const_iterator nx_iterator; + typedef std::map<Record*, NodeXForm, RecordPtrCmp>::const_iterator + nx_iterator; nx_iterator nx_begin() const { return SDNodeXForms.begin(); } nx_iterator nx_end() const { return SDNodeXForms.end(); } @@ -547,7 +557,8 @@ public: assert(PatternFragments.count(R) && "Invalid pattern fragment request!"); return PatternFragments.find(R)->second; } - typedef std::map<Record*, TreePattern*>::const_iterator pf_iterator; + typedef std::map<Record*, TreePattern*, RecordPtrCmp>::const_iterator + pf_iterator; pf_iterator pf_begin() const { return PatternFragments.begin(); } pf_iterator pf_end() const { return PatternFragments.end(); } diff --git a/utils/TableGen/CodeGenInstruction.cpp b/utils/TableGen/CodeGenInstruction.cpp index 4650b88..d421fd0 100644 --- a/utils/TableGen/CodeGenInstruction.cpp +++ b/utils/TableGen/CodeGenInstruction.cpp @@ -22,7 +22,7 @@ static void ParseConstraint(const std::string &CStr, CodeGenInstruction *I) { std::string::size_type pos = CStr.find_first_of('='); assert(pos != std::string::npos && "Unrecognized constraint"); std::string::size_type start = CStr.find_first_not_of(" \t"); - std::string Name = CStr.substr(start, pos); + std::string Name = CStr.substr(start, pos - start); // TIED_TO: $src1 = $dst std::string::size_type wpos = Name.find_first_of(" \t"); @@ -70,7 +70,7 @@ static void ParseConstraints(const std::string &CStr, CodeGenInstruction *I) { if (eidx == std::string::npos) eidx = CStr.length(); - ParseConstraint(CStr.substr(bidx, eidx), I); + ParseConstraint(CStr.substr(bidx, eidx - bidx), I); bidx = CStr.find_first_not_of(delims, eidx); } } @@ -101,6 +101,8 @@ CodeGenInstruction::CodeGenInstruction(Record *R, const std::string &AsmStr) mayHaveSideEffects = R->getValueAsBit("mayHaveSideEffects"); neverHasSideEffects = R->getValueAsBit("neverHasSideEffects"); isAsCheapAsAMove = R->getValueAsBit("isAsCheapAsAMove"); + hasExtraSrcRegAllocReq = R->getValueAsBit("hasExtraSrcRegAllocReq"); + hasExtraDefRegAllocReq = R->getValueAsBit("hasExtraDefRegAllocReq"); hasOptionalDef = false; isVariadic = false; diff --git a/utils/TableGen/CodeGenInstruction.h b/utils/TableGen/CodeGenInstruction.h index f4afd5e..04506e9 100644 --- a/utils/TableGen/CodeGenInstruction.h +++ b/utils/TableGen/CodeGenInstruction.h @@ -106,6 +106,8 @@ namespace llvm { bool mayHaveSideEffects; bool neverHasSideEffects; bool isAsCheapAsAMove; + bool hasExtraSrcRegAllocReq; + bool hasExtraDefRegAllocReq; /// ParseOperandName - Parse an operand name like "$foo" or "$foo.bar", /// where $foo is a whole operand and $foo.bar refers to a suboperand. diff --git a/utils/TableGen/CodeGenTarget.cpp b/utils/TableGen/CodeGenTarget.cpp index c17cd0e..0edca73 100644 --- a/utils/TableGen/CodeGenTarget.cpp +++ b/utils/TableGen/CodeGenTarget.cpp @@ -23,6 +23,10 @@ using namespace llvm; static cl::opt<unsigned> +AsmParserNum("asmparsernum", cl::init(0), + cl::desc("Make -gen-asm-parser emit assembly parser #N")); + +static cl::opt<unsigned> AsmWriterNum("asmwriternum", cl::init(0), cl::desc("Make -gen-asm-writer emit assembly writer #N")); @@ -34,47 +38,10 @@ MVT::SimpleValueType llvm::getValueType(Record *Rec) { std::string llvm::getName(MVT::SimpleValueType T) { switch (T) { - case MVT::Other: return "UNKNOWN"; - case MVT::i1: return "MVT::i1"; - case MVT::i8: return "MVT::i8"; - case MVT::i16: return "MVT::i16"; - case MVT::i32: return "MVT::i32"; - case MVT::i64: return "MVT::i64"; - case MVT::i128: return "MVT::i128"; - case MVT::iAny: return "MVT::iAny"; - case MVT::fAny: return "MVT::fAny"; - case MVT::f32: return "MVT::f32"; - case MVT::f64: return "MVT::f64"; - case MVT::f80: return "MVT::f80"; - case MVT::f128: return "MVT::f128"; - case MVT::ppcf128: return "MVT::ppcf128"; - case MVT::Flag: return "MVT::Flag"; - case MVT::isVoid:return "MVT::isVoid"; - case MVT::v2i8: return "MVT::v2i8"; - case MVT::v4i8: return "MVT::v4i8"; - case MVT::v8i8: return "MVT::v8i8"; - case MVT::v16i8: return "MVT::v16i8"; - case MVT::v32i8: return "MVT::v32i8"; - case MVT::v2i16: return "MVT::v2i16"; - case MVT::v4i16: return "MVT::v4i16"; - case MVT::v8i16: return "MVT::v8i16"; - case MVT::v16i16: return "MVT::v16i16"; - case MVT::v2i32: return "MVT::v2i32"; - case MVT::v4i32: return "MVT::v4i32"; - case MVT::v8i32: return "MVT::v8i32"; - case MVT::v1i64: return "MVT::v1i64"; - case MVT::v2i64: return "MVT::v2i64"; - case MVT::v4i64: return "MVT::v4i64"; - case MVT::v2f32: return "MVT::v2f32"; - case MVT::v4f32: return "MVT::v4f32"; - case MVT::v8f32: return "MVT::v8f32"; - case MVT::v2f64: return "MVT::v2f64"; - case MVT::v4f64: return "MVT::v4f64"; - case MVT::v3i32: return "MVT::v3i32"; - case MVT::v3f32: return "MVT::v3f32"; - case MVT::iPTR: return "TLI.getPointerTy()"; - case MVT::iPTRAny: return "TLI.getPointerTy()"; - default: assert(0 && "ILLEGAL VALUE TYPE!"); return ""; + case MVT::Other: return "UNKNOWN"; + case MVT::iPTR: return "TLI.getPointerTy()"; + case MVT::iPTRAny: return "TLI.getPointerTy()"; + default: return getEnumName(T); } } @@ -89,6 +56,7 @@ std::string llvm::getEnumName(MVT::SimpleValueType T) { case MVT::i128: return "MVT::i128"; case MVT::iAny: return "MVT::iAny"; case MVT::fAny: return "MVT::fAny"; + case MVT::vAny: return "MVT::vAny"; case MVT::f32: return "MVT::f32"; case MVT::f64: return "MVT::f64"; case MVT::f80: return "MVT::f80"; @@ -116,8 +84,7 @@ std::string llvm::getEnumName(MVT::SimpleValueType T) { case MVT::v8f32: return "MVT::v8f32"; case MVT::v2f64: return "MVT::v2f64"; case MVT::v4f64: return "MVT::v4f64"; - case MVT::v3i32: return "MVT::v3i32"; - case MVT::v3f32: return "MVT::v3f32"; + case MVT::Metadata: return "MVT::Metadata"; case MVT::iPTR: return "MVT::iPTR"; case MVT::iPTRAny: return "MVT::iPTRAny"; default: assert(0 && "ILLEGAL VALUE TYPE!"); return ""; @@ -171,6 +138,15 @@ Record *CodeGenTarget::getInstructionSet() const { return TargetRec->getValueAsDef("InstructionSet"); } +/// getAsmParser - Return the AssemblyParser definition for this target. +/// +Record *CodeGenTarget::getAsmParser() const { + std::vector<Record*> LI = TargetRec->getValueAsListOfDefs("AssemblyParsers"); + if (AsmParserNum >= LI.size()) + throw "Target does not have an AsmParser #" + utostr(AsmParserNum) + "!"; + return LI[AsmParserNum]; +} + /// getAsmWriter - Return the AssemblyWriter definition for this target. /// Record *CodeGenTarget::getAsmWriter() const { @@ -265,7 +241,7 @@ CodeGenRegisterClass::CodeGenRegisterClass(Record *R) : TheDef(R) { unsigned Size = R->getValueAsInt("Size"); Namespace = R->getValueAsString("Namespace"); - SpillSize = Size ? Size : MVT(VTs[0]).getSizeInBits(); + SpillSize = Size ? Size : EVT(VTs[0]).getSizeInBits(); SpillAlignment = R->getValueAsInt("Alignment"); CopyCost = R->getValueAsInt("CopyCost"); MethodBodies = R->getValueAsCode("MethodBodies"); @@ -332,9 +308,9 @@ getInstructionsByEnumValue(std::vector<const CodeGenInstruction*> if (I == Instructions.end()) throw "Could not find 'GC_LABEL' instruction!"; const CodeGenInstruction *GC_LABEL = &I->second; - I = getInstructions().find("DECLARE"); - if (I == Instructions.end()) throw "Could not find 'DECLARE' instruction!"; - const CodeGenInstruction *DECLARE = &I->second; + I = getInstructions().find("KILL"); + if (I == Instructions.end()) throw "Could not find 'KILL' instruction!"; + const CodeGenInstruction *KILL = &I->second; I = getInstructions().find("EXTRACT_SUBREG"); if (I == Instructions.end()) @@ -367,7 +343,7 @@ getInstructionsByEnumValue(std::vector<const CodeGenInstruction*> NumberedInstructions.push_back(DBG_LABEL); NumberedInstructions.push_back(EH_LABEL); NumberedInstructions.push_back(GC_LABEL); - NumberedInstructions.push_back(DECLARE); + NumberedInstructions.push_back(KILL); NumberedInstructions.push_back(EXTRACT_SUBREG); NumberedInstructions.push_back(INSERT_SUBREG); NumberedInstructions.push_back(IMPLICIT_DEF); @@ -379,7 +355,7 @@ getInstructionsByEnumValue(std::vector<const CodeGenInstruction*> &II->second != DBG_LABEL && &II->second != EH_LABEL && &II->second != GC_LABEL && - &II->second != DECLARE && + &II->second != KILL && &II->second != EXTRACT_SUBREG && &II->second != INSERT_SUBREG && &II->second != IMPLICIT_DEF && @@ -517,11 +493,12 @@ CodeGenIntrinsic::CodeGenIntrinsic(Record *R) { // overloaded, all the types can be specified directly. assert(((!TyEl->isSubClassOf("LLVMExtendedElementVectorType") && !TyEl->isSubClassOf("LLVMTruncatedElementVectorType")) || - VT == MVT::iAny) && "Expected iAny type"); + VT == MVT::iAny || VT == MVT::vAny) && + "Expected iAny or vAny type"); } else { VT = getValueType(TyEl->getValueAsDef("VT")); } - if (VT == MVT::iAny || VT == MVT::fAny || VT == MVT::iPTRAny) { + if (EVT(VT).isOverloaded()) { OverloadedVTs.push_back(VT); isOverloaded |= true; } @@ -548,10 +525,11 @@ CodeGenIntrinsic::CodeGenIntrinsic(Record *R) { // overloaded, all the types can be specified directly. assert(((!TyEl->isSubClassOf("LLVMExtendedElementVectorType") && !TyEl->isSubClassOf("LLVMTruncatedElementVectorType")) || - VT == MVT::iAny) && "Expected iAny type"); + VT == MVT::iAny || VT == MVT::vAny) && + "Expected iAny or vAny type"); } else VT = getValueType(TyEl->getValueAsDef("VT")); - if (VT == MVT::iAny || VT == MVT::fAny || VT == MVT::iPTRAny) { + if (EVT(VT).isOverloaded()) { OverloadedVTs.push_back(VT); isOverloaded |= true; } diff --git a/utils/TableGen/CodeGenTarget.h b/utils/TableGen/CodeGenTarget.h index 0ec9955..e763795 100644 --- a/utils/TableGen/CodeGenTarget.h +++ b/utils/TableGen/CodeGenTarget.h @@ -87,6 +87,10 @@ public: /// Record *getInstructionSet() const; + /// getAsmParser - Return the AssemblyParser definition for this target. + /// + Record *getAsmParser() const; + /// getAsmWriter - Return the AssemblyWriter definition for this target. /// Record *getAsmWriter() const; diff --git a/utils/TableGen/DAGISelEmitter.cpp b/utils/TableGen/DAGISelEmitter.cpp index bb26a1d..dcf64e4 100644 --- a/utils/TableGen/DAGISelEmitter.cpp +++ b/utils/TableGen/DAGISelEmitter.cpp @@ -23,11 +23,8 @@ #include <iostream> using namespace llvm; -namespace { - cl::opt<bool> - GenDebug("gen-debug", cl::desc("Generate debug code"), - cl::init(false)); -} +static cl::opt<bool> +GenDebug("gen-debug", cl::desc("Generate debug code"), cl::init(false)); //===----------------------------------------------------------------------===// // DAGISelEmitter Helper methods @@ -60,8 +57,8 @@ static const ComplexPattern *NodeGetComplexPattern(TreePatternNode *N, /// patterns before small ones. This is used to determine the size of a /// pattern. static unsigned getPatternSize(TreePatternNode *P, CodeGenDAGPatterns &CGP) { - assert((EMVT::isExtIntegerInVTs(P->getExtTypes()) || - EMVT::isExtFloatingPointInVTs(P->getExtTypes()) || + assert((EEVT::isExtIntegerInVTs(P->getExtTypes()) || + EEVT::isExtFloatingPointInVTs(P->getExtTypes()) || P->getExtTypeNum(0) == MVT::isVoid || P->getExtTypeNum(0) == MVT::Flag || P->getExtTypeNum(0) == MVT::iPTR || @@ -698,7 +695,7 @@ public: if (DefInit *DI = dynamic_cast<DefInit*>(Child->getLeafValue())) { Record *LeafRec = DI->getDef(); if (LeafRec->isSubClassOf("RegisterClass") || - LeafRec->getName() == "ptr_rc") { + LeafRec->isSubClassOf("PointerLikeRegClass")) { // Handle register references. Nothing to do here. } else if (LeafRec->isSubClassOf("Register")) { // Handle register references. @@ -787,7 +784,7 @@ public: EmitResultCode(TreePatternNode *N, std::vector<Record*> DstRegs, bool InFlagDecled, bool ResNodeDecled, bool LikeLeaf = false, bool isRoot = false) { - // List of arguments of getTargetNode() or SelectNodeTo(). + // List of arguments of getMachineNode() or SelectNodeTo(). std::vector<std::string> NodeOps; // This is something selected from the pattern we matched. if (!N->getName().empty()) { @@ -932,7 +929,8 @@ public: unsigned ResNo = TmpNo++; assert(N->getExtTypes().size() == 1 && "Multiple types not handled!"); emitCode("SDValue Tmp" + utostr(ResNo) + - " = CurDAG->getTargetConstant(0x" + itohexstr(II->getValue()) + + " = CurDAG->getTargetConstant(0x" + + utohexstr((uint64_t) II->getValue()) + "ULL, " + getEnumName(N->getTypeNum(0)) + ");"); NodeOps.push_back("Tmp" + utostr(ResNo)); return NodeOps; @@ -1091,7 +1089,7 @@ public: std::string Code = "Opc" + utostr(OpcNo); if (!isRoot || (InputHasChain && !NodeHasChain)) - // For call to "getTargetNode()". + // For call to "getMachineNode()". Code += ", N.getDebugLoc()"; emitOpcode(II.Namespace + "::" + II.TheDef->getName()); @@ -1137,24 +1135,18 @@ public: emitCode("}"); } - // Generate MemOperandSDNodes nodes for each memory accesses covered by + // Populate MemRefs with entries for each memory accesses covered by // this pattern. - if (II.mayLoad | II.mayStore) { - std::vector<std::string>::const_iterator mi, mie; - for (mi = LSI.begin(), mie = LSI.end(); mi != mie; ++mi) { - std::string LSIName = "LSI_" + *mi; - emitCode("SDValue " + LSIName + " = " - "CurDAG->getMemOperand(cast<MemSDNode>(" + - *mi + ")->getMemOperand());"); - if (GenDebug) { - emitCode("CurDAG->setSubgraphColor(" + LSIName +".getNode(), \"yellow\");"); - emitCode("CurDAG->setSubgraphColor(" + LSIName +".getNode(), \"black\");"); - } - if (IsVariadic) - emitCode("Ops" + utostr(OpsNo) + ".push_back(" + LSIName + ");"); - else - AllOps.push_back(LSIName); - } + if (isRoot && !LSI.empty()) { + std::string MemRefs = "MemRefs" + utostr(OpsNo); + emitCode("MachineSDNode::mmo_iterator " + MemRefs + " = " + "MF->allocateMemRefsArray(" + utostr(LSI.size()) + ");"); + for (unsigned i = 0, e = LSI.size(); i != e; ++i) + emitCode(MemRefs + "[" + utostr(i) + "] = " + "cast<MemSDNode>(" + LSI[i] + ")->getMemOperand();"); + After.push_back("cast<MachineSDNode>(ResNode)->setMemRefs(" + + MemRefs + ", " + MemRefs + " + " + utostr(LSI.size()) + + ");"); } if (NodeHasChain) { @@ -1305,7 +1297,7 @@ public: // would leave users of the chain dangling. // if (!isRoot || (InputHasChain && !NodeHasChain)) { - Code = "CurDAG->getTargetNode(" + Code; + Code = "CurDAG->getMachineNode(" + Code; } else { Code = "CurDAG->SelectNodeTo(N.getNode(), " + Code; } @@ -1778,7 +1770,7 @@ void DAGISelEmitter::EmitInstructionSelector(raw_ostream &OS) { CallerCode += ", " + TargetOpcodes[j]; } for (unsigned j = 0, e = TargetVTs.size(); j != e; ++j) { - CalleeCode += ", MVT VT" + utostr(j); + CalleeCode += ", MVT::SimpleValueType VT" + utostr(j); CallerCode += ", " + TargetVTs[j]; } for (std::set<std::string>::iterator @@ -1930,7 +1922,7 @@ void DAGISelEmitter::EmitInstructionSelector(raw_ostream &OS) { << " std::vector<SDValue> Ops(N.getNode()->op_begin(), N.getNode()->op_end());\n" << " SelectInlineAsmMemoryOperands(Ops);\n\n" - << " std::vector<MVT> VTs;\n" + << " std::vector<EVT> VTs;\n" << " VTs.push_back(MVT::Other);\n" << " VTs.push_back(MVT::Flag);\n" << " SDValue New = CurDAG->getNode(ISD::INLINEASM, N.getDebugLoc(), " @@ -1959,32 +1951,14 @@ void DAGISelEmitter::EmitInstructionSelector(raw_ostream &OS) { << " MVT::Other, Tmp, Chain);\n" << "}\n\n"; - OS << "SDNode *Select_DECLARE(const SDValue &N) {\n" - << " SDValue Chain = N.getOperand(0);\n" - << " SDValue N1 = N.getOperand(1);\n" - << " SDValue N2 = N.getOperand(2);\n" - << " if (!isa<FrameIndexSDNode>(N1) || !isa<GlobalAddressSDNode>(N2)) {\n" - << " CannotYetSelect(N);\n" - << " }\n" - << " int FI = cast<FrameIndexSDNode>(N1)->getIndex();\n" - << " GlobalValue *GV = cast<GlobalAddressSDNode>(N2)->getGlobal();\n" - << " SDValue Tmp1 = " - << "CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy());\n" - << " SDValue Tmp2 = " - << "CurDAG->getTargetGlobalAddress(GV, TLI.getPointerTy());\n" - << " return CurDAG->SelectNodeTo(N.getNode(), TargetInstrInfo::DECLARE,\n" - << " MVT::Other, Tmp1, Tmp2, Chain);\n" - << "}\n\n"; - OS << "// The main instruction selector code.\n" << "SDNode *SelectCode(SDValue N) {\n" - << " MVT::SimpleValueType NVT = N.getNode()->getValueType(0).getSimpleVT();\n" + << " MVT::SimpleValueType NVT = N.getNode()->getValueType(0).getSimpleVT().SimpleTy;\n" << " switch (N.getOpcode()) {\n" << " default:\n" << " assert(!N.isMachineOpcode() && \"Node already selected!\");\n" << " break;\n" << " case ISD::EntryToken: // These nodes remain the same.\n" - << " case ISD::MEMOPERAND:\n" << " case ISD::BasicBlock:\n" << " case ISD::Register:\n" << " case ISD::HANDLENODE:\n" @@ -2009,7 +1983,6 @@ void DAGISelEmitter::EmitInstructionSelector(raw_ostream &OS) { << " case ISD::INLINEASM: return Select_INLINEASM(N);\n" << " case ISD::DBG_LABEL: return Select_DBG_LABEL(N);\n" << " case ISD::EH_LABEL: return Select_EH_LABEL(N);\n" - << " case ISD::DECLARE: return Select_DECLARE(N);\n" << " case ISD::UNDEF: return Select_UNDEF(N);\n"; // Loop over all of the case statements, emiting a call to each method we @@ -2083,20 +2056,19 @@ void DAGISelEmitter::EmitInstructionSelector(raw_ostream &OS) { << "}\n\n"; OS << "void CannotYetSelect(SDValue N) DISABLE_INLINE {\n" - << " cerr << \"Cannot yet select: \";\n" - << " N.getNode()->dump(CurDAG);\n" - << " cerr << '\\n';\n" - << " abort();\n" + << " std::string msg;\n" + << " raw_string_ostream Msg(msg);\n" + << " Msg << \"Cannot yet select: \";\n" + << " N.getNode()->print(Msg, CurDAG);\n" + << " llvm_report_error(Msg.str());\n" << "}\n\n"; OS << "void CannotYetSelectIntrinsic(SDValue N) DISABLE_INLINE {\n" - << " cerr << \"Cannot yet select: \";\n" + << " errs() << \"Cannot yet select: \";\n" << " unsigned iid = cast<ConstantSDNode>(N.getOperand(" << "N.getOperand(0).getValueType() == MVT::Other))->getZExtValue();\n" - << " cerr << \"intrinsic %\"<< " - << "Intrinsic::getName((Intrinsic::ID)iid);\n" - << " cerr << '\\n';\n" - << " abort();\n" + << " llvm_report_error(\"Cannot yet select: intrinsic %\" +\n" + << "Intrinsic::getName((Intrinsic::ID)iid));\n" << "}\n\n"; } @@ -2115,12 +2087,12 @@ void DAGISelEmitter::run(raw_ostream &OS) { EmitNodeTransforms(OS); EmitPredicateFunctions(OS); - DOUT << "\n\nALL PATTERNS TO MATCH:\n\n"; + DEBUG(errs() << "\n\nALL PATTERNS TO MATCH:\n\n"); for (CodeGenDAGPatterns::ptm_iterator I = CGP.ptm_begin(), E = CGP.ptm_end(); I != E; ++I) { - DOUT << "PATTERN: "; DEBUG(I->getSrcPattern()->dump()); - DOUT << "\nRESULT: "; DEBUG(I->getDstPattern()->dump()); - DOUT << "\n"; + DEBUG(errs() << "PATTERN: "; I->getSrcPattern()->dump()); + DEBUG(errs() << "\nRESULT: "; I->getDstPattern()->dump()); + DEBUG(errs() << "\n"); } // At this point, we have full information about the 'Patterns' we need to diff --git a/utils/TableGen/FastISelEmitter.cpp b/utils/TableGen/FastISelEmitter.cpp index 0a43f02..277640d 100644 --- a/utils/TableGen/FastISelEmitter.cpp +++ b/utils/TableGen/FastISelEmitter.cpp @@ -216,7 +216,6 @@ public: explicit FastISelMap(std::string InstNS); void CollectPatterns(CodeGenDAGPatterns &CGP); - void PrintClass(raw_ostream &OS); void PrintFunctionDefinitions(raw_ostream &OS); }; @@ -461,11 +460,11 @@ void FastISelMap::PrintFunctionDefinitions(raw_ostream &OS) { << getLegalCName(Opcode) << "_" << getLegalCName(getName(VT)) << "_"; Operands.PrintManglingSuffix(OS); - OS << "(MVT::SimpleValueType RetVT"; + OS << "(MVT RetVT"; if (!Operands.empty()) OS << ", "; Operands.PrintParameters(OS); - OS << ") {\nswitch (RetVT) {\n"; + OS << ") {\nswitch (RetVT.SimpleTy) {\n"; for (RetPredMap::const_iterator RI = RM.begin(), RE = RM.end(); RI != RE; ++RI) { MVT::SimpleValueType RetVT = RI->first; @@ -485,13 +484,13 @@ void FastISelMap::PrintFunctionDefinitions(raw_ostream &OS) { << getLegalCName(Opcode) << "_" << getLegalCName(getName(VT)) << "_"; Operands.PrintManglingSuffix(OS); - OS << "(MVT::SimpleValueType RetVT"; + OS << "(MVT RetVT"; if (!Operands.empty()) OS << ", "; Operands.PrintParameters(OS); OS << ") {\n"; - OS << " if (RetVT != " << getName(RM.begin()->first) + OS << " if (RetVT.SimpleTy != " << getName(RM.begin()->first) << ")\n return 0;\n"; const PredMap &PM = RM.begin()->second; @@ -555,12 +554,12 @@ void FastISelMap::PrintFunctionDefinitions(raw_ostream &OS) { OS << "unsigned FastEmit_" << getLegalCName(Opcode) << "_"; Operands.PrintManglingSuffix(OS); - OS << "(MVT::SimpleValueType VT, MVT::SimpleValueType RetVT"; + OS << "(MVT VT, MVT RetVT"; if (!Operands.empty()) OS << ", "; Operands.PrintParameters(OS); OS << ") {\n"; - OS << " switch (VT) {\n"; + OS << " switch (VT.SimpleTy) {\n"; for (TypeRetPredMap::const_iterator TI = TM.begin(), TE = TM.end(); TI != TE; ++TI) { MVT::SimpleValueType VT = TI->first; @@ -587,7 +586,7 @@ void FastISelMap::PrintFunctionDefinitions(raw_ostream &OS) { // on opcode and type. OS << "unsigned FastEmit_"; Operands.PrintManglingSuffix(OS); - OS << "(MVT::SimpleValueType VT, MVT::SimpleValueType RetVT, ISD::NodeType Opcode"; + OS << "(MVT VT, MVT RetVT, ISD::NodeType Opcode"; if (!Operands.empty()) OS << ", "; Operands.PrintParameters(OS); diff --git a/utils/TableGen/InstrInfoEmitter.cpp b/utils/TableGen/InstrInfoEmitter.cpp index 4502da1..3a104ea 100644 --- a/utils/TableGen/InstrInfoEmitter.cpp +++ b/utils/TableGen/InstrInfoEmitter.cpp @@ -15,6 +15,7 @@ #include "InstrInfoEmitter.h" #include "CodeGenTarget.h" #include "Record.h" +#include "llvm/ADT/StringExtras.h" #include <algorithm> using namespace llvm; @@ -94,13 +95,16 @@ InstrInfoEmitter::GetOperandInfo(const CodeGenInstruction &Inst) { if (OpR->isSubClassOf("RegisterClass")) Res += getQualifiedName(OpR) + "RegClassID, "; + else if (OpR->isSubClassOf("PointerLikeRegClass")) + Res += utostr(OpR->getValueAsInt("RegClassKind")) + ", "; else Res += "0, "; + // Fill in applicable flags. Res += "0"; // Ptr value whose register class is resolved via callback. - if (OpR->getName() == "ptr_rc") + if (OpR->isSubClassOf("PointerLikeRegClass")) Res += "|(1<<TOI::LookupPtrRegClass)"; // Predicate operands. Check to see if the original unexpanded operand @@ -276,6 +280,8 @@ void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num, if (Inst.isVariadic) OS << "|(1<<TID::Variadic)"; if (Inst.hasSideEffects) OS << "|(1<<TID::UnmodeledSideEffects)"; if (Inst.isAsCheapAsAMove) OS << "|(1<<TID::CheapAsAMove)"; + if (Inst.hasExtraSrcRegAllocReq) OS << "|(1<<TID::ExtraSrcRegAllocReq)"; + if (Inst.hasExtraDefRegAllocReq) OS << "|(1<<TID::ExtraDefRegAllocReq)"; OS << ", 0"; // Emit all of the target-specific flags... @@ -335,7 +341,7 @@ void InstrInfoEmitter::emitShiftedValue(Record *R, StringInit *Val, R->getName() != "DBG_LABEL" && R->getName() != "EH_LABEL" && R->getName() != "GC_LABEL" && - R->getName() != "DECLARE" && + R->getName() != "KILL" && R->getName() != "EXTRACT_SUBREG" && R->getName() != "INSERT_SUBREG" && R->getName() != "IMPLICIT_DEF" && diff --git a/utils/TableGen/IntrinsicEmitter.cpp b/utils/TableGen/IntrinsicEmitter.cpp index 3676831..23919d9 100644 --- a/utils/TableGen/IntrinsicEmitter.cpp +++ b/utils/TableGen/IntrinsicEmitter.cpp @@ -141,24 +141,26 @@ EmitIntrinsicToOverloadTable(const std::vector<CodeGenIntrinsic> &Ints, } static void EmitTypeForValueType(raw_ostream &OS, MVT::SimpleValueType VT) { - if (MVT(VT).isInteger()) { - unsigned BitWidth = MVT(VT).getSizeInBits(); - OS << "IntegerType::get(" << BitWidth << ")"; + 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()"; + OS << "StructType::get(Context)"; } else if (VT == MVT::f32) { - OS << "Type::FloatTy"; + OS << "Type::getFloatTy(Context)"; } else if (VT == MVT::f64) { - OS << "Type::DoubleTy"; + OS << "Type::getDoubleTy(Context)"; } else if (VT == MVT::f80) { - OS << "Type::X86_FP80Ty"; + OS << "Type::getX86_FP80Ty(Context)"; } else if (VT == MVT::f128) { - OS << "Type::FP128Ty"; + OS << "Type::getFP128Ty(Context)"; } else if (VT == MVT::ppcf128) { - OS << "Type::PPC_FP128Ty"; + OS << "Type::getPPC_FP128Ty(Context)"; } else if (VT == MVT::isVoid) { - OS << "Type::VoidTy"; + OS << "Type::getVoidTy(Context)"; + } else if (VT == MVT::Metadata) { + OS << "Type::getMetadataTy(Context)"; } else { assert(false && "Unsupported ValueType!"); } @@ -175,7 +177,7 @@ static void EmitTypeGenerate(raw_ostream &OS, return; } - OS << "StructType::get("; + OS << "StructType::get(Context, "; for (std::vector<Record*>::const_iterator I = ArgTypes.begin(), E = ArgTypes.end(); I != E; ++I) { @@ -201,17 +203,17 @@ static void EmitTypeGenerate(raw_ostream &OS, const Record *ArgType, << "(dyn_cast<VectorType>(Tys[" << Number << "]))"; else OS << "Tys[" << Number << "]"; - } else if (VT == MVT::iAny || VT == MVT::fAny) { + } 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 (MVT(VT).isVector()) { - MVT VVT = VT; + } else if (EVT(VT).isVector()) { + EVT VVT = VT; OS << "VectorType::get("; - EmitTypeForValueType(OS, VVT.getVectorElementType().getSimpleVT()); + EmitTypeForValueType(OS, VVT.getVectorElementType().getSimpleVT().SimpleTy); OS << ", " << VVT.getVectorNumElements() << ")"; } else if (VT == MVT::iPTR) { OS << "PointerType::getUnqual("; @@ -227,7 +229,7 @@ static void EmitTypeGenerate(raw_ostream &OS, const Record *ArgType, ++ArgNo; } else if (VT == MVT::isVoid) { if (ArgNo == 0) - OS << "Type::VoidTy"; + OS << "Type::getVoidTy(Context)"; else // MVT::isVoid is used to mean varargs here. OS << "..."; @@ -302,6 +304,7 @@ void IntrinsicEmitter::EmitVerifier(const std::vector<CodeGenIntrinsic> &Ints, 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(); @@ -313,6 +316,9 @@ void IntrinsicEmitter::EmitVerifier(const std::vector<CodeGenIntrinsic> &Ints, 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")) @@ -323,6 +329,9 @@ void IntrinsicEmitter::EmitVerifier(const std::vector<CodeGenIntrinsic> &Ints, 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"; } @@ -335,6 +344,9 @@ void IntrinsicEmitter::EmitVerifier(const std::vector<CodeGenIntrinsic> &Ints, 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")) @@ -345,6 +357,9 @@ void IntrinsicEmitter::EmitVerifier(const std::vector<CodeGenIntrinsic> &Ints, 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"; } diff --git a/utils/TableGen/LLVMCConfigurationEmitter.cpp b/utils/TableGen/LLVMCConfigurationEmitter.cpp index fc182ce..06afaf7 100644 --- a/utils/TableGen/LLVMCConfigurationEmitter.cpp +++ b/utils/TableGen/LLVMCConfigurationEmitter.cpp @@ -39,10 +39,11 @@ typedef std::vector<std::string> StrVector; //===----------------------------------------------------------------------===// /// Constants -// Indentation strings. -const char * Indent1 = " "; -const char * Indent2 = " "; -const char * Indent3 = " "; +// Indentation. +unsigned TabWidth = 4; +unsigned Indent1 = TabWidth*1; +unsigned Indent2 = TabWidth*2; +unsigned Indent3 = TabWidth*3; // Default help string. const char * DefaultHelpString = "NO HELP MESSAGE PROVIDED"; @@ -81,16 +82,15 @@ const DagInit& InitPtrToDag(const Init* ptr) { } // checkNumberOfArguments - Ensure that the number of args in d is -// less than or equal to min_arguments, otherwise throw an exception. +// greater than or equal to min_arguments, otherwise throw an exception. void checkNumberOfArguments (const DagInit* d, unsigned min_arguments) { if (!d || d->getNumArgs() < min_arguments) - throw d->getOperator()->getAsString() - + ": too few arguments!"; + throw d->getOperator()->getAsString() + ": too few arguments!"; } // isDagEmpty - is this DAG marked with an empty marker? bool isDagEmpty (const DagInit* d) { - return d->getOperator()->getAsString() == "empty"; + return d->getOperator()->getAsString() == "empty_dag_marker"; } // EscapeVariableName - Escape commas and other symbols not allowed @@ -139,20 +139,21 @@ void checkedIncrement(I& P, I E, S ErrorString) { /// OptionType - One of six different option types. See the /// documentation for detailed description of differences. namespace OptionType { + enum OptionType { Alias, Switch, Parameter, ParameterList, Prefix, PrefixList}; -bool IsList (OptionType t) { - return (t == ParameterList || t == PrefixList); -} + bool IsList (OptionType t) { + return (t == ParameterList || t == PrefixList); + } -bool IsSwitch (OptionType t) { - return (t == Switch); -} + bool IsSwitch (OptionType t) { + return (t == Switch); + } -bool IsParameter (OptionType t) { - return (t == Parameter || t == Prefix); -} + bool IsParameter (OptionType t) { + return (t == Parameter || t == Prefix); + } } @@ -187,11 +188,12 @@ struct OptionDescription { unsigned Flags; std::string Help; unsigned MultiVal; + Init* InitVal; OptionDescription(OptionType::OptionType t = OptionType::Switch, const std::string& n = "", const std::string& h = DefaultHelpString) - : Type(t), Name(n), Flags(0x0), Help(h), MultiVal(1) + : Type(t), Name(n), Flags(0x0), Help(h), MultiVal(1), InitVal(0) {} /// GenTypeDeclaration - Returns the C++ variable type of this @@ -229,6 +231,15 @@ struct OptionDescription { bool isReallyHidden() const; void setReallyHidden(); + bool isParameter() const + { return OptionType::IsParameter(this->Type); } + + bool isSwitch() const + { return OptionType::IsSwitch(this->Type); } + + bool isList() const + { return OptionType::IsList(this->Type); } + }; void OptionDescription::Merge (const OptionDescription& other) @@ -438,6 +449,7 @@ public: AddHandler("extern", &CollectOptionProperties::onExtern); AddHandler("help", &CollectOptionProperties::onHelp); AddHandler("hidden", &CollectOptionProperties::onHidden); + AddHandler("init", &CollectOptionProperties::onInit); AddHandler("multi_val", &CollectOptionProperties::onMultiVal); AddHandler("one_or_more", &CollectOptionProperties::onOneOrMore); AddHandler("really_hidden", &CollectOptionProperties::onReallyHidden); @@ -481,6 +493,20 @@ private: optDesc_.setRequired(); } + void onInit (const DagInit* d) { + checkNumberOfArguments(d, 1); + Init* i = d->getArg(0); + const std::string& str = i->getAsString(); + + bool correct = optDesc_.isParameter() && dynamic_cast<StringInit*>(i); + correct |= (optDesc_.isSwitch() && (str == "true" || str == "false")); + + if (!correct) + throw std::string("Incorrect usage of the 'init' option property!"); + + optDesc_.InitVal = i; + } + void onOneOrMore (const DagInit* d) { checkNumberOfArguments(d, 0); if (optDesc_.isRequired() || optDesc_.isZeroOrOne()) @@ -950,8 +976,22 @@ void CheckForSuperfluousOptions (const RecordVector& Edges, } } -/// EmitCaseTest1Arg - Helper function used by -/// EmitCaseConstructHandler. +/// EmitCaseTest0Args - Helper function used by EmitCaseConstructHandler(). +bool EmitCaseTest0Args(const std::string& TestName, raw_ostream& O) { + if (TestName == "single_input_file") { + O << "InputFilenames.size() == 1"; + return true; + } + else if (TestName == "multiple_input_files") { + O << "InputFilenames.size() > 1"; + return true; + } + + return false; +} + + +/// EmitCaseTest1Arg - Helper function used by EmitCaseConstructHandler(). bool EmitCaseTest1Arg(const std::string& TestName, const DagInit& d, const OptionDescriptions& OptDescs, @@ -961,7 +1001,7 @@ bool EmitCaseTest1Arg(const std::string& TestName, if (TestName == "switch_on") { const OptionDescription& OptDesc = OptDescs.FindOption(OptName); - if (!OptionType::IsSwitch(OptDesc.Type)) + if (!OptDesc.isSwitch()) throw OptName + ": incorrect option type - should be a switch!"; O << OptDesc.GenVariableName(); return true; @@ -984,7 +1024,7 @@ bool EmitCaseTest1Arg(const std::string& TestName, } else { const OptionDescription& OptDesc = OptDescs.FindOption(OptName); - if (OptionType::IsSwitch(OptDesc.Type)) + if (OptDesc.isSwitch()) throw OptName + ": incorrect option type - should be a list or parameter!"; O << Test << OptDesc.GenVariableName() << ".empty()"; @@ -995,11 +1035,10 @@ bool EmitCaseTest1Arg(const std::string& TestName, return false; } -/// EmitCaseTest2Args - Helper function used by -/// EmitCaseConstructHandler. +/// EmitCaseTest2Args - Helper function used by EmitCaseConstructHandler(). bool EmitCaseTest2Args(const std::string& TestName, const DagInit& d, - const char* IndentLevel, + unsigned IndentLevel, const OptionDescriptions& OptDescs, raw_ostream& O) { checkNumberOfArguments(&d, 2); @@ -1008,17 +1047,18 @@ bool EmitCaseTest2Args(const std::string& TestName, const OptionDescription& OptDesc = OptDescs.FindOption(OptName); if (TestName == "parameter_equals") { - if (!OptionType::IsParameter(OptDesc.Type)) + if (!OptDesc.isParameter()) throw OptName + ": incorrect option type - should be a parameter!"; O << OptDesc.GenVariableName() << " == \"" << OptArg << "\""; return true; } else if (TestName == "element_in_list") { - if (!OptionType::IsList(OptDesc.Type)) + if (!OptDesc.isList()) throw OptName + ": incorrect option type - should be a list!"; const std::string& VarName = OptDesc.GenVariableName(); - O << "std::find(" << VarName << ".begin(),\n" - << IndentLevel << Indent1 << VarName << ".end(), \"" + O << "std::find(" << VarName << ".begin(),\n"; + O.indent(IndentLevel + Indent1) + << VarName << ".end(), \"" << OptArg << "\") != " << VarName << ".end()"; return true; } @@ -1028,29 +1068,42 @@ bool EmitCaseTest2Args(const std::string& TestName, // Forward declaration. // EmitLogicalOperationTest and EmitCaseTest are mutually recursive. -void EmitCaseTest(const DagInit& d, const char* IndentLevel, +void EmitCaseTest(const DagInit& d, unsigned IndentLevel, const OptionDescriptions& OptDescs, raw_ostream& O); /// EmitLogicalOperationTest - Helper function used by /// EmitCaseConstructHandler. void EmitLogicalOperationTest(const DagInit& d, const char* LogicOp, - const char* IndentLevel, + unsigned IndentLevel, const OptionDescriptions& OptDescs, raw_ostream& O) { O << '('; for (unsigned j = 0, NumArgs = d.getNumArgs(); j < NumArgs; ++j) { const DagInit& InnerTest = InitPtrToDag(d.getArg(j)); EmitCaseTest(InnerTest, IndentLevel, OptDescs, O); - if (j != NumArgs - 1) - O << ")\n" << IndentLevel << Indent1 << ' ' << LogicOp << " ("; - else + if (j != NumArgs - 1) { + O << ")\n"; + O.indent(IndentLevel + Indent1) << ' ' << LogicOp << " ("; + } + else { O << ')'; + } } } +void EmitLogicalNot(const DagInit& d, unsigned IndentLevel, + const OptionDescriptions& OptDescs, raw_ostream& O) +{ + checkNumberOfArguments(&d, 1); + const DagInit& InnerTest = InitPtrToDag(d.getArg(0)); + O << "! ("; + EmitCaseTest(InnerTest, IndentLevel, OptDescs, O); + O << ")"; +} + /// EmitCaseTest - Helper function used by EmitCaseConstructHandler. -void EmitCaseTest(const DagInit& d, const char* IndentLevel, +void EmitCaseTest(const DagInit& d, unsigned IndentLevel, const OptionDescriptions& OptDescs, raw_ostream& O) { const std::string& TestName = d.getOperator()->getAsString(); @@ -1059,6 +1112,10 @@ void EmitCaseTest(const DagInit& d, const char* IndentLevel, EmitLogicalOperationTest(d, "&&", IndentLevel, OptDescs, O); else if (TestName == "or") EmitLogicalOperationTest(d, "||", IndentLevel, OptDescs, O); + else if (TestName == "not") + EmitLogicalNot(d, IndentLevel, OptDescs, O); + else if (EmitCaseTest0Args(TestName, O)) + return; else if (EmitCaseTest1Arg(TestName, d, OptDescs, O)) return; else if (EmitCaseTest2Args(TestName, d, IndentLevel, OptDescs, O)) @@ -1070,9 +1127,9 @@ void EmitCaseTest(const DagInit& d, const char* IndentLevel, // Emit code that handles the 'case' construct. // Takes a function object that should emit code for every case clause. // Callback's type is -// void F(Init* Statement, const char* IndentLevel, raw_ostream& O). +// void F(Init* Statement, unsigned IndentLevel, raw_ostream& O). template <typename F> -void EmitCaseConstructHandler(const Init* Dag, const char* IndentLevel, +void EmitCaseConstructHandler(const Init* Dag, unsigned IndentLevel, F Callback, bool EmitElseIf, const OptionDescriptions& OptDescs, raw_ostream& O) { @@ -1094,10 +1151,10 @@ void EmitCaseConstructHandler(const Init* Dag, const char* IndentLevel, if (i+2 != numArgs) throw std::string("The 'default' clause should be the last in the" "'case' construct!"); - O << IndentLevel << "else {\n"; + O.indent(IndentLevel) << "else {\n"; } else { - O << IndentLevel << ((i != 0 && EmitElseIf) ? "else if (" : "if ("); + O.indent(IndentLevel) << ((i != 0 && EmitElseIf) ? "else if (" : "if ("); EmitCaseTest(Test, IndentLevel, OptDescs, O); O << ") {\n"; } @@ -1112,13 +1169,13 @@ void EmitCaseConstructHandler(const Init* Dag, const char* IndentLevel, const DagInit* nd = dynamic_cast<DagInit*>(arg); if (nd && (nd->getOperator()->getAsString() == "case")) { // Handle the nested 'case'. - EmitCaseConstructHandler(nd, (std::string(IndentLevel) + Indent1).c_str(), + EmitCaseConstructHandler(nd, (IndentLevel + Indent1), Callback, EmitElseIf, OptDescs, O); } else { - Callback(arg, (std::string(IndentLevel) + Indent1).c_str(), O); + Callback(arg, (IndentLevel + Indent1), O); } - O << IndentLevel << "}\n"; + O.indent(IndentLevel) << "}\n"; } } @@ -1272,7 +1329,7 @@ StrVector::const_iterator SubstituteSpecialCommands /// EmitCmdLineVecFill - Emit code that fills in the command line /// vector. Helper function used by EmitGenerateActionMethod(). void EmitCmdLineVecFill(const Init* CmdLine, const std::string& ToolName, - bool IsJoin, const char* IndentLevel, + bool IsJoin, unsigned IndentLevel, raw_ostream& O) { StrVector StrVec; TokenizeCmdline(InitPtrToString(CmdLine), StrVec); @@ -1295,22 +1352,28 @@ void EmitCmdLineVecFill(const Init* CmdLine, const std::string& ToolName, ++I; } + bool hasINFILE = false; + for (; I != E; ++I) { const std::string& cmd = *I; assert(!cmd.empty()); - O << IndentLevel; + O.indent(IndentLevel); if (cmd.at(0) == '$') { if (cmd == "$INFILE") { - if (IsJoin) + hasINFILE = true; + if (IsJoin) { O << "for (PathVector::const_iterator B = inFiles.begin()" - << ", E = inFiles.end();\n" - << IndentLevel << "B != E; ++B)\n" - << IndentLevel << Indent1 << "vec.push_back(B->toString());\n"; - else - O << "vec.push_back(inFile.toString());\n"; + << ", E = inFiles.end();\n"; + O.indent(IndentLevel) << "B != E; ++B)\n"; + O.indent(IndentLevel + Indent1) << "vec.push_back(B->str());\n"; + } + else { + O << "vec.push_back(inFile.str());\n"; + } } else if (cmd == "$OUTFILE") { - O << "vec.push_back(out_file);\n"; + O << "vec.push_back(\"\");\n"; + O.indent(IndentLevel) << "out_file_index = vec.size()-1;\n"; } else { O << "vec.push_back("; @@ -1322,8 +1385,10 @@ void EmitCmdLineVecFill(const Init* CmdLine, const std::string& ToolName, O << "vec.push_back(\"" << cmd << "\");\n"; } } - O << IndentLevel << "cmd = "; + if (!hasINFILE) + throw "Tool '" + ToolName + "' doesn't take any input!"; + O.indent(IndentLevel) << "cmd = "; if (StrVec[0][0] == '$') SubstituteSpecialCommands(StrVec.begin(), StrVec.end(), O); else @@ -1341,11 +1406,10 @@ class EmitCmdLineVecFillCallback { EmitCmdLineVecFillCallback(bool J, const std::string& TN) : IsJoin(J), ToolName(TN) {} - void operator()(const Init* Statement, const char* IndentLevel, + void operator()(const Init* Statement, unsigned IndentLevel, raw_ostream& O) const { - EmitCmdLineVecFill(Statement, ToolName, IsJoin, - IndentLevel, O); + EmitCmdLineVecFill(Statement, ToolName, IsJoin, IndentLevel, O); } }; @@ -1353,53 +1417,56 @@ class EmitCmdLineVecFillCallback { /// implement EmitActionHandler. Emits code for /// handling the (forward) and (forward_as) option properties. void EmitForwardOptionPropertyHandlingCode (const OptionDescription& D, - const char* Indent, + unsigned IndentLevel, const std::string& NewName, raw_ostream& O) { const std::string& Name = NewName.empty() ? ("-" + D.Name) : NewName; + unsigned IndentLevel1 = IndentLevel + Indent1; switch (D.Type) { case OptionType::Switch: - O << Indent << "vec.push_back(\"" << Name << "\");\n"; + O.indent(IndentLevel) << "vec.push_back(\"" << Name << "\");\n"; break; case OptionType::Parameter: - O << Indent << "vec.push_back(\"" << Name << "\");\n"; - O << Indent << "vec.push_back(" << D.GenVariableName() << ");\n"; + O.indent(IndentLevel) << "vec.push_back(\"" << Name << "\");\n"; + O.indent(IndentLevel) << "vec.push_back(" << D.GenVariableName() << ");\n"; break; case OptionType::Prefix: - O << Indent << "vec.push_back(\"" << Name << "\" + " - << D.GenVariableName() << ");\n"; + O.indent(IndentLevel) << "vec.push_back(\"" << Name << "\" + " + << D.GenVariableName() << ");\n"; break; case OptionType::PrefixList: - O << Indent << "for (" << D.GenTypeDeclaration() - << "::iterator B = " << D.GenVariableName() << ".begin(),\n" - << Indent << "E = " << D.GenVariableName() << ".end(); B != E;) {\n" - << Indent << Indent1 << "vec.push_back(\"" << Name << "\" + " - << "*B);\n" - << Indent << Indent1 << "++B;\n"; + O.indent(IndentLevel) + << "for (" << D.GenTypeDeclaration() + << "::iterator B = " << D.GenVariableName() << ".begin(),\n"; + O.indent(IndentLevel) + << "E = " << D.GenVariableName() << ".end(); B != E;) {\n"; + O.indent(IndentLevel1) << "vec.push_back(\"" << Name << "\" + " << "*B);\n"; + O.indent(IndentLevel1) << "++B;\n"; for (int i = 1, j = D.MultiVal; i < j; ++i) { - O << Indent << Indent1 << "vec.push_back(*B);\n" - << Indent << Indent1 << "++B;\n"; + O.indent(IndentLevel1) << "vec.push_back(*B);\n"; + O.indent(IndentLevel1) << "++B;\n"; } - O << Indent << "}\n"; + O.indent(IndentLevel) << "}\n"; break; case OptionType::ParameterList: - O << Indent << "for (" << D.GenTypeDeclaration() - << "::iterator B = " << D.GenVariableName() << ".begin(),\n" - << Indent << "E = " << D.GenVariableName() - << ".end() ; B != E;) {\n" - << Indent << Indent1 << "vec.push_back(\"" << Name << "\");\n"; + O.indent(IndentLevel) + << "for (" << D.GenTypeDeclaration() << "::iterator B = " + << D.GenVariableName() << ".begin(),\n"; + O.indent(IndentLevel) << "E = " << D.GenVariableName() + << ".end() ; B != E;) {\n"; + O.indent(IndentLevel1) << "vec.push_back(\"" << Name << "\");\n"; for (int i = 0, j = D.MultiVal; i < j; ++i) { - O << Indent << Indent1 << "vec.push_back(*B);\n" - << Indent << Indent1 << "++B;\n"; + O.indent(IndentLevel1) << "vec.push_back(*B);\n"; + O.indent(IndentLevel1) << "++B;\n"; } - O << Indent << "}\n"; + O.indent(IndentLevel) << "}\n"; break; case OptionType::Alias: default: @@ -1413,7 +1480,7 @@ void EmitForwardOptionPropertyHandlingCode (const OptionDescription& D, class EmitActionHandler { const OptionDescriptions& OptDescs; - void processActionDag(const Init* Statement, const char* IndentLevel, + void processActionDag(const Init* Statement, unsigned IndentLevel, raw_ostream& O) const { const DagInit& Dag = InitPtrToDag(Statement); @@ -1427,10 +1494,10 @@ class EmitActionHandler { for (StrVector::const_iterator B = Out.begin(), E = Out.end(); B != E; ++B) - O << IndentLevel << "vec.push_back(\"" << *B << "\");\n"; + O.indent(IndentLevel) << "vec.push_back(\"" << *B << "\");\n"; } else if (ActionName == "error") { - O << IndentLevel << "throw std::runtime_error(\"" << + O.indent(IndentLevel) << "throw std::runtime_error(\"" << (Dag.getNumArgs() >= 1 ? InitPtrToString(Dag.getArg(0)) : "Unknown error!") << "\");\n"; @@ -1451,10 +1518,10 @@ class EmitActionHandler { else if (ActionName == "output_suffix") { checkNumberOfArguments(&Dag, 1); const std::string& OutSuf = InitPtrToString(Dag.getArg(0)); - O << IndentLevel << "output_suffix = \"" << OutSuf << "\";\n"; + O.indent(IndentLevel) << "output_suffix = \"" << OutSuf << "\";\n"; } else if (ActionName == "stop_compilation") { - O << IndentLevel << "stop_compilation = true;\n"; + O.indent(IndentLevel) << "stop_compilation = true;\n"; } else if (ActionName == "unpack_values") { checkNumberOfArguments(&Dag, 1); @@ -1464,16 +1531,18 @@ class EmitActionHandler { if (D.isMultiVal()) throw std::string("Can't use unpack_values with multi-valued options!"); - if (OptionType::IsList(D.Type)) { - O << IndentLevel << "for (" << D.GenTypeDeclaration() - << "::iterator B = " << D.GenVariableName() << ".begin(),\n" - << IndentLevel << "E = " << D.GenVariableName() - << ".end(); B != E; ++B)\n" - << IndentLevel << Indent1 << "llvm::SplitString(*B, vec, \",\");\n"; + if (D.isList()) { + O.indent(IndentLevel) + << "for (" << D.GenTypeDeclaration() + << "::iterator B = " << D.GenVariableName() << ".begin(),\n"; + O.indent(IndentLevel) + << "E = " << D.GenVariableName() << ".end(); B != E; ++B)\n"; + O.indent(IndentLevel + Indent1) + << "llvm::SplitString(*B, vec, \",\");\n"; } - else if (OptionType::IsParameter(D.Type)){ - O << Indent3 << "llvm::SplitString(" - << D.GenVariableName() << ", vec, \",\");\n"; + else if (D.isParameter()){ + O.indent(IndentLevel) << "llvm::SplitString(" + << D.GenVariableName() << ", vec, \",\");\n"; } else { throw "Option '" + D.Name + @@ -1488,7 +1557,7 @@ class EmitActionHandler { EmitActionHandler(const OptionDescriptions& OD) : OptDescs(OD) {} - void operator()(const Init* Statement, const char* IndentLevel, + void operator()(const Init* Statement, unsigned IndentLevel, raw_ostream& O) const { if (typeid(*Statement) == typeid(ListInit)) { @@ -1503,56 +1572,111 @@ class EmitActionHandler { } }; -// EmitGenerateActionMethod - Emit one of two versions of the +bool IsOutFileIndexCheckRequiredStr (const Init* CmdLine) { + StrVector StrVec; + TokenizeCmdline(InitPtrToString(CmdLine), StrVec); + + for (StrVector::const_iterator I = StrVec.begin(), E = StrVec.end(); + I != E; ++I) { + if (*I == "$OUTFILE") + return false; + } + + return true; +} + +class IsOutFileIndexCheckRequiredStrCallback { + bool* ret_; + +public: + IsOutFileIndexCheckRequiredStrCallback(bool* ret) : ret_(ret) + {} + + void operator()(const Init* CmdLine) { + if (IsOutFileIndexCheckRequiredStr(CmdLine)) + *ret_ = true; + } +}; + +bool IsOutFileIndexCheckRequiredCase (Init* CmdLine) { + bool ret = false; + WalkCase(CmdLine, Id(), IsOutFileIndexCheckRequiredStrCallback(&ret)); + return ret; +} + +/// IsOutFileIndexCheckRequired - Should we emit an "out_file_index != -1" check +/// in EmitGenerateActionMethod() ? +bool IsOutFileIndexCheckRequired (Init* CmdLine) { + if (typeid(*CmdLine) == typeid(StringInit)) + return IsOutFileIndexCheckRequiredStr(CmdLine); + else + return IsOutFileIndexCheckRequiredCase(CmdLine); +} + +// EmitGenerateActionMethod - Emit either a normal or a "join" version of the // Tool::GenerateAction() method. void EmitGenerateActionMethod (const ToolDescription& D, const OptionDescriptions& OptDescs, bool IsJoin, raw_ostream& O) { if (IsJoin) - O << Indent1 << "Action GenerateAction(const PathVector& inFiles,\n"; + O.indent(Indent1) << "Action GenerateAction(const PathVector& inFiles,\n"; else - O << Indent1 << "Action GenerateAction(const sys::Path& inFile,\n"; - - O << Indent2 << "bool HasChildren,\n" - << Indent2 << "const llvm::sys::Path& TempDir,\n" - << Indent2 << "const InputLanguagesSet& InLangs,\n" - << Indent2 << "const LanguageMap& LangMap) const\n" - << Indent1 << "{\n" - << Indent2 << "std::string cmd;\n" - << Indent2 << "std::vector<std::string> vec;\n" - << Indent2 << "bool stop_compilation = !HasChildren;\n" - << Indent2 << "const char* output_suffix = \"" << D.OutputSuffix << "\";\n" - << Indent2 << "std::string out_file;\n\n"; - - // For every understood option, emit handling code. - if (D.Actions) - EmitCaseConstructHandler(D.Actions, Indent2, EmitActionHandler(OptDescs), - false, OptDescs, O); - - O << '\n' << Indent2 - << "out_file = OutFilename(" << (IsJoin ? "sys::Path(),\n" : "inFile,\n") - << Indent3 << "TempDir, stop_compilation, output_suffix).toString();\n\n"; + O.indent(Indent1) << "Action GenerateAction(const sys::Path& inFile,\n"; + + O.indent(Indent2) << "bool HasChildren,\n"; + O.indent(Indent2) << "const llvm::sys::Path& TempDir,\n"; + O.indent(Indent2) << "const InputLanguagesSet& InLangs,\n"; + O.indent(Indent2) << "const LanguageMap& LangMap) const\n"; + O.indent(Indent1) << "{\n"; + O.indent(Indent2) << "std::string cmd;\n"; + O.indent(Indent2) << "std::vector<std::string> vec;\n"; + O.indent(Indent2) << "bool stop_compilation = !HasChildren;\n"; + O.indent(Indent2) << "const char* output_suffix = \"" + << D.OutputSuffix << "\";\n"; - // cmd_line is either a string or a 'case' construct. if (!D.CmdLine) throw "Tool " + D.Name + " has no cmd_line property!"; - else if (typeid(*D.CmdLine) == typeid(StringInit)) + + bool IndexCheckRequired = IsOutFileIndexCheckRequired(D.CmdLine); + O.indent(Indent2) << "int out_file_index" + << (IndexCheckRequired ? " = -1" : "") + << ";\n\n"; + + // Process the cmd_line property. + if (typeid(*D.CmdLine) == typeid(StringInit)) EmitCmdLineVecFill(D.CmdLine, D.Name, IsJoin, Indent2, O); else EmitCaseConstructHandler(D.CmdLine, Indent2, EmitCmdLineVecFillCallback(IsJoin, D.Name), true, OptDescs, O); + // For every understood option, emit handling code. + if (D.Actions) + EmitCaseConstructHandler(D.Actions, Indent2, EmitActionHandler(OptDescs), + false, OptDescs, O); + + O << '\n'; + O.indent(Indent2) + << "std::string out_file = OutFilename(" + << (IsJoin ? "sys::Path(),\n" : "inFile,\n"); + O.indent(Indent3) << "TempDir, stop_compilation, output_suffix).str();\n\n"; + + if (IndexCheckRequired) + O.indent(Indent2) << "if (out_file_index != -1)\n"; + O.indent(IndexCheckRequired ? Indent3 : Indent2) + << "vec[out_file_index] = out_file;\n"; + // Handle the Sink property. if (D.isSink()) { - O << Indent2 << "if (!" << SinkOptionName << ".empty()) {\n" - << Indent3 << "vec.insert(vec.end(), " - << SinkOptionName << ".begin(), " << SinkOptionName << ".end());\n" - << Indent2 << "}\n"; + O.indent(Indent2) << "if (!" << SinkOptionName << ".empty()) {\n"; + O.indent(Indent3) << "vec.insert(vec.end(), " + << SinkOptionName << ".begin(), " << SinkOptionName + << ".end());\n"; + O.indent(Indent2) << "}\n"; } - O << Indent2 << "return Action(cmd, vec, stop_compilation, out_file);\n" - << Indent1 << "}\n\n"; + O.indent(Indent2) << "return Action(cmd, vec, stop_compilation, out_file);\n"; + O.indent(Indent1) << "}\n\n"; } /// EmitGenerateActionMethods - Emit two GenerateAction() methods for @@ -1560,18 +1684,20 @@ void EmitGenerateActionMethod (const ToolDescription& D, void EmitGenerateActionMethods (const ToolDescription& ToolDesc, const OptionDescriptions& OptDescs, raw_ostream& O) { - if (!ToolDesc.isJoin()) - O << Indent1 << "Action GenerateAction(const PathVector& inFiles,\n" - << Indent2 << "bool HasChildren,\n" - << Indent2 << "const llvm::sys::Path& TempDir,\n" - << Indent2 << "const InputLanguagesSet& InLangs,\n" - << Indent2 << "const LanguageMap& LangMap) const\n" - << Indent1 << "{\n" - << Indent2 << "throw std::runtime_error(\"" << ToolDesc.Name - << " is not a Join tool!\");\n" - << Indent1 << "}\n\n"; - else + if (!ToolDesc.isJoin()) { + O.indent(Indent1) << "Action GenerateAction(const PathVector& inFiles,\n"; + O.indent(Indent2) << "bool HasChildren,\n"; + O.indent(Indent2) << "const llvm::sys::Path& TempDir,\n"; + O.indent(Indent2) << "const InputLanguagesSet& InLangs,\n"; + O.indent(Indent2) << "const LanguageMap& LangMap) const\n"; + O.indent(Indent1) << "{\n"; + O.indent(Indent2) << "throw std::runtime_error(\"" << ToolDesc.Name + << " is not a Join tool!\");\n"; + O.indent(Indent1) << "}\n\n"; + } + else { EmitGenerateActionMethod(ToolDesc, OptDescs, true, O); + } EmitGenerateActionMethod(ToolDesc, OptDescs, false, O); } @@ -1579,34 +1705,34 @@ void EmitGenerateActionMethods (const ToolDescription& ToolDesc, /// EmitInOutLanguageMethods - Emit the [Input,Output]Language() /// methods for a given Tool class. void EmitInOutLanguageMethods (const ToolDescription& D, raw_ostream& O) { - O << Indent1 << "const char** InputLanguages() const {\n" - << Indent2 << "return InputLanguages_;\n" - << Indent1 << "}\n\n"; + O.indent(Indent1) << "const char** InputLanguages() const {\n"; + O.indent(Indent2) << "return InputLanguages_;\n"; + O.indent(Indent1) << "}\n\n"; if (D.OutLanguage.empty()) throw "Tool " + D.Name + " has no 'out_language' property!"; - O << Indent1 << "const char* OutputLanguage() const {\n" - << Indent2 << "return \"" << D.OutLanguage << "\";\n" - << Indent1 << "}\n\n"; + O.indent(Indent1) << "const char* OutputLanguage() const {\n"; + O.indent(Indent2) << "return \"" << D.OutLanguage << "\";\n"; + O.indent(Indent1) << "}\n\n"; } /// EmitNameMethod - Emit the Name() method for a given Tool class. void EmitNameMethod (const ToolDescription& D, raw_ostream& O) { - O << Indent1 << "const char* Name() const {\n" - << Indent2 << "return \"" << D.Name << "\";\n" - << Indent1 << "}\n\n"; + O.indent(Indent1) << "const char* Name() const {\n"; + O.indent(Indent2) << "return \"" << D.Name << "\";\n"; + O.indent(Indent1) << "}\n\n"; } /// EmitIsJoinMethod - Emit the IsJoin() method for a given Tool /// class. void EmitIsJoinMethod (const ToolDescription& D, raw_ostream& O) { - O << Indent1 << "bool IsJoin() const {\n"; + O.indent(Indent1) << "bool IsJoin() const {\n"; if (D.isJoin()) - O << Indent2 << "return true;\n"; + O.indent(Indent2) << "return true;\n"; else - O << Indent2 << "return false;\n"; - O << Indent1 << "}\n\n"; + O.indent(Indent2) << "return false;\n"; + O.indent(Indent1) << "}\n\n"; } /// EmitStaticMemberDefinitions - Emit static member definitions for a @@ -1636,8 +1762,8 @@ void EmitToolClassDefinition (const ToolDescription& D, else O << "Tool"; - O << "{\nprivate:\n" - << Indent1 << "static const char* InputLanguages_[];\n\n"; + O << "{\nprivate:\n"; + O.indent(Indent1) << "static const char* InputLanguages_[];\n\n"; O << "public:\n"; EmitNameMethod(D, O); @@ -1687,15 +1813,15 @@ void EmitOptionDefinitions (const OptionDescriptions& descs, O << ", cl::Prefix"; if (val.isRequired()) { - if (OptionType::IsList(val.Type) && !val.isMultiVal()) + if (val.isList() && !val.isMultiVal()) O << ", cl::OneOrMore"; else O << ", cl::Required"; } - else if (val.isOneOrMore() && OptionType::IsList(val.Type)) { + else if (val.isOneOrMore() && val.isList()) { O << ", cl::OneOrMore"; } - else if (val.isZeroOrOne() && OptionType::IsList(val.Type)) { + else if (val.isZeroOrOne() && val.isList()) { O << ", cl::ZeroOrOne"; } @@ -1707,7 +1833,12 @@ void EmitOptionDefinitions (const OptionDescriptions& descs, } if (val.MultiVal > 1) - O << ", cl::multi_val(" << val.MultiVal << ")"; + O << ", cl::multi_val(" << val.MultiVal << ')'; + + if (val.InitVal) { + const std::string& str = val.InitVal->getAsString(); + O << ", cl::init(" << str << ')'; + } if (!val.Help.empty()) O << ", cl::desc(\"" << val.Help << "\")"; @@ -1762,9 +1893,9 @@ void EmitPopulateLanguageMap (const RecordKeeper& Records, raw_ostream& O) const ListInit* Suffixes = LangToSuffixes->getValueAsListInit("suffixes"); for (unsigned i = 0; i < Suffixes->size(); ++i) - O << Indent1 << "langMap[\"" - << InitPtrToString(Suffixes->getElement(i)) - << "\"] = \"" << Lang << "\";\n"; + O.indent(Indent1) << "langMap[\"" + << InitPtrToString(Suffixes->getElement(i)) + << "\"] = \"" << Lang << "\";\n"; } } @@ -1773,21 +1904,22 @@ void EmitPopulateLanguageMap (const RecordKeeper& Records, raw_ostream& O) /// IncDecWeight - Helper function passed to EmitCaseConstructHandler() /// by EmitEdgeClass(). -void IncDecWeight (const Init* i, const char* IndentLevel, +void IncDecWeight (const Init* i, unsigned IndentLevel, raw_ostream& O) { const DagInit& d = InitPtrToDag(i); const std::string& OpName = d.getOperator()->getAsString(); if (OpName == "inc_weight") { - O << IndentLevel << "ret += "; + O.indent(IndentLevel) << "ret += "; } else if (OpName == "dec_weight") { - O << IndentLevel << "ret -= "; + O.indent(IndentLevel) << "ret -= "; } else if (OpName == "error") { - O << IndentLevel << "throw std::runtime_error(\"" << - (d.getNumArgs() >= 1 ? InitPtrToString(d.getArg(0)) - : "Unknown error!") + O.indent(IndentLevel) + << "throw std::runtime_error(\"" << + (d.getNumArgs() >= 1 ? InitPtrToString(d.getArg(0)) + : "Unknown error!") << "\");\n"; return; } @@ -1810,19 +1942,20 @@ void EmitEdgeClass (unsigned N, const std::string& Target, // Class constructor. O << "class Edge" << N << ": public Edge {\n" - << "public:\n" - << Indent1 << "Edge" << N << "() : Edge(\"" << Target - << "\") {}\n\n" + << "public:\n"; + O.indent(Indent1) << "Edge" << N << "() : Edge(\"" << Target + << "\") {}\n\n"; // Function Weight(). - << Indent1 << "unsigned Weight(const InputLanguagesSet& InLangs) const {\n" - << Indent2 << "unsigned ret = 0;\n"; + O.indent(Indent1) + << "unsigned Weight(const InputLanguagesSet& InLangs) const {\n"; + O.indent(Indent2) << "unsigned ret = 0;\n"; // Handle the 'case' construct. EmitCaseConstructHandler(Case, Indent2, IncDecWeight, false, OptDescs, O); - O << Indent2 << "return ret;\n" - << Indent1 << "};\n\n};\n\n"; + O.indent(Indent2) << "return ret;\n"; + O.indent(Indent1) << "};\n\n};\n\n"; } /// EmitEdgeClasses - Emit Edge* classes that represent graph edges. @@ -1852,7 +1985,7 @@ void EmitPopulateCompilationGraph (const RecordVector& EdgeVector, for (ToolDescriptions::const_iterator B = ToolDescs.begin(), E = ToolDescs.end(); B != E; ++B) - O << Indent1 << "G.insertNode(new " << (*B)->Name << "());\n"; + O.indent(Indent1) << "G.insertNode(new " << (*B)->Name << "());\n"; O << '\n'; @@ -1866,7 +1999,7 @@ void EmitPopulateCompilationGraph (const RecordVector& EdgeVector, const std::string& NodeB = Edge->getValueAsString("b"); DagInit* Weight = Edge->getValueAsDag("weight"); - O << Indent1 << "G.insertEdge(\"" << NodeA << "\", "; + O.indent(Indent1) << "G.insertEdge(\"" << NodeA << "\", "; if (isDagEmpty(Weight)) O << "new SimpleEdge(\"" << NodeB << "\")"; @@ -1955,7 +2088,7 @@ void EmitHookDeclarations(const ToolDescriptions& ToolDescs, raw_ostream& O) { O << "namespace hooks {\n"; for (StringMap<unsigned>::const_iterator B = HookNames.begin(), E = HookNames.end(); B != E; ++B) { - O << Indent1 << "std::string " << B->first() << "("; + O.indent(Indent1) << "std::string " << B->first() << "("; for (unsigned i = 0, j = B->second; i < j; ++i) { O << "const char* Arg" << i << (i+1 == j ? "" : ", "); @@ -1968,22 +2101,23 @@ void EmitHookDeclarations(const ToolDescriptions& ToolDescs, raw_ostream& O) { /// EmitRegisterPlugin - Emit code to register this plugin. void EmitRegisterPlugin(int Priority, raw_ostream& O) { - O << "struct Plugin : public llvmc::BasePlugin {\n\n" - << Indent1 << "int Priority() const { return " << Priority << "; }\n\n" - << Indent1 << "void PopulateLanguageMap(LanguageMap& langMap) const\n" - << Indent1 << "{ PopulateLanguageMapLocal(langMap); }\n\n" - << Indent1 - << "void PopulateCompilationGraph(CompilationGraph& graph) const\n" - << Indent1 << "{ PopulateCompilationGraphLocal(graph); }\n" - << "};\n\n" - - << "static llvmc::RegisterPlugin<Plugin> RP;\n\n"; + O << "struct Plugin : public llvmc::BasePlugin {\n\n"; + O.indent(Indent1) << "int Priority() const { return " + << Priority << "; }\n\n"; + O.indent(Indent1) << "void PopulateLanguageMap(LanguageMap& langMap) const\n"; + O.indent(Indent1) << "{ PopulateLanguageMapLocal(langMap); }\n\n"; + O.indent(Indent1) + << "void PopulateCompilationGraph(CompilationGraph& graph) const\n"; + O.indent(Indent1) << "{ PopulateCompilationGraphLocal(graph); }\n" + << "};\n\n" + << "static llvmc::RegisterPlugin<Plugin> RP;\n\n"; } /// EmitIncludes - Emit necessary #include directives and some /// additional declarations. void EmitIncludes(raw_ostream& O) { - O << "#include \"llvm/CompilerDriver/CompilationGraph.h\"\n" + O << "#include \"llvm/CompilerDriver/BuiltinOptions.h\"\n" + << "#include \"llvm/CompilerDriver/CompilationGraph.h\"\n" << "#include \"llvm/CompilerDriver/ForceLinkageMacros.h\"\n" << "#include \"llvm/CompilerDriver/Plugin.h\"\n" << "#include \"llvm/CompilerDriver/Tool.h\"\n\n" diff --git a/utils/TableGen/Record.cpp b/utils/TableGen/Record.cpp index 8f31624..a551166 100644 --- a/utils/TableGen/Record.cpp +++ b/utils/TableGen/Record.cpp @@ -1319,6 +1319,8 @@ void RecordVal::print(raw_ostream &OS, bool PrintSem) const { if (PrintSem) OS << ";\n"; } +unsigned Record::LastID = 0; + void Record::setName(const std::string &Name) { if (Records.getDef(getName()) == this) { Records.removeDef(getName()); @@ -1382,11 +1384,11 @@ raw_ostream &llvm::operator<<(raw_ostream &OS, const Record &R) { /// getValueInit - Return the initializer for a value with the specified name, /// or throw an exception if the field does not exist. /// -Init *Record::getValueInit(const std::string &FieldName) const { +Init *Record::getValueInit(StringRef FieldName) const { const RecordVal *R = getValue(FieldName); if (R == 0 || R->getValue() == 0) throw "Record `" + getName() + "' does not have a field named `" + - FieldName + "'!\n"; + FieldName.str() + "'!\n"; return R->getValue(); } @@ -1395,15 +1397,15 @@ Init *Record::getValueInit(const std::string &FieldName) const { /// value as a string, throwing an exception if the field does not exist or if /// the value is not a string. /// -std::string Record::getValueAsString(const std::string &FieldName) const { +std::string Record::getValueAsString(StringRef FieldName) const { const RecordVal *R = getValue(FieldName); if (R == 0 || R->getValue() == 0) throw "Record `" + getName() + "' does not have a field named `" + - FieldName + "'!\n"; + FieldName.str() + "'!\n"; if (const StringInit *SI = dynamic_cast<const StringInit*>(R->getValue())) return SI->getValue(); - throw "Record `" + getName() + "', field `" + FieldName + + throw "Record `" + getName() + "', field `" + FieldName.str() + "' does not have a string initializer!"; } @@ -1411,15 +1413,15 @@ std::string Record::getValueAsString(const std::string &FieldName) const { /// its value as a BitsInit, throwing an exception if the field does not exist /// or if the value is not the right type. /// -BitsInit *Record::getValueAsBitsInit(const std::string &FieldName) const { +BitsInit *Record::getValueAsBitsInit(StringRef FieldName) const { const RecordVal *R = getValue(FieldName); if (R == 0 || R->getValue() == 0) throw "Record `" + getName() + "' does not have a field named `" + - FieldName + "'!\n"; + FieldName.str() + "'!\n"; if (BitsInit *BI = dynamic_cast<BitsInit*>(R->getValue())) return BI; - throw "Record `" + getName() + "', field `" + FieldName + + throw "Record `" + getName() + "', field `" + FieldName.str() + "' does not have a BitsInit initializer!"; } @@ -1427,15 +1429,15 @@ BitsInit *Record::getValueAsBitsInit(const std::string &FieldName) const { /// its value as a ListInit, throwing an exception if the field does not exist /// or if the value is not the right type. /// -ListInit *Record::getValueAsListInit(const std::string &FieldName) const { +ListInit *Record::getValueAsListInit(StringRef FieldName) const { const RecordVal *R = getValue(FieldName); if (R == 0 || R->getValue() == 0) throw "Record `" + getName() + "' does not have a field named `" + - FieldName + "'!\n"; + FieldName.str() + "'!\n"; if (ListInit *LI = dynamic_cast<ListInit*>(R->getValue())) return LI; - throw "Record `" + getName() + "', field `" + FieldName + + throw "Record `" + getName() + "', field `" + FieldName.str() + "' does not have a list initializer!"; } @@ -1444,14 +1446,14 @@ ListInit *Record::getValueAsListInit(const std::string &FieldName) const { /// not exist or if the value is not the right type. /// std::vector<Record*> -Record::getValueAsListOfDefs(const std::string &FieldName) const { +Record::getValueAsListOfDefs(StringRef FieldName) const { ListInit *List = getValueAsListInit(FieldName); std::vector<Record*> Defs; for (unsigned i = 0; i < List->getSize(); i++) { if (DefInit *DI = dynamic_cast<DefInit*>(List->getElement(i))) { Defs.push_back(DI->getDef()); } else { - throw "Record `" + getName() + "', field `" + FieldName + + throw "Record `" + getName() + "', field `" + FieldName.str() + "' list is not entirely DefInit!"; } } @@ -1462,15 +1464,15 @@ Record::getValueAsListOfDefs(const std::string &FieldName) const { /// value as an int64_t, throwing an exception if the field does not exist or if /// the value is not the right type. /// -int64_t Record::getValueAsInt(const std::string &FieldName) const { +int64_t Record::getValueAsInt(StringRef FieldName) const { const RecordVal *R = getValue(FieldName); if (R == 0 || R->getValue() == 0) throw "Record `" + getName() + "' does not have a field named `" + - FieldName + "'!\n"; + FieldName.str() + "'!\n"; if (IntInit *II = dynamic_cast<IntInit*>(R->getValue())) return II->getValue(); - throw "Record `" + getName() + "', field `" + FieldName + + throw "Record `" + getName() + "', field `" + FieldName.str() + "' does not have an int initializer!"; } @@ -1479,14 +1481,14 @@ int64_t Record::getValueAsInt(const std::string &FieldName) const { /// not exist or if the value is not the right type. /// std::vector<int64_t> -Record::getValueAsListOfInts(const std::string &FieldName) const { +Record::getValueAsListOfInts(StringRef FieldName) const { ListInit *List = getValueAsListInit(FieldName); std::vector<int64_t> Ints; for (unsigned i = 0; i < List->getSize(); i++) { if (IntInit *II = dynamic_cast<IntInit*>(List->getElement(i))) { Ints.push_back(II->getValue()); } else { - throw "Record `" + getName() + "', field `" + FieldName + + throw "Record `" + getName() + "', field `" + FieldName.str() + "' does not have a list of ints initializer!"; } } @@ -1497,15 +1499,15 @@ Record::getValueAsListOfInts(const std::string &FieldName) const { /// value as a Record, throwing an exception if the field does not exist or if /// the value is not the right type. /// -Record *Record::getValueAsDef(const std::string &FieldName) const { +Record *Record::getValueAsDef(StringRef FieldName) const { const RecordVal *R = getValue(FieldName); if (R == 0 || R->getValue() == 0) throw "Record `" + getName() + "' does not have a field named `" + - FieldName + "'!\n"; + FieldName.str() + "'!\n"; if (DefInit *DI = dynamic_cast<DefInit*>(R->getValue())) return DI->getDef(); - throw "Record `" + getName() + "', field `" + FieldName + + throw "Record `" + getName() + "', field `" + FieldName.str() + "' does not have a def initializer!"; } @@ -1513,15 +1515,15 @@ Record *Record::getValueAsDef(const std::string &FieldName) const { /// value as a bit, throwing an exception if the field does not exist or if /// the value is not the right type. /// -bool Record::getValueAsBit(const std::string &FieldName) const { +bool Record::getValueAsBit(StringRef FieldName) const { const RecordVal *R = getValue(FieldName); if (R == 0 || R->getValue() == 0) throw "Record `" + getName() + "' does not have a field named `" + - FieldName + "'!\n"; + FieldName.str() + "'!\n"; if (BitInit *BI = dynamic_cast<BitInit*>(R->getValue())) return BI->getValue(); - throw "Record `" + getName() + "', field `" + FieldName + + throw "Record `" + getName() + "', field `" + FieldName.str() + "' does not have a bit initializer!"; } @@ -1529,27 +1531,27 @@ bool Record::getValueAsBit(const std::string &FieldName) const { /// value as an Dag, throwing an exception if the field does not exist or if /// the value is not the right type. /// -DagInit *Record::getValueAsDag(const std::string &FieldName) const { +DagInit *Record::getValueAsDag(StringRef FieldName) const { const RecordVal *R = getValue(FieldName); if (R == 0 || R->getValue() == 0) throw "Record `" + getName() + "' does not have a field named `" + - FieldName + "'!\n"; + FieldName.str() + "'!\n"; if (DagInit *DI = dynamic_cast<DagInit*>(R->getValue())) return DI; - throw "Record `" + getName() + "', field `" + FieldName + + throw "Record `" + getName() + "', field `" + FieldName.str() + "' does not have a dag initializer!"; } -std::string Record::getValueAsCode(const std::string &FieldName) const { +std::string Record::getValueAsCode(StringRef FieldName) const { const RecordVal *R = getValue(FieldName); if (R == 0 || R->getValue() == 0) throw "Record `" + getName() + "' does not have a field named `" + - FieldName + "'!\n"; + FieldName.str() + "'!\n"; if (const CodeInit *CI = dynamic_cast<const CodeInit*>(R->getValue())) return CI->getValue(); - throw "Record `" + getName() + "', field `" + FieldName + + throw "Record `" + getName() + "', field `" + FieldName.str() + "' does not have a code initializer!"; } diff --git a/utils/TableGen/Record.h b/utils/TableGen/Record.h index 11db910..1b33743 100644 --- a/utils/TableGen/Record.h +++ b/utils/TableGen/Record.h @@ -782,7 +782,7 @@ public: // Clone - Clone this operator, replacing arguments with the new list virtual OpInit *clone(std::vector<Init *> &Operands) = 0; - virtual int getNumOperands(void) const = 0; + virtual int getNumOperands() const = 0; virtual Init *getOperand(int i) = 0; // Fold - If possible, fold this to a simpler init. Return this if not @@ -820,7 +820,7 @@ public: return new UnOpInit(getOpcode(), *Operands.begin(), getType()); } - int getNumOperands(void) const { return 1; } + int getNumOperands() const { return 1; } Init *getOperand(int i) { assert(i == 0 && "Invalid operand id for unary operator"); return getOperand(); @@ -864,7 +864,7 @@ public: return new BinOpInit(getOpcode(), Operands[0], Operands[1], getType()); } - int getNumOperands(void) const { return 2; } + int getNumOperands() const { return 2; } Init *getOperand(int i) { assert((i == 0 || i == 1) && "Invalid operand id for binary operator"); if (i == 0) { @@ -909,7 +909,7 @@ public: getType()); } - int getNumOperands(void) const { return 3; } + int getNumOperands() const { return 3; } Init *getOperand(int i) { assert((i == 0 || i == 1 || i == 2) && "Invalid operand id for ternary operator"); @@ -1220,6 +1220,10 @@ inline raw_ostream &operator<<(raw_ostream &OS, const RecordVal &RV) { } class Record { + static unsigned LastID; + + // Unique record ID. + unsigned ID; std::string Name; SMLoc Loc; std::vector<std::string> TemplateArgs; @@ -1227,9 +1231,12 @@ class Record { std::vector<Record*> SuperClasses; public: - explicit Record(const std::string &N, SMLoc loc) : Name(N), Loc(loc) {} + explicit Record(const std::string &N, SMLoc loc) : + ID(LastID++), Name(N), Loc(loc) {} ~Record() {} + unsigned getID() const { return ID; } + const std::string &getName() const { return Name; } void setName(const std::string &Name); // Also updates RecordKeeper. @@ -1241,24 +1248,24 @@ public: const std::vector<RecordVal> &getValues() const { return Values; } const std::vector<Record*> &getSuperClasses() const { return SuperClasses; } - bool isTemplateArg(const std::string &Name) const { + bool isTemplateArg(StringRef Name) const { for (unsigned i = 0, e = TemplateArgs.size(); i != e; ++i) if (TemplateArgs[i] == Name) return true; return false; } - const RecordVal *getValue(const std::string &Name) const { + const RecordVal *getValue(StringRef Name) const { for (unsigned i = 0, e = Values.size(); i != e; ++i) if (Values[i].getName() == Name) return &Values[i]; return 0; } - RecordVal *getValue(const std::string &Name) { + RecordVal *getValue(StringRef Name) { for (unsigned i = 0, e = Values.size(); i != e; ++i) if (Values[i].getName() == Name) return &Values[i]; return 0; } - void addTemplateArg(const std::string &Name) { + void addTemplateArg(StringRef Name) { assert(!isTemplateArg(Name) && "Template arg already defined!"); TemplateArgs.push_back(Name); } @@ -1268,7 +1275,7 @@ public: Values.push_back(RV); } - void removeValue(const std::string &Name) { + void removeValue(StringRef Name) { assert(getValue(Name) && "Cannot remove an entry that does not exist!"); for (unsigned i = 0, e = Values.size(); i != e; ++i) if (Values[i].getName() == Name) { @@ -1285,7 +1292,7 @@ public: return false; } - bool isSubClassOf(const std::string &Name) const { + bool isSubClassOf(StringRef Name) const { for (unsigned i = 0, e = SuperClasses.size(); i != e; ++i) if (SuperClasses[i]->getName() == Name) return true; @@ -1316,67 +1323,67 @@ public: /// getValueInit - Return the initializer for a value with the specified name, /// or throw an exception if the field does not exist. /// - Init *getValueInit(const std::string &FieldName) const; + Init *getValueInit(StringRef FieldName) const; /// getValueAsString - This method looks up the specified field and returns /// its value as a string, throwing an exception if the field does not exist /// or if the value is not a string. /// - std::string getValueAsString(const std::string &FieldName) const; + std::string getValueAsString(StringRef FieldName) const; /// getValueAsBitsInit - This method looks up the specified field and returns /// its value as a BitsInit, throwing an exception if the field does not exist /// or if the value is not the right type. /// - BitsInit *getValueAsBitsInit(const std::string &FieldName) const; + BitsInit *getValueAsBitsInit(StringRef FieldName) const; /// getValueAsListInit - This method looks up the specified field and returns /// its value as a ListInit, throwing an exception if the field does not exist /// or if the value is not the right type. /// - ListInit *getValueAsListInit(const std::string &FieldName) const; + ListInit *getValueAsListInit(StringRef FieldName) const; /// getValueAsListOfDefs - This method looks up the specified field and /// returns its value as a vector of records, throwing an exception if the /// field does not exist or if the value is not the right type. /// - std::vector<Record*> getValueAsListOfDefs(const std::string &FieldName) const; + std::vector<Record*> getValueAsListOfDefs(StringRef FieldName) const; /// getValueAsListOfInts - This method looks up the specified field and returns /// its value as a vector of integers, throwing an exception if the field does /// not exist or if the value is not the right type. /// - std::vector<int64_t> getValueAsListOfInts(const std::string &FieldName) const; + std::vector<int64_t> getValueAsListOfInts(StringRef FieldName) const; /// getValueAsDef - This method looks up the specified field and returns its /// value as a Record, throwing an exception if the field does not exist or if /// the value is not the right type. /// - Record *getValueAsDef(const std::string &FieldName) const; + Record *getValueAsDef(StringRef FieldName) const; /// getValueAsBit - This method looks up the specified field and returns its /// value as a bit, throwing an exception if the field does not exist or if /// the value is not the right type. /// - bool getValueAsBit(const std::string &FieldName) const; + bool getValueAsBit(StringRef FieldName) const; /// getValueAsInt - This method looks up the specified field and returns its /// value as an int64_t, throwing an exception if the field does not exist or /// if the value is not the right type. /// - int64_t getValueAsInt(const std::string &FieldName) const; + int64_t getValueAsInt(StringRef FieldName) const; /// getValueAsDag - This method looks up the specified field and returns its /// value as an Dag, throwing an exception if the field does not exist or if /// the value is not the right type. /// - DagInit *getValueAsDag(const std::string &FieldName) const; + DagInit *getValueAsDag(StringRef FieldName) const; /// getValueAsCode - This method looks up the specified field and returns /// its value as the string data in a CodeInit, throwing an exception if the /// field does not exist or if the value is not a code object. /// - std::string getValueAsCode(const std::string &FieldName) const; + std::string getValueAsCode(StringRef FieldName) const; }; raw_ostream &operator<<(raw_ostream &OS, const Record &R); diff --git a/utils/TableGen/RegisterInfoEmitter.cpp b/utils/TableGen/RegisterInfoEmitter.cpp index 3297e93..3c7b44a 100644 --- a/utils/TableGen/RegisterInfoEmitter.cpp +++ b/utils/TableGen/RegisterInfoEmitter.cpp @@ -222,7 +222,7 @@ void RegisterInfoEmitter::run(raw_ostream &OS) { // Emit the register list now. OS << " // " << Name << " Register Class Value Types...\n" - << " static const MVT " << Name + << " static const EVT " << Name << "[] = {\n "; for (unsigned i = 0, e = RC.VTs.size(); i != e; ++i) OS << getEnumName(RC.VTs[i]) << ", "; @@ -252,7 +252,7 @@ void RegisterInfoEmitter::run(raw_ostream &OS) { OS << " // " << Name << " Sub-register Classes...\n" << " static const TargetRegisterClass* const " - << Name << "SubRegClasses [] = {\n "; + << Name << "SubRegClasses[] = {\n "; bool Empty = true; @@ -298,7 +298,7 @@ void RegisterInfoEmitter::run(raw_ostream &OS) { OS << " // " << Name << " Super-register Classes...\n" << " static const TargetRegisterClass* const " - << Name << "SuperRegClasses [] = {\n "; + << Name << "SuperRegClasses[] = {\n "; bool Empty = true; std::map<unsigned, std::set<unsigned> >::iterator I = @@ -334,7 +334,7 @@ void RegisterInfoEmitter::run(raw_ostream &OS) { OS << " // " << Name << " Register Class sub-classes...\n" << " static const TargetRegisterClass* const " - << Name << "Subclasses [] = {\n "; + << Name << "Subclasses[] = {\n "; bool Empty = true; for (unsigned rc2 = 0, e2 = RegisterClasses.size(); rc2 != e2; ++rc2) { @@ -382,7 +382,7 @@ void RegisterInfoEmitter::run(raw_ostream &OS) { OS << " // " << Name << " Register Class super-classes...\n" << " static const TargetRegisterClass* const " - << Name << "Superclasses [] = {\n "; + << Name << "Superclasses[] = {\n "; bool Empty = true; std::map<unsigned, std::set<unsigned> >::iterator I = @@ -767,7 +767,7 @@ void RegisterInfoEmitter::run(raw_ostream &OS) { } OS<<"\n const TargetRegisterDesc RegisterDescriptors[] = { // Descriptors\n"; - OS << " { \"NOREG\",\t\"NOREG\",\t0,\t0,\t0 },\n"; + OS << " { \"NOREG\",\t0,\t0,\t0 },\n"; // Now that register alias and sub-registers sets have been emitted, emit the // register descriptors now. @@ -775,11 +775,6 @@ void RegisterInfoEmitter::run(raw_ostream &OS) { for (unsigned i = 0, e = Registers.size(); i != e; ++i) { const CodeGenRegister &Reg = Registers[i]; OS << " { \""; - if (!Reg.TheDef->getValueAsString("AsmName").empty()) - OS << Reg.TheDef->getValueAsString("AsmName"); - else - OS << Reg.getName(); - OS << "\",\t\""; OS << Reg.getName() << "\",\t"; if (RegisterAliases.count(Reg.TheDef)) OS << Reg.getName() << "_AliasSet,\t"; diff --git a/utils/TableGen/StringToOffsetTable.h b/utils/TableGen/StringToOffsetTable.h new file mode 100644 index 0000000..d9d7cf4 --- /dev/null +++ b/utils/TableGen/StringToOffsetTable.h @@ -0,0 +1,76 @@ +//===- StringToOffsetTable.h - Emit a big concatenated string ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef TBLGEN_STRING_TO_OFFSET_TABLE_H +#define TBLGEN_STRING_TO_OFFSET_TABLE_H + +#include "llvm/ADT/StringMap.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/ADT/StringExtras.h" + +namespace llvm { + +/// StringToOffsetTable - This class uniques a bunch of nul-terminated strings +/// and keeps track of their offset in a massive contiguous string allocation. +/// It can then output this string blob and use indexes into the string to +/// reference each piece. +class StringToOffsetTable { + StringMap<unsigned> StringOffset; + std::string AggregateString; +public: + + unsigned GetOrAddStringOffset(StringRef Str) { + unsigned &Entry = StringOffset[Str]; + if (Entry == 0) { + // Add the string to the aggregate if this is the first time found. + Entry = AggregateString.size(); + AggregateString.append(Str.begin(), Str.end()); + AggregateString += '\0'; + } + + return Entry; + } + + void EmitString(raw_ostream &O) { + O << " \""; + unsigned CharsPrinted = 0; + EscapeString(AggregateString); + for (unsigned i = 0, e = AggregateString.size(); i != e; ++i) { + if (CharsPrinted > 70) { + O << "\"\n \""; + CharsPrinted = 0; + } + O << AggregateString[i]; + ++CharsPrinted; + + // Print escape sequences all together. + if (AggregateString[i] != '\\') + continue; + + assert(i+1 < AggregateString.size() && "Incomplete escape sequence!"); + if (isdigit(AggregateString[i+1])) { + assert(isdigit(AggregateString[i+2]) && + isdigit(AggregateString[i+3]) && + "Expected 3 digit octal escape!"); + O << AggregateString[++i]; + O << AggregateString[++i]; + O << AggregateString[++i]; + CharsPrinted += 3; + } else { + O << AggregateString[++i]; + ++CharsPrinted; + } + } + O << "\""; + } +}; + +} // end namespace llvm + +#endif diff --git a/utils/TableGen/SubtargetEmitter.cpp b/utils/TableGen/SubtargetEmitter.cpp index 919ac66..c8cf234 100644 --- a/utils/TableGen/SubtargetEmitter.cpp +++ b/utils/TableGen/SubtargetEmitter.cpp @@ -199,12 +199,13 @@ unsigned SubtargetEmitter::CollectAllItinClasses(raw_ostream &OS, } // -// FormItineraryString - Compose a string containing the data initialization -// for the specified itinerary. N is the number of stages. +// FormItineraryStageString - Compose a string containing the stage +// data initialization for the specified itinerary. N is the number +// of stages. // -void SubtargetEmitter::FormItineraryString(Record *ItinData, - std::string &ItinString, - unsigned &NStages) { +void SubtargetEmitter::FormItineraryStageString(Record *ItinData, + std::string &ItinString, + unsigned &NStages) { // Get states list const std::vector<Record*> &StageList = ItinData->getValueAsListOfDefs("Stages"); @@ -215,7 +216,7 @@ void SubtargetEmitter::FormItineraryString(Record *ItinData, // Next stage const Record *Stage = StageList[i]; - // Form string as ,{ cycles, u1 | u2 | ... | un } + // Form string as ,{ cycles, u1 | u2 | ... | un, timeinc } int Cycles = Stage->getValueAsInt("Cycles"); ItinString += " { " + itostr(Cycles) + ", "; @@ -229,6 +230,9 @@ void SubtargetEmitter::FormItineraryString(Record *ItinData, if (++j < M) ItinString += " | "; } + int TimeInc = Stage->getValueAsInt("TimeInc"); + ItinString += ", " + itostr(TimeInc); + // Close off stage ItinString += " }"; if (++i < N) ItinString += ", "; @@ -236,10 +240,32 @@ void SubtargetEmitter::FormItineraryString(Record *ItinData, } // -// EmitStageData - Generate unique itinerary stages. Record itineraries for -// processors. +// FormItineraryOperandCycleString - Compose a string containing the +// operand cycle initialization for the specified itinerary. N is the +// number of operands that has cycles specified. +// +void SubtargetEmitter::FormItineraryOperandCycleString(Record *ItinData, + std::string &ItinString, unsigned &NOperandCycles) { + // Get operand cycle list + const std::vector<int64_t> &OperandCycleList = + ItinData->getValueAsListOfInts("OperandCycles"); + + // For each operand cycle + unsigned N = NOperandCycles = OperandCycleList.size(); + for (unsigned i = 0; i < N;) { + // Next operand cycle + const int OCycle = OperandCycleList[i]; + + ItinString += " " + itostr(OCycle); + if (++i < N) ItinString += ", "; + } +} + +// +// EmitStageAndOperandCycleData - Generate unique itinerary stages and +// operand cycle tables. Record itineraries for processors. // -void SubtargetEmitter::EmitStageData(raw_ostream &OS, +void SubtargetEmitter::EmitStageAndOperandCycleData(raw_ostream &OS, unsigned NItinClasses, std::map<std::string, unsigned> &ItinClassesMap, std::vector<std::vector<InstrItinerary> > &ProcList) { @@ -251,12 +277,16 @@ void SubtargetEmitter::EmitStageData(raw_ostream &OS, if (ProcItinList.size() < 2) return; // Begin stages table - OS << "static const llvm::InstrStage Stages[] = {\n" - " { 0, 0 }, // No itinerary\n"; + std::string StageTable = "static const llvm::InstrStage Stages[] = {\n"; + StageTable += " { 0, 0, 0 }, // No itinerary\n"; - unsigned StageCount = 1; - unsigned ItinEnum = 1; - std::map<std::string, unsigned> ItinMap; + // Begin operand cycle table + std::string OperandCycleTable = "static const unsigned OperandCycles[] = {\n"; + OperandCycleTable += " 0, // No itinerary\n"; + + unsigned StageCount = 1, OperandCycleCount = 1; + unsigned ItinStageEnum = 1, ItinOperandCycleEnum = 1; + std::map<std::string, unsigned> ItinStageMap, ItinOperandCycleMap; for (unsigned i = 0, N = ProcItinList.size(); i < N; i++) { // Next record Record *Proc = ProcItinList[i]; @@ -280,29 +310,53 @@ void SubtargetEmitter::EmitStageData(raw_ostream &OS, Record *ItinData = ItinDataList[j]; // Get string and stage count - std::string ItinString; + std::string ItinStageString; unsigned NStages; - FormItineraryString(ItinData, ItinString, NStages); - - // Check to see if it already exists - unsigned Find = ItinMap[ItinString]; + FormItineraryStageString(ItinData, ItinStageString, NStages); + + // Get string and operand cycle count + std::string ItinOperandCycleString; + unsigned NOperandCycles; + FormItineraryOperandCycleString(ItinData, ItinOperandCycleString, + NOperandCycles); + + // Check to see if stage already exists and create if it doesn't + unsigned FindStage = 0; + if (NStages > 0) { + FindStage = ItinStageMap[ItinStageString]; + if (FindStage == 0) { + // Emit as { cycles, u1 | u2 | ... | un, timeinc }, // index + StageTable += ItinStageString + ", // " + itostr(ItinStageEnum) + "\n"; + // Record Itin class number. + ItinStageMap[ItinStageString] = FindStage = StageCount; + StageCount += NStages; + ItinStageEnum++; + } + } - // If new itinerary - if (Find == 0) { - // Emit as { cycles, u1 | u2 | ... | un }, // index - OS << ItinString << ", // " << ItinEnum << "\n"; - // Record Itin class number. - ItinMap[ItinString] = Find = StageCount; - StageCount += NStages; - ItinEnum++; + // Check to see if operand cycle already exists and create if it doesn't + unsigned FindOperandCycle = 0; + if (NOperandCycles > 0) { + FindOperandCycle = ItinOperandCycleMap[ItinOperandCycleString]; + if (FindOperandCycle == 0) { + // Emit as cycle, // index + OperandCycleTable += ItinOperandCycleString + ", // " + + itostr(ItinOperandCycleEnum) + "\n"; + // Record Itin class number. + ItinOperandCycleMap[ItinOperandCycleString] = + FindOperandCycle = OperandCycleCount; + OperandCycleCount += NOperandCycles; + ItinOperandCycleEnum++; + } } // Set up itinerary as location and location + stage count - InstrItinerary Intinerary = { Find, Find + NStages }; + InstrItinerary Intinerary = { FindStage, FindStage + NStages, + FindOperandCycle, FindOperandCycle + NOperandCycles}; // Locate where to inject into processor itinerary table const std::string &Name = ItinData->getValueAsDef("TheClass")->getName(); - Find = ItinClassesMap[Name]; + unsigned Find = ItinClassesMap[Name]; // Inject - empty slots will be 0, 0 ItinList[Find] = Intinerary; @@ -313,13 +367,21 @@ void SubtargetEmitter::EmitStageData(raw_ostream &OS, } // Closing stage - OS << " { 0, 0 } // End itinerary\n"; - // End stages table - OS << "};\n"; + StageTable += " { 0, 0, 0 } // End itinerary\n"; + StageTable += "};\n"; + + // Closing operand cycles + OperandCycleTable += " 0 // End itinerary\n"; + OperandCycleTable += "};\n"; + + // Emit tables. + OS << StageTable; + OS << OperandCycleTable; - // Emit size of table + // Emit size of tables OS<<"\nenum {\n"; - OS<<" StagesSize = sizeof(Stages)/sizeof(llvm::InstrStage)\n"; + OS<<" StagesSize = sizeof(Stages)/sizeof(llvm::InstrStage),\n"; + OS<<" OperandCyclesSize = sizeof(OperandCycles)/sizeof(unsigned)\n"; OS<<"};\n"; } @@ -351,23 +413,25 @@ void SubtargetEmitter::EmitProcessorData(raw_ostream &OS, // For each itinerary class std::vector<InstrItinerary> &ItinList = *ProcListIter++; - for (unsigned j = 0, M = ItinList.size(); j < M;) { + for (unsigned j = 0, M = ItinList.size(); j < M; ++j) { InstrItinerary &Intinerary = ItinList[j]; - // Emit in the form of { first, last } // index - if (Intinerary.First == 0) { - OS << " { 0, 0 }"; + // Emit in the form of + // { firstStage, lastStage, firstCycle, lastCycle } // index + if (Intinerary.FirstStage == 0) { + OS << " { 0, 0, 0, 0 }"; } else { - OS << " { " << Intinerary.First << ", " << Intinerary.Last << " }"; + OS << " { " << Intinerary.FirstStage << ", " << + Intinerary.LastStage << ", " << + Intinerary.FirstOperandCycle << ", " << + Intinerary.LastOperandCycle << " }"; } - // If more in list add comma - if (++j < M) OS << ","; - - OS << " // " << (j - 1) << "\n"; + OS << ", // " << j << "\n"; } // End processor itinerary table + OS << " { ~0U, ~0U, ~0U, ~0U } // end marker\n"; OS << "};\n"; } } @@ -432,7 +496,7 @@ void SubtargetEmitter::EmitData(raw_ostream &OS) { if (HasItineraries) { // Emit the stage data - EmitStageData(OS, NItinClasses, ItinClassesMap, ProcList); + EmitStageAndOperandCycleData(OS, NItinClasses, ItinClassesMap, ProcList); // Emit the processor itinerary data EmitProcessorData(OS, ProcList); // Emit the processor lookup data @@ -479,7 +543,7 @@ void SubtargetEmitter::ParseFeaturesFunction(raw_ostream &OS) { OS << "\n" << " InstrItinerary *Itinerary = (InstrItinerary *)" << "Features.getInfo(ProcItinKV, ProcItinKVSize);\n" - << " InstrItins = InstrItineraryData(Stages, Itinerary);\n"; + << " InstrItins = InstrItineraryData(Stages, OperandCycles, Itinerary);\n"; } OS << " return Features.getCPU();\n" diff --git a/utils/TableGen/SubtargetEmitter.h b/utils/TableGen/SubtargetEmitter.h index f44278c..1d7088f 100644 --- a/utils/TableGen/SubtargetEmitter.h +++ b/utils/TableGen/SubtargetEmitter.h @@ -34,9 +34,11 @@ class SubtargetEmitter : public TableGenBackend { void CPUKeyValues(raw_ostream &OS); unsigned CollectAllItinClasses(raw_ostream &OS, std::map<std::string, unsigned> &ItinClassesMap); - void FormItineraryString(Record *ItinData, std::string &ItinString, - unsigned &NStages); - void EmitStageData(raw_ostream &OS, unsigned NItinClasses, + void FormItineraryStageString(Record *ItinData, std::string &ItinString, + unsigned &NStages); + void FormItineraryOperandCycleString(Record *ItinData, std::string &ItinString, + unsigned &NOperandCycles); + void EmitStageAndOperandCycleData(raw_ostream &OS, unsigned NItinClasses, std::map<std::string, unsigned> &ItinClassesMap, std::vector<std::vector<InstrItinerary> > &ProcList); void EmitProcessorData(raw_ostream &OS, diff --git a/utils/TableGen/TGParser.cpp b/utils/TableGen/TGParser.cpp index ba480e6..7122265 100644 --- a/utils/TableGen/TGParser.cpp +++ b/utils/TableGen/TGParser.cpp @@ -974,7 +974,7 @@ Init *TGParser::ParseOperation(Record *CurRec) { /// /// OperatorType ::= '<' Type '>' /// -RecTy *TGParser::ParseOperatorType(void) { +RecTy *TGParser::ParseOperatorType() { RecTy *Type = 0; if (Lex.getCode() != tgtok::less) { diff --git a/utils/TableGen/TGValueTypes.cpp b/utils/TableGen/TGValueTypes.cpp index e4edca6..122d085 100644 --- a/utils/TableGen/TGValueTypes.cpp +++ b/utils/TableGen/TGValueTypes.cpp @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// // -// The MVT type is used by tablegen as well as in LLVM. In order to handle -// extended types, the MVT type uses support functions that call into +// The EVT type is used by tablegen as well as in LLVM. In order to handle +// extended types, the EVT type uses support functions that call into // LLVM's type system code. These aren't accessible in tablegen, so this // file provides simple replacements. // @@ -43,15 +43,15 @@ public: }; class ExtendedVectorType : public Type { - MVT ElementType; + EVT ElementType; unsigned NumElements; public: - ExtendedVectorType(MVT elty, unsigned num) + ExtendedVectorType(EVT elty, unsigned num) : ElementType(elty), NumElements(num) {} unsigned getSizeInBits() const { return getNumElements() * getElementType().getSizeInBits(); } - MVT getElementType() const { + EVT getElementType() const { return ElementType; } unsigned getNumElements() const { @@ -64,62 +64,43 @@ static std::map<unsigned, const Type *> static std::map<std::pair<uintptr_t, uintptr_t>, const Type *> ExtendedVectorTypeMap; -MVT MVT::getExtendedIntegerVT(unsigned BitWidth) { - const Type *&ET = ExtendedIntegerTypeMap[BitWidth]; - if (!ET) ET = new ExtendedIntegerType(BitWidth); - MVT VT; - VT.LLVMTy = ET; - assert(VT.isExtended() && "Type is not extended!"); - return VT; -} - -MVT MVT::getExtendedVectorVT(MVT VT, unsigned NumElements) { - const Type *&ET = ExtendedVectorTypeMap[std::make_pair(VT.getRawBits(), - NumElements)]; - if (!ET) ET = new ExtendedVectorType(VT, NumElements); - MVT ResultVT; - ResultVT.LLVMTy = ET; - assert(ResultVT.isExtended() && "Type is not extended!"); - return ResultVT; -} - -bool MVT::isExtendedFloatingPoint() const { +bool EVT::isExtendedFloatingPoint() const { assert(isExtended() && "Type is not extended!"); // Extended floating-point types are not supported yet. return false; } -bool MVT::isExtendedInteger() const { +bool EVT::isExtendedInteger() const { assert(isExtended() && "Type is not extended!"); return dynamic_cast<const ExtendedIntegerType *>(LLVMTy) != 0; } -bool MVT::isExtendedVector() const { +bool EVT::isExtendedVector() const { assert(isExtended() && "Type is not extended!"); return dynamic_cast<const ExtendedVectorType *>(LLVMTy) != 0; } -bool MVT::isExtended64BitVector() const { +bool EVT::isExtended64BitVector() const { assert(isExtended() && "Type is not extended!"); return isExtendedVector() && getSizeInBits() == 64; } -bool MVT::isExtended128BitVector() const { +bool EVT::isExtended128BitVector() const { assert(isExtended() && "Type is not extended!"); return isExtendedVector() && getSizeInBits() == 128; } -MVT MVT::getExtendedVectorElementType() const { +EVT EVT::getExtendedVectorElementType() const { assert(isExtendedVector() && "Type is not an extended vector!"); return static_cast<const ExtendedVectorType *>(LLVMTy)->getElementType(); } -unsigned MVT::getExtendedVectorNumElements() const { +unsigned EVT::getExtendedVectorNumElements() const { assert(isExtendedVector() && "Type is not an extended vector!"); return static_cast<const ExtendedVectorType *>(LLVMTy)->getNumElements(); } -unsigned MVT::getExtendedSizeInBits() const { +unsigned EVT::getExtendedSizeInBits() const { assert(isExtended() && "Type is not extended!"); return LLVMTy->getSizeInBits(); } diff --git a/utils/TableGen/TableGen.cpp b/utils/TableGen/TableGen.cpp index 6015814..c6d7502 100644 --- a/utils/TableGen/TableGen.cpp +++ b/utils/TableGen/TableGen.cpp @@ -17,24 +17,25 @@ #include "Record.h" #include "TGParser.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/System/Signals.h" -#include "llvm/Support/FileUtilities.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/raw_ostream.h" #include "CallingConvEmitter.h" #include "CodeEmitterGen.h" #include "RegisterInfoEmitter.h" #include "InstrInfoEmitter.h" #include "InstrEnumEmitter.h" #include "AsmWriterEmitter.h" +#include "AsmMatcherEmitter.h" #include "DAGISelEmitter.h" #include "FastISelEmitter.h" #include "SubtargetEmitter.h" #include "IntrinsicEmitter.h" #include "LLVMCConfigurationEmitter.h" #include "ClangDiagnosticsEmitter.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/FileUtilities.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/System/Signals.h" #include <algorithm> #include <cstdio> using namespace llvm; @@ -43,7 +44,7 @@ enum ActionType { PrintRecords, GenEmitter, GenRegisterEnums, GenRegister, GenRegisterHeader, - GenInstrEnums, GenInstrs, GenAsmWriter, + GenInstrEnums, GenInstrs, GenAsmWriter, GenAsmMatcher, GenCallingConv, GenClangDiagsDefs, GenClangDiagGroups, @@ -77,6 +78,8 @@ namespace { "Generate calling convention descriptions"), clEnumValN(GenAsmWriter, "gen-asm-writer", "Generate assembly writer"), + clEnumValN(GenAsmMatcher, "gen-asm-matcher", + "Generate assembly instruction matcher"), clEnumValN(GenDAGISel, "gen-dag-isel", "Generate a DAG instruction selector"), clEnumValN(GenFastISel, "gen-fast-isel", @@ -138,7 +141,7 @@ static bool ParseFile(const std::string &Filename, std::string ErrorStr; MemoryBuffer *F = MemoryBuffer::getFileOrSTDIN(Filename.c_str(), &ErrorStr); if (F == 0) { - errs() << "Could not open input file '" + Filename + "': " + errs() << "Could not open input file '" << Filename << "': " << ErrorStr <<"\n"; return true; } @@ -168,7 +171,7 @@ int main(int argc, char **argv) { raw_ostream *Out = &outs(); if (OutputFilename != "-") { std::string Error; - Out = new raw_fd_ostream(OutputFilename.c_str(), false, Error); + Out = new raw_fd_ostream(OutputFilename.c_str(), Error); if (!Error.empty()) { errs() << argv[0] << ": error opening " << OutputFilename @@ -210,6 +213,9 @@ int main(int argc, char **argv) { case GenAsmWriter: AsmWriterEmitter(Records).run(*Out); break; + case GenAsmMatcher: + AsmMatcherEmitter(Records).run(*Out); + break; case GenClangDiagsDefs: ClangDiagsDefsEmitter(Records, ClangComponent).run(*Out); break; |