From: Daniel Dunbar Date: Sun, 9 Aug 2009 04:00:06 +0000 (+0000) Subject: llvm-mc/AsmParser: Sketch infrastructure for ordering instructions & detecting X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=606e8ad796f72824f5509e2657c44eca025d4baf;p=oota-llvm.git llvm-mc/AsmParser: Sketch infrastructure for ordering instructions & detecting ambiguities. - Currently there are 483 ambiguities to resolve. :) git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@78522 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/utils/TableGen/AsmMatcherEmitter.cpp b/utils/TableGen/AsmMatcherEmitter.cpp index 6948a7ee645..9b12927521f 100644 --- a/utils/TableGen/AsmMatcherEmitter.cpp +++ b/utils/TableGen/AsmMatcherEmitter.cpp @@ -78,6 +78,7 @@ #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" @@ -88,8 +89,8 @@ using namespace llvm; namespace { static cl::opt -MatchOneInstr("match-one-instr", cl::desc("Match only the named instruction"), - cl::init("")); +MatchPrefix("match-prefix", cl::init(""), + cl::desc("Only match instructions with the given prefix")); } /// FlattenVariants - Flatten an .td file assembly string by selecting the @@ -276,11 +277,16 @@ namespace { /// ClassInfo - Helper class for storing the information about a particular /// class of operands which can be matched. struct ClassInfo { - enum { + enum ClassInfoKind { Token, ///< The class for a particular token. Register, ///< A register class. - User ///< A user defined class. - } Kind; + 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. std::string Name; @@ -297,6 +303,29 @@ struct ClassInfo { /// RenderMethod - The name of the operand method to add this operand to an /// MCInst; this is not valid for Token kinds. std::string RenderMethod; + + /// operator< - Compare two classes. + bool operator<(const ClassInfo &RHS) const { + // Incompatible kinds are comparable. + if (Kind != RHS.Kind) + return Kind < RHS.Kind; + + switch (Kind) { + case Token: + // Tokens are always comparable. + // + // FIXME: Compare by enum value. + return ValueName < RHS.ValueName; + + case Register: + // FIXME: Compare by subset relation. + return false; + + default: + // FIXME: Allow user defined relation. + return false; + } + } }; /// InstructionInfo - Helper class for storing the necessary information for an @@ -331,6 +360,38 @@ struct InstructionInfo { /// function. std::string ConversionFnKind; + /// operator< - Compare two instructions. + bool operator<(const InstructionInfo &RHS) const { + // Order first by the number of operands (which is unambiguous). + if (Operands.size() != RHS.Operands.size()) + return Operands.size() < RHS.Operands.size(); + + // Otherwise, order by lexicographic comparison of tokens and operand kinds + // (these can never be ambiguous). + 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) + return true; + + // Finally, order by the component wise comparison of operand classes. We + // don't want to rely on the lexigraphic ordering of elements, so we define + // only define the ordering when it is unambiguous. That is, when some pair + // compares less than and no pair compares greater than. + + // Check that no pair compares greater than. + for (unsigned i = 0, e = Operands.size(); i != e; ++i) + if (*RHS.Operands[i].Class < *Operands[i].Class) + return false; + + // Otherwise, return true if some pair compares less than. + for (unsigned i = 0, e = Operands.size(); i != e; ++i) + if (*Operands[i].Class < *RHS.Operands[i].Class) + return true; + + return false; + } + public: void dump(); }; @@ -460,7 +521,10 @@ AsmMatcherInfo::getOperandClass(const StringRef &Token, if (ClassName == "Reg") { Entry->Kind = ClassInfo::Register; } else { - Entry->Kind = ClassInfo::User; + if (ClassName == "Mem") + Entry->Kind = ClassInfo::UserClass0; + else + Entry->Kind = ClassInfo::UserClass0 + 1; } Entry->Name = "MCK_" + ClassName; Entry->ValueName = OI.Rec->getName(); @@ -479,7 +543,7 @@ void AsmMatcherInfo::BuildInfo(CodeGenTarget &Target) { it != ie; ++it) { const CodeGenInstruction &CGI = it->second; - if (!MatchOneInstr.empty() && it->first != MatchOneInstr) + if (!StringRef(it->first).startswith(MatchPrefix)) continue; OwningPtr II(new InstructionInfo); @@ -537,9 +601,9 @@ void AsmMatcherInfo::BuildInfo(CodeGenTarget &Target) { } } -static void ConstructConversionFunctions(CodeGenTarget &Target, - std::vector &Infos, - raw_ostream &OS) { +static void EmitConvertToMCInst(CodeGenTarget &Target, + std::vector &Infos, + raw_ostream &OS) { // Write the convert function to a separate stream, so we can drop it after // the enum. std::string ConvertFnBody; @@ -902,6 +966,10 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { AsmMatcherInfo Info; Info.BuildInfo(Target); + // Sort the instruction table using the partial order on classes. + std::sort(Info.Instructions.begin(), Info.Instructions.end(), + less_ptr()); + DEBUG_WITH_TYPE("instruction_info", { for (std::vector::iterator it = Info.Instructions.begin(), ie = Info.Instructions.end(); @@ -909,11 +977,35 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { (*it)->dump(); }); - // FIXME: At this point we should be able to totally order Infos, if not then - // we have an ambiguity which the .td file should be forced to resolve. + // Check for ambiguous instructions. + unsigned NumAmbiguous = 0; + for (std::vector::const_iterator it = + Info.Instructions.begin(), ie = Info.Instructions.end() - 1; + it != ie;) { + InstructionInfo &II = **it; + ++it; - // Generate the terminal actions to convert operands into an MCInst. - ConstructConversionFunctions(Target, Info.Instructions, OS); + InstructionInfo &Next = **it; + + if (!(II < Next)){ + DEBUG_WITH_TYPE("ambiguous_instrs", { + errs() << "warning: ambiguous instruction match:\n"; + II.dump(); + errs() << "\nis incomparable with:\n"; + Next.dump(); + errs() << "\n\n"; + }); + ++NumAmbiguous; + } + } + if (NumAmbiguous) + DEBUG_WITH_TYPE("ambiguous_instrs", { + errs() << "warning: " << NumAmbiguous + << " ambiguous instructions!\n"; + }); + + // 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);