diff --git a/include/llvm/Target/TargetAsmParser.h b/include/llvm/Target/TargetAsmParser.h index f431c38dc3a..4d37ad3d75d 100644 --- a/include/llvm/Target/TargetAsmParser.h +++ b/include/llvm/Target/TargetAsmParser.h @@ -28,14 +28,20 @@ class TargetAsmParser : public MCAsmParserExtension { protected: // Can only create subclasses. TargetAsmParser(const Target &); - /// TheTarget - The Target that this machine was created for. + /// The Target that this machine was created for. const Target &TheTarget; + /// The current set of available features. + unsigned AvailableFeatures; + public: virtual ~TargetAsmParser(); const Target &getTarget() const { return TheTarget; } + unsigned getAvailableFeatures() const { return AvailableFeatures; } + void setAvailableFeatures(unsigned Value) { AvailableFeatures = Value; } + /// ParseInstruction - Parse one assembly instruction. /// /// The parser is positioned following the instruction name. The target diff --git a/lib/MC/MCParser/TargetAsmParser.cpp b/lib/MC/MCParser/TargetAsmParser.cpp index 05760c96cc6..8d43c21f4bc 100644 --- a/lib/MC/MCParser/TargetAsmParser.cpp +++ b/lib/MC/MCParser/TargetAsmParser.cpp @@ -11,7 +11,7 @@ using namespace llvm; TargetAsmParser::TargetAsmParser(const Target &T) - : TheTarget(T) + : TheTarget(T), AvailableFeatures(0) { } diff --git a/lib/Target/X86/AsmParser/X86AsmParser.cpp b/lib/Target/X86/AsmParser/X86AsmParser.cpp index 9b1ef197429..c33678cb262 100644 --- a/lib/Target/X86/AsmParser/X86AsmParser.cpp +++ b/lib/Target/X86/AsmParser/X86AsmParser.cpp @@ -9,6 +9,7 @@ #include "llvm/Target/TargetAsmParser.h" #include "X86.h" +#include "X86Subtarget.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" @@ -51,12 +52,14 @@ private: void InstructionCleanup(MCInst &Inst); - /// @name Auto-generated Match Functions - /// { - bool MatchInstruction(const SmallVectorImpl &Operands, MCInst &Inst); + /// @name Auto-generated Matcher Functions + /// { + + unsigned ComputeAvailableFeatures(const X86Subtarget *Subtarget) const; + bool MatchInstructionImpl( const SmallVectorImpl &Operands, MCInst &Inst); @@ -64,7 +67,12 @@ private: public: X86ATTAsmParser(const Target &T, MCAsmParser &_Parser, TargetMachine &TM) - : TargetAsmParser(T), Parser(_Parser), TM(TM) {} + : TargetAsmParser(T), Parser(_Parser), TM(TM) { + + // Initialize the set of available features. + setAvailableFeatures(ComputeAvailableFeatures( + &TM.getSubtarget())); + } virtual bool ParseInstruction(StringRef Name, SMLoc NameLoc, SmallVectorImpl &Operands); diff --git a/utils/TableGen/AsmMatcherEmitter.cpp b/utils/TableGen/AsmMatcherEmitter.cpp index e1aa2bc70f6..08a430dc92d 100644 --- a/utils/TableGen/AsmMatcherEmitter.cpp +++ b/utils/TableGen/AsmMatcherEmitter.cpp @@ -271,6 +271,8 @@ static bool IsAssemblerInstruction(StringRef Name, namespace { +struct SubtargetFeatureInfo; + /// ClassInfo - Helper class for storing the information about a particular /// class of operands which can be matched. struct ClassInfo { @@ -444,6 +446,9 @@ struct InstructionInfo { /// Operands - The operands that this instruction matches. SmallVector Operands; + /// Predicates - The required subtarget features to match this instruction. + SmallVector RequiredFeatures; + /// ConversionFnKind - The enum value which is passed to the generated /// ConvertToMCInst to convert parsed operands into an MCInst for this /// function. @@ -505,6 +510,19 @@ public: void dump(); }; +/// SubtargetFeatureInfo - Helper class for storing information on a subtarget +/// feature which participates in instruction matching. +struct SubtargetFeatureInfo { + /// \brief The predicate record for this feature. + Record *TheDef; + + /// \brief An unique index assigned to represent this feature. + unsigned Index; + + /// \brief The name of the enumerated constant identifying this feature. + std::string EnumName; +}; + class AsmMatcherInfo { public: /// The tablegen AsmParser record. @@ -525,6 +543,9 @@ public: /// Map of Register records to their class information. std::map RegisterClasses; + /// Map of Predicate records to their subtarget information. + std::map SubtargetFeatures; + private: /// Map of token to class information which has already been constructed. std::map TokenClasses; @@ -543,6 +564,23 @@ private: ClassInfo *getOperandClass(StringRef Token, const CodeGenInstruction::OperandInfo &OI); + /// getSubtargetFeature - Lookup or create the subtarget feature info for the + /// given operand. + SubtargetFeatureInfo *getSubtargetFeature(Record *Def) { + assert(Def->isSubClassOf("Predicate") && "Invalid predicate type!"); + + SubtargetFeatureInfo *&Entry = SubtargetFeatures[Def]; + if (!Entry) { + Entry = new SubtargetFeatureInfo; + Entry->TheDef = Def; + Entry->Index = SubtargetFeatures.size() - 1; + Entry->EnumName = "Feature_" + Def->getName(); + assert(Entry->Index < 32 && "Too many subtarget features!"); + } + + return Entry; + } + /// BuildRegisterClasses - Build the ClassInfo* instances for register /// classes. void BuildRegisterClasses(CodeGenTarget &Target, @@ -903,7 +941,31 @@ void AsmMatcherInfo::BuildInfo(CodeGenTarget &Target) { } } } - + + // Compute the require features. + ListInit *Predicates = CGI.TheDef->getValueAsListInit("Predicates"); + for (unsigned i = 0, e = Predicates->getSize(); i != e; ++i) { + if (DefInit *Pred = dynamic_cast(Predicates->getElement(i))) { + // Ignore OptForSize and OptForSpeed, they aren't really requirements, + // rather they are hints to isel. + // + // FIXME: Find better way to model this. + if (Pred->getDef()->getName() == "OptForSize" || + Pred->getDef()->getName() == "OptForSpeed") + continue; + + // FIXME: Total hack; for now, we just limit ourselves to In32BitMode + // and In64BitMode, because we aren't going to have the right feature + // masks for SSE and friends. We need to decide what we are going to do + // about CPU subtypes to implement this the right way. + if (Pred->getDef()->getName() != "In32BitMode" && + Pred->getDef()->getName() != "In64BitMode") + continue; + + II->RequiredFeatures.push_back(getSubtargetFeature(Pred->getDef())); + } + } + Instructions.push_back(II.take()); } @@ -1499,6 +1561,48 @@ static void EmitMatchRegisterName(CodeGenTarget &Target, Record *AsmParser, OS << "}\n\n"; } +/// EmitSubtargetFeatureFlagEnumeration - Emit the subtarget feature flag +/// definitions. +static void EmitSubtargetFeatureFlagEnumeration(CodeGenTarget &Target, + AsmMatcherInfo &Info, + raw_ostream &OS) { + OS << "// Flags for subtarget features that participate in " + << "instruction matching.\n"; + OS << "enum SubtargetFeatureFlag {\n"; + for (std::map::const_iterator + it = Info.SubtargetFeatures.begin(), + ie = Info.SubtargetFeatures.end(); it != ie; ++it) { + SubtargetFeatureInfo &SFI = *it->second; + OS << " " << SFI.EnumName << " = (1 << " << SFI.Index << "),\n"; + } + OS << " Feature_None = 0\n"; + OS << "};\n\n"; +} + +/// EmitComputeAvailableFeatures - Emit the function to compute the list of +/// available features given a subtarget. +static void EmitComputeAvailableFeatures(CodeGenTarget &Target, + AsmMatcherInfo &Info, + raw_ostream &OS) { + std::string ClassName = + Info.AsmParser->getValueAsString("AsmParserClassName"); + + OS << "unsigned " << Target.getName() << ClassName << "::\n" + << "ComputeAvailableFeatures(const " << Target.getName() + << "Subtarget *Subtarget) const {\n"; + OS << " unsigned Features = 0;\n"; + for (std::map::const_iterator + it = Info.SubtargetFeatures.begin(), + ie = Info.SubtargetFeatures.end(); it != ie; ++it) { + SubtargetFeatureInfo &SFI = *it->second; + OS << " if (" << SFI.TheDef->getValueAsString("CondString") + << ")\n"; + OS << " Features |= " << SFI.EnumName << ";\n"; + } + OS << " return Features;\n"; + OS << "}\n\n"; +} + void AsmMatcherEmitter::run(raw_ostream &OS) { CodeGenTarget Target; Record *AsmParser = Target.getAsmParser(); @@ -1550,6 +1654,9 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { EmitSourceFileHeader("Assembly Matcher Source Fragment", OS); + // Emit the subtarget feature enumeration. + EmitSubtargetFeatureFlagEnumeration(Target, Info, OS); + // Emit the function to match a register name to number. EmitMatchRegisterName(Target, AsmParser, OS); @@ -1570,6 +1677,9 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { // Emit the subclass predicate routine. EmitIsSubclass(Target, Info.Classes, OS); + // Emit the available features compute function. + EmitComputeAvailableFeatures(Target, Info, OS); + // Finally, build the match function. size_t MaxNumOperands = 0; @@ -1600,6 +1710,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << " unsigned Opcode;\n"; OS << " ConversionKind ConvertFn;\n"; OS << " MatchClassKind Classes[" << MaxNumOperands << "];\n"; + OS << " unsigned RequiredFeatures;\n"; OS << " } MatchTable[" << Info.Instructions.size() << "] = {\n"; for (std::vector::const_iterator it = @@ -1615,11 +1726,27 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { if (i) OS << ", "; OS << Op.Class->Name; } - OS << " } },\n"; + OS << " }, "; + + // Write the required features mask. + if (!II.RequiredFeatures.empty()) { + for (unsigned i = 0, e = II.RequiredFeatures.size(); i != e; ++i) { + if (i) OS << "|"; + OS << II.RequiredFeatures[i]->EnumName; + } + } else + OS << "0"; + + OS << "},\n"; } OS << " };\n\n"; + + // Emit code to get the available features. + OS << " // Get the current feature set.\n"; + OS << " unsigned AvailableFeatures = getAvailableFeatures();\n\n"; + // Emit code to compute the class list for this operand vector. OS << " // Eliminate obvious mismatches.\n"; OS << " if (Operands.size() > " << MaxNumOperands << ")\n"; @@ -1645,6 +1772,13 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << " for (const MatchEntry *it = MatchTable, " << "*ie = MatchTable + " << Info.Instructions.size() << "; it != ie; ++it) {\n"; + + // Emit check that the required features are available. + OS << " if ((AvailableFeatures & it->RequiredFeatures) " + << "!= it->RequiredFeatures)\n"; + OS << " continue;\n"; + + // Emit check that the subclasses match. for (unsigned i = 0; i != MaxNumOperands; ++i) { OS << " if (!IsSubclass(Classes[" << i << "], it->Classes[" << i << "]))\n";