diff --git a/include/llvm/Target/Target.td b/include/llvm/Target/Target.td index 5262cce6943..98b41254fc7 100644 --- a/include/llvm/Target/Target.td +++ b/include/llvm/Target/Target.td @@ -286,6 +286,17 @@ class Operand { string PrintMethod = "printOperand"; string AsmOperandLowerMethod = ?; dag MIOperandInfo = (ops); + + // ParserMatchClass - The "match class" that operands of this type fit + // in. Match classes are used to define the order in which instructions are + // match, to ensure that which instructions gets matched is deterministic. + string ParserMatchClass = "Imm"; + + // ParserMatchSuperClass - The enclosing super class for this operand (if + // any). This operand *must* be a subset of the valid operands for the super + // class; i.e., the match predicate for this super class must return true + // for all instances of this class. + string ParserMatchSuperClass = ?; } def i1imm : Operand; diff --git a/lib/Target/X86/X86InstrInfo.td b/lib/Target/X86/X86InstrInfo.td index 8263b2795a7..c21cad98df0 100644 --- a/lib/Target/X86/X86InstrInfo.td +++ b/lib/Target/X86/X86InstrInfo.td @@ -173,6 +173,7 @@ def ptr_rc_nosp : PointerLikeRegClass<1>; class X86MemOperand : Operand { let PrintMethod = printMethod; let MIOperandInfo = (ops ptr_rc, i8imm, ptr_rc_nosp, i32imm, i8imm); + let ParserMatchClass = "Mem"; } def i8mem : X86MemOperand<"printi8mem">; @@ -192,11 +193,13 @@ def f256mem : X86MemOperand<"printf256mem">; def i8mem_NOREX : Operand { let PrintMethod = "printi8mem"; let MIOperandInfo = (ops GR64_NOREX, i8imm, GR64_NOREX_NOSP, i32imm, i8imm); + let ParserMatchClass = "Mem"; } def lea32mem : Operand { let PrintMethod = "printlea32mem"; let MIOperandInfo = (ops GR32, i8imm, GR32_NOSP, i32imm); + let ParserMatchClass = "Mem"; } def SSECC : Operand { diff --git a/utils/TableGen/AsmMatcherEmitter.cpp b/utils/TableGen/AsmMatcherEmitter.cpp index 9b12927521f..cbe214d3f31 100644 --- a/utils/TableGen/AsmMatcherEmitter.cpp +++ b/utils/TableGen/AsmMatcherEmitter.cpp @@ -278,19 +278,23 @@ namespace { /// class of operands which can be matched. struct ClassInfo { enum ClassInfoKind { - Token, ///< The class for a particular token. - Register, ///< A register class. - UserClass0 ///< The (first) user defined class, subsequent user defined - /// classes are UserClass0+1, and so on. + Invalid = 0, ///< Invalid kind, for use as a sentinel value. + Token, ///< The class for a particular token. + Register, ///< A register class. + UserClass0 ///< The (first) user defined class, subsequent user defined + /// classes are UserClass0+1, and so on. }; /// Kind - The class kind, which is either a predefined kind, or (UserClass0 + /// N) for the Nth user defined class. unsigned Kind; - /// Name - The class name, suitable for use as an enum. + /// 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). @@ -311,6 +315,8 @@ struct ClassInfo { return Kind < RHS.Kind; switch (Kind) { + case Invalid: + assert(0 && "Invalid kind!"); case Token: // Tokens are always comparable. // @@ -412,10 +418,17 @@ private: /// constructed. std::map OperandClasses; + /// Map of user class names to kind value. + std::map UserClasses; + private: /// getTokenClass - Lookup or create the class for the given token. ClassInfo *getTokenClass(const StringRef &Token); + /// getUserClassKind - Lookup or create the kind value for the given class + /// name. + unsigned getUserClassKind(const StringRef &Name); + /// getOperandClass - Lookup or create the class for the given operand. ClassInfo *getOperandClass(const StringRef &Token, const CodeGenInstruction::OperandInfo &OI); @@ -439,7 +452,7 @@ void InstructionInfo::dump() { for (unsigned i = 0, e = Operands.size(); i != e; ++i) { Operand &Op = Operands[i]; - errs() << " op[" << i << "] = "; + errs() << " op[" << i << "] = " << Op.Class->ClassName << " - "; if (Op.Class->Kind == ClassInfo::Token) { errs() << '\"' << Tokens[i] << "\"\n"; continue; @@ -478,6 +491,7 @@ ClassInfo *AsmMatcherInfo::getTokenClass(const StringRef &Token) { if (!Entry) { Entry = new ClassInfo(); Entry->Kind = ClassInfo::Token; + Entry->ClassName = "Token"; Entry->Name = "MCK_" + getEnumNameForToken(Token); Entry->ValueName = Token; Entry->PredicateMethod = ""; @@ -488,28 +502,28 @@ ClassInfo *AsmMatcherInfo::getTokenClass(const StringRef &Token) { return Entry; } +unsigned AsmMatcherInfo::getUserClassKind(const StringRef &Name) { + unsigned &Entry = UserClasses[Name]; + + if (!Entry) + Entry = ClassInfo::UserClass0 + UserClasses.size() - 1; + + return Entry; +} + ClassInfo * AsmMatcherInfo::getOperandClass(const StringRef &Token, const CodeGenInstruction::OperandInfo &OI) { std::string ClassName; if (OI.Rec->isSubClassOf("RegisterClass")) { ClassName = "Reg"; - } else if (OI.Rec->isSubClassOf("Operand")) { - // FIXME: This should not be hard coded. - const RecordVal *RV = OI.Rec->getValue("Type"); - - // FIXME: Yet another total hack. - if (RV->getValue()->getAsString() == "iPTR" || - OI.Rec->getName() == "i8mem_NOREX" || - OI.Rec->getName() == "lea32mem" || - OI.Rec->getName() == "lea64mem" || - OI.Rec->getName() == "i128mem" || - OI.Rec->getName() == "sdmem" || - OI.Rec->getName() == "ssmem" || - OI.Rec->getName() == "lea64_32mem") { - ClassName = "Mem"; - } else { - ClassName = "Imm"; + } else { + try { + ClassName = OI.Rec->getValueAsString("ParserMatchClass"); + assert(ClassName != "Reg" && "'Reg' class name is reserved!"); + } catch(...) { + PrintError(OI.Rec->getLoc(), "operand has no match class!"); + ClassName = "Invalid"; } } @@ -521,11 +535,9 @@ AsmMatcherInfo::getOperandClass(const StringRef &Token, if (ClassName == "Reg") { Entry->Kind = ClassInfo::Register; } else { - if (ClassName == "Mem") - Entry->Kind = ClassInfo::UserClass0; - else - Entry->Kind = ClassInfo::UserClass0 + 1; + Entry->Kind = getUserClassKind(ClassName); } + Entry->ClassName = ClassName; Entry->Name = "MCK_" + ClassName; Entry->ValueName = OI.Rec->getName(); Entry->PredicateMethod = "is" + ClassName; @@ -665,7 +677,7 @@ static void EmitConvertToMCInst(CodeGenTarget &Target, for (; CurIndex != Op.OperandInfo->MIOperandNo; ++CurIndex) Signature += "Imp"; - Signature += Op.Class->Name; + Signature += Op.Class->ClassName; Signature += utostr(Op.OperandInfo->MINumOperands); Signature += "_" + utostr(MIOperandList[i].second);