diff options
Diffstat (limited to 'utils/TableGen')
-rw-r--r-- | utils/TableGen/AsmMatcherEmitter.cpp | 47 | ||||
-rw-r--r-- | utils/TableGen/AsmWriterEmitter.cpp | 4 | ||||
-rw-r--r-- | utils/TableGen/CodeEmitterGen.cpp | 14 | ||||
-rw-r--r-- | utils/TableGen/CodeGenInstruction.h | 2 | ||||
-rw-r--r-- | utils/TableGen/CodeGenMapTable.cpp | 4 | ||||
-rw-r--r-- | utils/TableGen/CodeGenTarget.cpp | 2 | ||||
-rw-r--r-- | utils/TableGen/CodeGenTarget.h | 2 | ||||
-rw-r--r-- | utils/TableGen/DAGISelMatcherGen.cpp | 2 | ||||
-rw-r--r-- | utils/TableGen/FastISelEmitter.cpp | 18 | ||||
-rw-r--r-- | utils/TableGen/FixedLenDecoderEmitter.cpp | 4 | ||||
-rw-r--r-- | utils/TableGen/GlobalISelEmitter.cpp | 777 | ||||
-rw-r--r-- | utils/TableGen/InstrInfoEmitter.cpp | 12 | ||||
-rw-r--r-- | utils/TableGen/RegisterBankEmitter.cpp | 2 | ||||
-rw-r--r-- | utils/TableGen/SearchableTableEmitter.cpp | 10 | ||||
-rw-r--r-- | utils/TableGen/SubtargetEmitter.cpp | 9 | ||||
-rw-r--r-- | utils/TableGen/X86DisassemblerTables.cpp | 2 | ||||
-rw-r--r-- | utils/TableGen/X86DisassemblerTables.h | 2 | ||||
-rw-r--r-- | utils/TableGen/X86ModRMFilters.h | 2 | ||||
-rw-r--r-- | utils/TableGen/X86RecognizableInstr.cpp | 4 | ||||
-rw-r--r-- | utils/TableGen/X86RecognizableInstr.h | 2 |
20 files changed, 568 insertions, 353 deletions
diff --git a/utils/TableGen/AsmMatcherEmitter.cpp b/utils/TableGen/AsmMatcherEmitter.cpp index 0980e08f67f7..1f8e1b125889 100644 --- a/utils/TableGen/AsmMatcherEmitter.cpp +++ b/utils/TableGen/AsmMatcherEmitter.cpp @@ -2222,7 +2222,7 @@ static void emitValidateOperandClass(AsmMatcherInfo &Info, OS << " switch (Operand.getReg()) {\n"; OS << " default: OpKind = InvalidMatchClass; break;\n"; for (const auto &RC : Info.RegisterClasses) - OS << " case " << Info.Target.getName() << "::" + OS << " case " << RC.first->getValueAsString("Namespace") << "::" << RC.first->getName() << ": OpKind = " << RC.second->Name << "; break;\n"; OS << " }\n"; @@ -2711,6 +2711,47 @@ static void emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target, OS << "}\n\n"; } +static void emitMnemonicSpellChecker(raw_ostream &OS, CodeGenTarget &Target, + unsigned VariantCount) { + OS << "std::string " << Target.getName() << "MnemonicSpellCheck(StringRef S, uint64_t FBS) {\n"; + if (!VariantCount) + OS << " return \"\";"; + else { + OS << " const unsigned MaxEditDist = 2;\n"; + OS << " std::vector<StringRef> Candidates;\n"; + OS << " StringRef Prev = \"\";\n"; + OS << " auto End = std::end(MatchTable0);\n"; + OS << "\n"; + OS << " for (auto I = std::begin(MatchTable0); I < End; I++) {\n"; + OS << " // Ignore unsupported instructions.\n"; + OS << " if ((FBS & I->RequiredFeatures) != I->RequiredFeatures)\n"; + OS << " continue;\n"; + OS << "\n"; + OS << " StringRef T = I->getMnemonic();\n"; + OS << " // Avoid recomputing the edit distance for the same string.\n"; + OS << " if (T.equals(Prev))\n"; + OS << " continue;\n"; + OS << "\n"; + OS << " Prev = T;\n"; + OS << " unsigned Dist = S.edit_distance(T, false, MaxEditDist);\n"; + OS << " if (Dist <= MaxEditDist)\n"; + OS << " Candidates.push_back(T);\n"; + OS << " }\n"; + OS << "\n"; + OS << " if (Candidates.empty())\n"; + OS << " return \"\";\n"; + OS << "\n"; + OS << " std::string Res = \", did you mean: \";\n"; + OS << " unsigned i = 0;\n"; + OS << " for( ; i < Candidates.size() - 1; i++)\n"; + OS << " Res += Candidates[i].str() + \", \";\n"; + OS << " return Res + Candidates[i].str() + \"?\";\n"; + } + OS << "}\n"; + OS << "\n"; +} + + void AsmMatcherEmitter::run(raw_ostream &OS) { CodeGenTarget Target(Records); Record *AsmParser = Target.getAsmParser(); @@ -2948,7 +2989,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { std::string LenMnemonic = char(MI->Mnemonic.size()) + MI->Mnemonic.str(); OS << " { " << StringTable.GetOrAddStringOffset(LenMnemonic, false) << " /* " << MI->Mnemonic << " */, " - << Target.getName() << "::" + << Target.getInstNamespace() << "::" << MI->getResultInst()->TheDef->getName() << ", " << MI->ConversionFnKind << ", "; @@ -2974,6 +3015,8 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << "};\n\n"; } + emitMnemonicSpellChecker(OS, Target, VariantCount); + // Finally, build the match function. OS << "unsigned " << Target.getName() << ClassName << "::\n" << "MatchInstructionImpl(const OperandVector &Operands,\n"; diff --git a/utils/TableGen/AsmWriterEmitter.cpp b/utils/TableGen/AsmWriterEmitter.cpp index 30d21984c4d3..75b9bc6cca40 100644 --- a/utils/TableGen/AsmWriterEmitter.cpp +++ b/utils/TableGen/AsmWriterEmitter.cpp @@ -137,12 +137,12 @@ static void EmitInstructions(std::vector<AsmWriterInst> &Insts, O << " switch (MI->getOpcode()) {\n"; O << " default: llvm_unreachable(\"Unexpected opcode.\");\n"; std::vector<std::pair<std::string, AsmWriterOperand>> OpsToPrint; - OpsToPrint.push_back(std::make_pair(FirstInst.CGI->Namespace + "::" + + OpsToPrint.push_back(std::make_pair(FirstInst.CGI->Namespace.str() + "::" + FirstInst.CGI->TheDef->getName().str(), FirstInst.Operands[i])); for (const AsmWriterInst &AWI : SimilarInsts) { - OpsToPrint.push_back(std::make_pair(AWI.CGI->Namespace+"::" + + OpsToPrint.push_back(std::make_pair(AWI.CGI->Namespace.str()+"::" + AWI.CGI->TheDef->getName().str(), AWI.Operands[i])); } diff --git a/utils/TableGen/CodeEmitterGen.cpp b/utils/TableGen/CodeEmitterGen.cpp index b80dd5daefe0..23751a2cbfba 100644 --- a/utils/TableGen/CodeEmitterGen.cpp +++ b/utils/TableGen/CodeEmitterGen.cpp @@ -187,20 +187,18 @@ AddCodeToMergeInOperand(Record *R, BitsInit *BI, const std::string &VarName, std::string CodeEmitterGen::getInstructionCase(Record *R, CodeGenTarget &Target) { std::string Case; - BitsInit *BI = R->getValueAsBitsInit("Inst"); - const std::vector<RecordVal> &Vals = R->getValues(); unsigned NumberedOp = 0; - std::set<unsigned> NamedOpIndices; + // Collect the set of operand indices that might correspond to named // operand, and skip these when assigning operands based on position. if (Target.getInstructionSet()-> getValueAsBit("noNamedPositionallyEncodedOperands")) { CodeGenInstruction &CGI = Target.getInstruction(R); - for (unsigned i = 0, e = Vals.size(); i != e; ++i) { + for (const RecordVal &RV : R->getValues()) { unsigned OpIdx; - if (!CGI.Operands.hasOperandNamed(Vals[i].getName(), OpIdx)) + if (!CGI.Operands.hasOperandNamed(RV.getName(), OpIdx)) continue; NamedOpIndices.insert(OpIdx); @@ -209,13 +207,13 @@ std::string CodeEmitterGen::getInstructionCase(Record *R, // Loop over all of the fields in the instruction, determining which are the // operands to the instruction. - for (unsigned i = 0, e = Vals.size(); i != e; ++i) { + for (const RecordVal &RV : R->getValues()) { // Ignore fixed fields in the record, we're looking for values like: // bits<5> RST = { ?, ?, ?, ?, ? }; - if (Vals[i].getPrefix() || Vals[i].getValue()->isComplete()) + if (RV.getPrefix() || RV.getValue()->isComplete()) continue; - AddCodeToMergeInOperand(R, BI, Vals[i].getName(), NumberedOp, + AddCodeToMergeInOperand(R, BI, RV.getName(), NumberedOp, NamedOpIndices, Case, Target); } diff --git a/utils/TableGen/CodeGenInstruction.h b/utils/TableGen/CodeGenInstruction.h index 75db17b59ac3..e173e153879c 100644 --- a/utils/TableGen/CodeGenInstruction.h +++ b/utils/TableGen/CodeGenInstruction.h @@ -206,7 +206,7 @@ template <typename T> class ArrayRef; class CodeGenInstruction { public: Record *TheDef; // The actual record defining this instruction. - std::string Namespace; // The namespace the instruction is in. + StringRef Namespace; // The namespace the instruction is in. /// AsmString - The format string used to emit a .s file for the /// instruction. diff --git a/utils/TableGen/CodeGenMapTable.cpp b/utils/TableGen/CodeGenMapTable.cpp index 60db6c267ad7..43348b622a74 100644 --- a/utils/TableGen/CodeGenMapTable.cpp +++ b/utils/TableGen/CodeGenMapTable.cpp @@ -367,7 +367,7 @@ unsigned MapTableEmitter::emitBinSearchTable(raw_ostream &OS) { ArrayRef<const CodeGenInstruction*> NumberedInstructions = Target.getInstructionsByEnumValue(); - std::string Namespace = Target.getInstNamespace(); + StringRef Namespace = Target.getInstNamespace(); const std::vector<ListInit*> &ValueCols = InstrMapDesc.getValueCols(); unsigned NumCol = ValueCols.size(); unsigned TotalNumInstr = NumberedInstructions.size(); @@ -567,7 +567,7 @@ namespace llvm { //===----------------------------------------------------------------------===// void EmitMapTable(RecordKeeper &Records, raw_ostream &OS) { CodeGenTarget Target(Records); - std::string NameSpace = Target.getInstNamespace(); + StringRef NameSpace = Target.getInstNamespace(); std::vector<Record*> InstrMapVec; InstrMapVec = Records.getAllDerivedDefinitions("InstrMapping"); diff --git a/utils/TableGen/CodeGenTarget.cpp b/utils/TableGen/CodeGenTarget.cpp index eb277f3298f9..58df3ceceee7 100644 --- a/utils/TableGen/CodeGenTarget.cpp +++ b/utils/TableGen/CodeGenTarget.cpp @@ -207,7 +207,7 @@ const StringRef CodeGenTarget::getName() const { return TargetRec->getName(); } -std::string CodeGenTarget::getInstNamespace() const { +StringRef CodeGenTarget::getInstNamespace() const { for (const CodeGenInstruction *Inst : getInstructionsByEnumValue()) { // Make sure not to pick up "TargetOpcode" by accidentally getting // the namespace off the PHI instruction or something. diff --git a/utils/TableGen/CodeGenTarget.h b/utils/TableGen/CodeGenTarget.h index c822e940ffae..ff624ea559e5 100644 --- a/utils/TableGen/CodeGenTarget.h +++ b/utils/TableGen/CodeGenTarget.h @@ -86,7 +86,7 @@ public: /// getInstNamespace - Return the target-specific instruction namespace. /// - std::string getInstNamespace() const; + StringRef getInstNamespace() const; /// getInstructionSet - Return the InstructionSet object. /// diff --git a/utils/TableGen/DAGISelMatcherGen.cpp b/utils/TableGen/DAGISelMatcherGen.cpp index d239f96d2a60..d4a56a64324f 100644 --- a/utils/TableGen/DAGISelMatcherGen.cpp +++ b/utils/TableGen/DAGISelMatcherGen.cpp @@ -886,7 +886,7 @@ EmitResultInstructionAsOperand(const TreePatternNode *N, assert((!ResultVTs.empty() || TreeHasOutGlue || NodeHasChain) && "Node has no result"); - AddMatcher(new EmitNodeMatcher(II.Namespace+"::"+II.TheDef->getName().str(), + AddMatcher(new EmitNodeMatcher(II.Namespace.str()+"::"+II.TheDef->getName().str(), ResultVTs, InstOps, NodeHasChain, TreeHasInGlue, TreeHasOutGlue, NodeHasMemRefs, NumFixedArityOperands, diff --git a/utils/TableGen/FastISelEmitter.cpp b/utils/TableGen/FastISelEmitter.cpp index 0e7b0dc09442..25388b75cc0d 100644 --- a/utils/TableGen/FastISelEmitter.cpp +++ b/utils/TableGen/FastISelEmitter.cpp @@ -390,10 +390,10 @@ class FastISelMap { std::map<OperandsSignature, std::vector<OperandsSignature> > SignaturesWithConstantForms; - std::string InstNS; + StringRef InstNS; ImmPredicateSet ImmediatePredicates; public: - explicit FastISelMap(std::string InstNS); + explicit FastISelMap(StringRef InstNS); void collectPatterns(CodeGenDAGPatterns &CGP); void printImmediatePredicates(raw_ostream &OS); @@ -417,7 +417,7 @@ static std::string getLegalCName(std::string OpName) { return OpName; } -FastISelMap::FastISelMap(std::string instns) : InstNS(std::move(instns)) {} +FastISelMap::FastISelMap(StringRef instns) : InstNS(instns) {} static std::string PhyRegForNode(TreePatternNode *Op, const CodeGenTarget &Target) { @@ -440,10 +440,6 @@ static std::string PhyRegForNode(TreePatternNode *Op, void FastISelMap::collectPatterns(CodeGenDAGPatterns &CGP) { const CodeGenTarget &Target = CGP.getTargetInfo(); - // Determine the target's namespace name. - InstNS = Target.getInstNamespace() + "::"; - assert(InstNS.size() > 2 && "Can't determine target-specific namespace!"); - // Scan through all the patterns and record the simple ones. for (CodeGenDAGPatterns::ptm_iterator I = CGP.ptm_begin(), E = CGP.ptm_end(); I != E; ++I) { @@ -659,8 +655,8 @@ void FastISelMap::emitInstructionCode(raw_ostream &OS, if (Memo.SubRegNo.empty()) { Operands.PrintManglingSuffix(OS, *Memo.PhysRegs, ImmediatePredicates, true); - OS << "(" << InstNS << Memo.Name << ", "; - OS << "&" << InstNS << Memo.RC->getName() << "RegClass"; + OS << "(" << InstNS << "::" << Memo.Name << ", "; + OS << "&" << InstNS << "::" << Memo.RC->getName() << "RegClass"; if (!Operands.empty()) OS << ", "; Operands.PrintArguments(OS, *Memo.PhysRegs); @@ -873,8 +869,8 @@ void EmitFastISel(RecordKeeper &RK, raw_ostream &OS) { Target.getName().str() + " target", OS); // Determine the target's namespace name. - std::string InstNS = Target.getInstNamespace() + "::"; - assert(InstNS.size() > 2 && "Can't determine target-specific namespace!"); + StringRef InstNS = Target.getInstNamespace(); + assert(!InstNS.empty() && "Can't determine target-specific namespace!"); FastISelMap F(InstNS); F.collectPatterns(CGP); diff --git a/utils/TableGen/FixedLenDecoderEmitter.cpp b/utils/TableGen/FixedLenDecoderEmitter.cpp index 75fd73082b9a..03930d7132df 100644 --- a/utils/TableGen/FixedLenDecoderEmitter.cpp +++ b/utils/TableGen/FixedLenDecoderEmitter.cpp @@ -1691,9 +1691,7 @@ void FilterChooser::emitTableEntries(DecoderTableInfo &TableInfo) const { dumpStack(errs(), "\t\t"); for (unsigned i = 0; i < Opcodes.size(); ++i) { - const std::string &Name = nameWithID(Opcodes[i]); - - errs() << '\t' << Name << " "; + errs() << '\t' << nameWithID(Opcodes[i]) << " "; dumpBits(errs(), getBitsField(*AllInstructions[Opcodes[i]]->TheDef, "Inst")); errs() << '\n'; diff --git a/utils/TableGen/GlobalISelEmitter.cpp b/utils/TableGen/GlobalISelEmitter.cpp index 924ed8f65c2c..cafcbeb57de5 100644 --- a/utils/TableGen/GlobalISelEmitter.cpp +++ b/utils/TableGen/GlobalISelEmitter.cpp @@ -53,6 +53,8 @@ STATISTIC(NumPatternTotal, "Total number of patterns"); STATISTIC(NumPatternImported, "Number of patterns imported from SelectionDAG"); STATISTIC(NumPatternImportsSkipped, "Number of SelectionDAG imports skipped"); STATISTIC(NumPatternEmitted, "Number of patterns emitted"); +/// A unique identifier for a MatchTable. +static unsigned CurrentMatchTableID = 0; cl::OptionCategory GlobalISelEmitterCat("Options for -gen-global-isel"); @@ -74,6 +76,18 @@ private: public: LLTCodeGen(const LLT &Ty) : Ty(Ty) {} + void emitCxxEnumValue(raw_ostream &OS) const { + if (Ty.isScalar()) { + OS << "GILLT_s" << Ty.getSizeInBits(); + return; + } + if (Ty.isVector()) { + OS << "GILLT_v" << Ty.getNumElements() << "s" << Ty.getScalarSizeInBits(); + return; + } + llvm_unreachable("Unhandled LLT"); + } + void emitCxxConstructorCall(raw_ostream &OS) const { if (Ty.isScalar()) { OS << "LLT::scalar(" << Ty.getSizeInBits() << ")"; @@ -88,6 +102,33 @@ public: } const LLT &get() const { return Ty; } + + /// This ordering is used for std::unique() and std::sort(). There's no + /// particular logic behind the order. + bool operator<(const LLTCodeGen &Other) const { + if (!Ty.isValid()) + return Other.Ty.isValid(); + if (Ty.isScalar()) { + if (!Other.Ty.isValid()) + return false; + if (Other.Ty.isScalar()) + return Ty.getSizeInBits() < Other.Ty.getSizeInBits(); + return false; + } + if (Ty.isVector()) { + if (!Other.Ty.isValid() || Other.Ty.isScalar()) + return false; + if (Other.Ty.isVector()) { + if (Ty.getNumElements() < Other.Ty.getNumElements()) + return true; + if (Ty.getNumElements() > Other.Ty.getNumElements()) + return false; + return Ty.getSizeInBits() < Other.Ty.getSizeInBits(); + } + return false; + } + llvm_unreachable("Unhandled LLT"); + } }; class InstructionMatcher; @@ -169,6 +210,13 @@ static Record *getInitValueAsRegClass(Init *V) { return nullptr; } +std::string +getNameForFeatureBitset(const std::vector<Record *> &FeatureBitset) { + std::string Name = "GIFBS"; + for (const auto &Feature : FeatureBitset) + Name += ("_" + Feature->getName()).str(); + return Name; +} //===- Matchers -----------------------------------------------------------===// class OperandMatcher; @@ -187,8 +235,8 @@ class RuleMatcher { std::vector<std::unique_ptr<MatchAction>> Actions; /// A map of instruction matchers to the local variables created by - /// emitCxxCaptureStmts(). - std::map<const InstructionMatcher *, std::string> InsnVariableNames; + /// emitCaptureOpcodes(). + std::map<const InstructionMatcher *, unsigned> InsnVariableIDs; /// ID for the next instruction variable defined with defineInsnVar() unsigned NextInsnVarID; @@ -197,35 +245,39 @@ class RuleMatcher { public: RuleMatcher() - : Matchers(), Actions(), InsnVariableNames(), NextInsnVarID(0) {} + : Matchers(), Actions(), InsnVariableIDs(), NextInsnVarID(0) {} RuleMatcher(RuleMatcher &&Other) = default; RuleMatcher &operator=(RuleMatcher &&Other) = default; InstructionMatcher &addInstructionMatcher(); void addRequiredFeature(Record *Feature); + const std::vector<Record *> &getRequiredFeatures() const; template <class Kind, class... Args> Kind &addAction(Args &&... args); - std::string defineInsnVar(raw_ostream &OS, const InstructionMatcher &Matcher, - StringRef Value); - StringRef getInsnVarName(const InstructionMatcher &InsnMatcher) const; + /// Define an instruction without emitting any code to do so. + /// This is used for the root of the match. + unsigned implicitlyDefineInsnVar(const InstructionMatcher &Matcher); + /// Define an instruction and emit corresponding state-machine opcodes. + unsigned defineInsnVar(raw_ostream &OS, const InstructionMatcher &Matcher, + unsigned InsnVarID, unsigned OpIdx); + unsigned getInsnVarID(const InstructionMatcher &InsnMatcher) const; - void emitCxxCapturedInsnList(raw_ostream &OS); - void emitCxxCaptureStmts(raw_ostream &OS, StringRef Expr); + void emitCaptureOpcodes(raw_ostream &OS); -void emit(raw_ostream &OS, SubtargetFeatureInfoMap SubtargetFeatures); + void emit(raw_ostream &OS); -/// Compare the priority of this object and B. -/// -/// Returns true if this object is more important than B. -bool isHigherPriorityThan(const RuleMatcher &B) const; + /// Compare the priority of this object and B. + /// + /// Returns true if this object is more important than B. + bool isHigherPriorityThan(const RuleMatcher &B) const; -/// Report the maximum number of temporary operands needed by the rule -/// matcher. -unsigned countRendererFns() const; + /// Report the maximum number of temporary operands needed by the rule + /// matcher. + unsigned countRendererFns() const; -// FIXME: Remove this as soon as possible -InstructionMatcher &insnmatcher_front() const { return *Matchers.front(); } + // FIXME: Remove this as soon as possible + InstructionMatcher &insnmatcher_front() const { return *Matchers.front(); } }; template <class PredicateTy> class PredicateListMatcher { @@ -255,21 +307,16 @@ public: return Predicates.size(); } - /// Emit a C++ expression that tests whether all the predicates are met. + /// Emit MatchTable opcodes that tests whether all the predicates are met. template <class... Args> - void emitCxxPredicateListExpr(raw_ostream &OS, Args &&... args) const { + void emitPredicateListOpcodes(raw_ostream &OS, Args &&... args) const { if (Predicates.empty()) { - OS << "true"; + OS << "// No predicates\n"; return; } - StringRef Separator = ""; - for (const auto &Predicate : predicates()) { - OS << Separator << "("; - Predicate->emitCxxPredicateExpr(OS, std::forward<Args>(args)...); - OS << ")"; - Separator = " &&\n"; - } + for (const auto &Predicate : predicates()) + Predicate->emitPredicateOpcodes(OS, std::forward<Args>(args)...); } }; @@ -291,6 +338,7 @@ public: enum PredicateKind { OPM_ComplexPattern, OPM_Instruction, + OPM_IntrinsicID, OPM_Int, OPM_LiteralInt, OPM_LLT, @@ -318,15 +366,17 @@ public: return None; } - /// Emit C++ statements to capture instructions into local variables. + /// Emit MatchTable opcodes to capture instructions into the MIs table. /// - /// Only InstructionOperandMatcher needs to do anything for this method. - virtual void emitCxxCaptureStmts(raw_ostream &OS, RuleMatcher &Rule, - StringRef Expr) const {} + /// Only InstructionOperandMatcher needs to do anything for this method the + /// rest just walk the tree. + virtual void emitCaptureOpcodes(raw_ostream &OS, RuleMatcher &Rule, + unsigned InsnVarID, unsigned OpIdx) const {} - /// Emit a C++ expression that checks the predicate for the given operand. - virtual void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule, - StringRef OperandExpr) const = 0; + /// Emit MatchTable opcodes that check the predicate for the given operand. + virtual void emitPredicateOpcodes(raw_ostream &OS, RuleMatcher &Rule, + unsigned InsnVarID, + unsigned OpIdx) const = 0; /// Compare the priority of this object and B. /// @@ -353,11 +403,12 @@ public: return P->getKind() == OPM_LLT; } - void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule, - StringRef OperandExpr) const override { - OS << "MRI.getType(" << OperandExpr << ".getReg()) == ("; - Ty.emitCxxConstructorCall(OS); - OS << ")"; + void emitPredicateOpcodes(raw_ostream &OS, RuleMatcher &Rule, + unsigned InsnVarID, unsigned OpIdx) const override { + OS << " GIM_CheckType, /*MI*/" << InsnVarID << ", /*Op*/" << OpIdx + << ", /*Type*/"; + Ty.emitCxxEnumValue(OS); + OS << ", \n"; } }; @@ -379,11 +430,12 @@ public: return P->getKind() == OPM_ComplexPattern; } - void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule, - StringRef OperandExpr) const override { + void emitPredicateOpcodes(raw_ostream &OS, RuleMatcher &Rule, + unsigned InsnVarID, unsigned OpIdx) const override { unsigned ID = getAllocatedTemporariesBaseID(); - OS << "(Renderer" << ID << " = " << TheDef.getValueAsString("MatcherFn") - << "(" << OperandExpr << "))"; + OS << " GIM_CheckComplexPattern, /*MI*/" << InsnVarID << ", /*Op*/" + << OpIdx << ", /*Renderer*/" << ID << ", GICP_" + << TheDef.getName() << ",\n"; } unsigned countRendererFns() const override { @@ -404,11 +456,10 @@ public: return P->getKind() == OPM_RegBank; } - void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule, - StringRef OperandExpr) const override { - OS << "(&RBI.getRegBankFromRegClass(" << RC.getQualifiedName() - << "RegClass) == RBI.getRegBank(" << OperandExpr - << ".getReg(), MRI, TRI))"; + void emitPredicateOpcodes(raw_ostream &OS, RuleMatcher &Rule, + unsigned InsnVarID, unsigned OpIdx) const override { + OS << " GIM_CheckRegBankForClass, /*MI*/" << InsnVarID << ", /*Op*/" + << OpIdx << ", /*RC*/" << RC.getQualifiedName() << "RegClassID,\n"; } }; @@ -421,9 +472,9 @@ public: return P->getKind() == OPM_MBB; } - void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule, - StringRef OperandExpr) const override { - OS << OperandExpr << ".isMBB()"; + void emitPredicateOpcodes(raw_ostream &OS, RuleMatcher &Rule, + unsigned InsnVarID, unsigned OpIdx) const override { + OS << " GIM_CheckIsMBB, /*MI*/" << InsnVarID << ", /*Op*/" << OpIdx << ",\n"; } }; @@ -441,9 +492,10 @@ public: return P->getKind() == OPM_Int; } - void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule, - StringRef OperandExpr) const override { - OS << "isOperandImmEqual(" << OperandExpr << ", " << Value << ", MRI)"; + void emitPredicateOpcodes(raw_ostream &OS, RuleMatcher &Rule, + unsigned InsnVarID, unsigned OpIdx) const override { + OS << " GIM_CheckConstantInt, /*MI*/" << InsnVarID << ", /*Op*/" + << OpIdx << ", " << Value << ",\n"; } }; @@ -461,10 +513,30 @@ public: return P->getKind() == OPM_LiteralInt; } - void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule, - StringRef OperandExpr) const override { - OS << OperandExpr << ".isCImm() && " << OperandExpr - << ".getCImm()->equalsInt(" << Value << ")"; + void emitPredicateOpcodes(raw_ostream &OS, RuleMatcher &Rule, + unsigned InsnVarID, unsigned OpIdx) const override { + OS << " GIM_CheckLiteralInt, /*MI*/" << InsnVarID << ", /*Op*/" + << OpIdx << ", " << Value << ",\n"; + } +}; + +/// Generates code to check that an operand is an intrinsic ID. +class IntrinsicIDOperandMatcher : public OperandPredicateMatcher { +protected: + const CodeGenIntrinsic *II; + +public: + IntrinsicIDOperandMatcher(const CodeGenIntrinsic *II) + : OperandPredicateMatcher(OPM_IntrinsicID), II(II) {} + + static bool classof(const OperandPredicateMatcher *P) { + return P->getKind() == OPM_IntrinsicID; + } + + void emitPredicateOpcodes(raw_ostream &OS, RuleMatcher &Rule, + unsigned InsnVarID, unsigned OpIdx) const override { + OS << " GIM_CheckIntrinsicID, /*MI*/" << InsnVarID << ", /*Op*/" + << OpIdx << ", Intrinsic::" << II->EnumName << ",\n"; } }; @@ -496,8 +568,9 @@ public: } unsigned getOperandIndex() const { return OpIdx; } - std::string getOperandExpr(StringRef InsnVarName) const { - return (InsnVarName + ".getOperand(" + llvm::to_string(OpIdx) + ")").str(); + std::string getOperandExpr(unsigned InsnVarID) const { + return "State.MIs[" + llvm::to_string(InsnVarID) + "]->getOperand(" + + llvm::to_string(OpIdx) + ")"; } Optional<const OperandMatcher *> @@ -515,25 +588,24 @@ public: InstructionMatcher &getInstructionMatcher() const { return Insn; } - /// Emit C++ statements to capture instructions into local variables. - void emitCxxCaptureStmts(raw_ostream &OS, RuleMatcher &Rule, - StringRef OperandExpr) const { + /// Emit MatchTable opcodes to capture instructions into the MIs table. + void emitCaptureOpcodes(raw_ostream &OS, RuleMatcher &Rule, + unsigned InsnVarID) const { for (const auto &Predicate : predicates()) - Predicate->emitCxxCaptureStmts(OS, Rule, OperandExpr); + Predicate->emitCaptureOpcodes(OS, Rule, InsnVarID, OpIdx); } - /// Emit a C++ expression that tests whether the instruction named in - /// InsnVarName matches all the predicate and all the operands. - void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule, - StringRef InsnVarName) const { - OS << "(/* "; + /// Emit MatchTable opcodes that test whether the instruction named in + /// InsnVarID matches all the predicates and all the operands. + void emitPredicateOpcodes(raw_ostream &OS, RuleMatcher &Rule, + unsigned InsnVarID) const { + OS << " // MIs[" << InsnVarID << "] "; if (SymbolicName.empty()) OS << "Operand " << OpIdx; else OS << SymbolicName; - OS << " */ "; - emitCxxPredicateListExpr(OS, Rule, getOperandExpr(InsnVarName)); - OS << ")"; + OS << "\n"; + emitPredicateListOpcodes(OS, Rule, InsnVarID, OpIdx); } /// Compare the priority of this object and B. @@ -599,10 +671,10 @@ public: PredicateKind getKind() const { return Kind; } - /// Emit a C++ expression that tests whether the instruction named in - /// InsnVarName matches the predicate. - virtual void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule, - StringRef InsnVarName) const = 0; + /// Emit MatchTable opcodes that test whether the instruction named in + /// InsnVarID matches the predicate. + virtual void emitPredicateOpcodes(raw_ostream &OS, RuleMatcher &Rule, + unsigned InsnVarID) const = 0; /// Compare the priority of this object and B. /// @@ -630,10 +702,10 @@ public: return P->getKind() == IPM_Opcode; } - void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule, - StringRef InsnVarName) const override { - OS << InsnVarName << ".getOpcode() == " << I->Namespace - << "::" << I->TheDef->getName(); + void emitPredicateOpcodes(raw_ostream &OS, RuleMatcher &Rule, + unsigned InsnVarID) const override { + OS << " GIM_CheckOpcode, /*MI*/" << InsnVarID << ", " << I->Namespace + << "::" << I->TheDef->getName() << ",\n"; } /// Compare the priority of this object and B. @@ -721,26 +793,23 @@ public: return make_range(operands_begin(), operands_end()); } - /// Emit C++ statements to check the shape of the match and capture - /// instructions into local variables. - void emitCxxCaptureStmts(raw_ostream &OS, RuleMatcher &Rule, StringRef Expr) { - OS << "if (" << Expr << ".getNumOperands() < " << getNumOperands() << ")\n" - << " return false;\n"; - for (const auto &Operand : Operands) { - Operand->emitCxxCaptureStmts(OS, Rule, Operand->getOperandExpr(Expr)); - } + /// Emit MatchTable opcodes to check the shape of the match and capture + /// instructions into the MIs table. + void emitCaptureOpcodes(raw_ostream &OS, RuleMatcher &Rule, + unsigned InsnID) { + OS << " GIM_CheckNumOperands, /*MI*/" << InsnID << ", /*Expected*/" + << getNumOperands() << ",\n"; + for (const auto &Operand : Operands) + Operand->emitCaptureOpcodes(OS, Rule, InsnID); } - /// Emit a C++ expression that tests whether the instruction named in + /// Emit MatchTable opcodes that test whether the instruction named in /// InsnVarName matches all the predicates and all the operands. - void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule, - StringRef InsnVarName) const { - emitCxxPredicateListExpr(OS, Rule, InsnVarName); - for (const auto &Operand : Operands) { - OS << " &&\n("; - Operand->emitCxxPredicateExpr(OS, Rule, InsnVarName); - OS << ")"; - } + void emitPredicateOpcodes(raw_ostream &OS, RuleMatcher &Rule, + unsigned InsnVarID) const { + emitPredicateListOpcodes(OS, Rule, InsnVarID); + for (const auto &Operand : Operands) + Operand->emitPredicateOpcodes(OS, Rule, InsnVarID); } /// Compare the priority of this object and B. @@ -817,24 +886,17 @@ public: return InsnMatcher->getOptionalOperand(SymbolicName); } - void emitCxxCaptureStmts(raw_ostream &OS, RuleMatcher &Rule, - StringRef OperandExpr) const override { - OS << "if (!" << OperandExpr + ".isReg())\n" - << " return false;\n" - << "if (TRI.isPhysicalRegister(" << OperandExpr + ".getReg()))\n" - << " return false;\n"; - std::string InsnVarName = Rule.defineInsnVar( - OS, *InsnMatcher, - ("*MRI.getVRegDef(" + OperandExpr + ".getReg())").str()); - InsnMatcher->emitCxxCaptureStmts(OS, Rule, InsnVarName); + void emitCaptureOpcodes(raw_ostream &OS, RuleMatcher &Rule, + unsigned InsnID, unsigned OpIdx) const override { + unsigned InsnVarID = Rule.defineInsnVar(OS, *InsnMatcher, InsnID, OpIdx); + InsnMatcher->emitCaptureOpcodes(OS, Rule, InsnVarID); } - void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule, - StringRef OperandExpr) const override { - OperandExpr = Rule.getInsnVarName(*InsnMatcher); - OS << "("; - InsnMatcher->emitCxxPredicateExpr(OS, Rule, OperandExpr); - OS << ")\n"; + void emitPredicateOpcodes(raw_ostream &OS, RuleMatcher &Rule, + unsigned InsnVarID_, + unsigned OpIdx_) const override { + unsigned InsnVarID = Rule.getInsnVarID(*InsnMatcher); + InsnMatcher->emitPredicateOpcodes(OS, Rule, InsnVarID); } }; @@ -858,13 +920,14 @@ public: RendererKind getKind() const { return Kind; } - virtual void emitCxxRenderStmts(raw_ostream &OS, RuleMatcher &Rule) const = 0; + virtual void emitRenderOpcodes(raw_ostream &OS, RuleMatcher &Rule) const = 0; }; /// A CopyRenderer emits code to copy a single operand from an existing /// instruction to the one being built. class CopyRenderer : public OperandRenderer { protected: + unsigned NewInsnID; /// The matcher for the instruction that this operand is copied from. /// This provides the facility for looking up an a operand by it's name so /// that it can be used as a source for the instruction being built. @@ -873,9 +936,10 @@ protected: const StringRef SymbolicName; public: - CopyRenderer(const InstructionMatcher &Matched, StringRef SymbolicName) - : OperandRenderer(OR_Copy), Matched(Matched), SymbolicName(SymbolicName) { - } + CopyRenderer(unsigned NewInsnID, const InstructionMatcher &Matched, + StringRef SymbolicName) + : OperandRenderer(OR_Copy), NewInsnID(NewInsnID), Matched(Matched), + SymbolicName(SymbolicName) {} static bool classof(const OperandRenderer *R) { return R->getKind() == OR_Copy; @@ -883,12 +947,12 @@ public: const StringRef getSymbolicName() const { return SymbolicName; } - void emitCxxRenderStmts(raw_ostream &OS, RuleMatcher &Rule) const override { + void emitRenderOpcodes(raw_ostream &OS, RuleMatcher &Rule) const override { const OperandMatcher &Operand = Matched.getOperand(SymbolicName); - StringRef InsnVarName = - Rule.getInsnVarName(Operand.getInstructionMatcher()); - std::string OperandExpr = Operand.getOperandExpr(InsnVarName); - OS << " MIB.add(" << OperandExpr << "/*" << SymbolicName << "*/);\n"; + unsigned OldInsnVarID = Rule.getInsnVarID(Operand.getInstructionMatcher()); + OS << " GIR_Copy, /*NewInsnID*/" << NewInsnID << ", /*OldInsnID*/" + << OldInsnVarID << ", /*OpIdx*/" << Operand.getOperandIndex() << ", // " + << SymbolicName << "\n"; } }; @@ -897,6 +961,7 @@ public: /// subregister should be copied. class CopySubRegRenderer : public OperandRenderer { protected: + unsigned NewInsnID; /// The matcher for the instruction that this operand is copied from. /// This provides the facility for looking up an a operand by it's name so /// that it can be used as a source for the instruction being built. @@ -907,9 +972,9 @@ protected: const CodeGenSubRegIndex *SubReg; public: - CopySubRegRenderer(const InstructionMatcher &Matched, StringRef SymbolicName, - const CodeGenSubRegIndex *SubReg) - : OperandRenderer(OR_CopySubReg), Matched(Matched), + CopySubRegRenderer(unsigned NewInsnID, const InstructionMatcher &Matched, + StringRef SymbolicName, const CodeGenSubRegIndex *SubReg) + : OperandRenderer(OR_CopySubReg), NewInsnID(NewInsnID), Matched(Matched), SymbolicName(SymbolicName), SubReg(SubReg) {} static bool classof(const OperandRenderer *R) { @@ -918,13 +983,13 @@ public: const StringRef getSymbolicName() const { return SymbolicName; } - void emitCxxRenderStmts(raw_ostream &OS, RuleMatcher &Rule) const override { + void emitRenderOpcodes(raw_ostream &OS, RuleMatcher &Rule) const override { const OperandMatcher &Operand = Matched.getOperand(SymbolicName); - StringRef InsnVarName = - Rule.getInsnVarName(Operand.getInstructionMatcher()); - std::string OperandExpr = Operand.getOperandExpr(InsnVarName); - OS << " MIB.addReg(" << OperandExpr << ".getReg() /*" << SymbolicName - << "*/, 0, " << SubReg->EnumValue << ");\n"; + unsigned OldInsnVarID = Rule.getInsnVarID(Operand.getInstructionMatcher()); + OS << " GIR_CopySubReg, /*NewInsnID*/" << NewInsnID + << ", /*OldInsnID*/" << OldInsnVarID << ", /*OpIdx*/" + << Operand.getOperandIndex() << ", /*SubRegIdx*/" << SubReg->EnumValue + << ", // " << SymbolicName << "\n"; } }; @@ -932,39 +997,44 @@ public: /// This is typically useful for WZR/XZR on AArch64. class AddRegisterRenderer : public OperandRenderer { protected: + unsigned InsnID; const Record *RegisterDef; public: - AddRegisterRenderer(const Record *RegisterDef) - : OperandRenderer(OR_Register), RegisterDef(RegisterDef) {} + AddRegisterRenderer(unsigned InsnID, const Record *RegisterDef) + : OperandRenderer(OR_Register), InsnID(InsnID), RegisterDef(RegisterDef) { + } static bool classof(const OperandRenderer *R) { return R->getKind() == OR_Register; } - void emitCxxRenderStmts(raw_ostream &OS, RuleMatcher &Rule) const override { - OS << " MIB.addReg(" << (RegisterDef->getValue("Namespace") - ? RegisterDef->getValueAsString("Namespace") - : "") - << "::" << RegisterDef->getName() << ");\n"; + void emitRenderOpcodes(raw_ostream &OS, RuleMatcher &Rule) const override { + OS << " GIR_AddRegister, /*InsnID*/" << InsnID << ", " + << (RegisterDef->getValue("Namespace") + ? RegisterDef->getValueAsString("Namespace") + : "") + << "::" << RegisterDef->getName() << ",\n"; } }; /// Adds a specific immediate to the instruction being built. class ImmRenderer : public OperandRenderer { protected: + unsigned InsnID; int64_t Imm; public: - ImmRenderer(int64_t Imm) - : OperandRenderer(OR_Imm), Imm(Imm) {} + ImmRenderer(unsigned InsnID, int64_t Imm) + : OperandRenderer(OR_Imm), InsnID(InsnID), Imm(Imm) {} static bool classof(const OperandRenderer *R) { return R->getKind() == OR_Imm; } - void emitCxxRenderStmts(raw_ostream &OS, RuleMatcher &Rule) const override { - OS << " MIB.addImm(" << Imm << ");\n"; + void emitRenderOpcodes(raw_ostream &OS, RuleMatcher &Rule) const override { + OS << " GIR_AddImm, /*InsnID*/" << InsnID << ", /*Imm*/" << Imm + << ",\n"; } }; @@ -972,6 +1042,7 @@ public: /// matcher function. class RenderComplexPatternOperand : public OperandRenderer { private: + unsigned InsnID; const Record &TheDef; /// The name of the operand. const StringRef SymbolicName; @@ -984,17 +1055,18 @@ private: } public: - RenderComplexPatternOperand(const Record &TheDef, StringRef SymbolicName, - unsigned RendererID) - : OperandRenderer(OR_ComplexPattern), TheDef(TheDef), + RenderComplexPatternOperand(unsigned InsnID, const Record &TheDef, + StringRef SymbolicName, unsigned RendererID) + : OperandRenderer(OR_ComplexPattern), InsnID(InsnID), TheDef(TheDef), SymbolicName(SymbolicName), RendererID(RendererID) {} static bool classof(const OperandRenderer *R) { return R->getKind() == OR_ComplexPattern; } - void emitCxxRenderStmts(raw_ostream &OS, RuleMatcher &Rule) const override { - OS << "Renderer" << RendererID << "(MIB);\n"; + void emitRenderOpcodes(raw_ostream &OS, RuleMatcher &Rule) const override { + OS << " GIR_ComplexRenderer, /*InsnID*/" << InsnID << ", /*RendererID*/" + << RendererID << ",\n"; } }; @@ -1009,11 +1081,11 @@ public: /// Emit the C++ statements to implement the action. /// - /// \param RecycleVarName If given, it's an instruction to recycle. The - /// requirements on the instruction vary from action to - /// action. + /// \param RecycleInsnID If given, it's an instruction to recycle. The + /// requirements on the instruction vary from action to + /// action. virtual void emitCxxActionStmts(raw_ostream &OS, RuleMatcher &Rule, - StringRef RecycleVarName) const = 0; + unsigned RecycleInsnID) const = 0; }; /// Generates a comment describing the matched rule being acted upon. @@ -1025,8 +1097,9 @@ public: DebugCommentAction(const PatternToMatch &P) : P(P) {} void emitCxxActionStmts(raw_ostream &OS, RuleMatcher &Rule, - StringRef RecycleVarName) const override { - OS << "// " << *P.getSrcPattern() << " => " << *P.getDstPattern() << "\n"; + unsigned RecycleInsnID) const override { + OS << " // " << *P.getSrcPattern() << " => " << *P.getDstPattern() + << "\n"; } }; @@ -1034,7 +1107,7 @@ public: /// into the desired instruction when this is possible. class BuildMIAction : public MatchAction { private: - std::string Name; + unsigned InsnID; const CodeGenInstruction *I; const InstructionMatcher &Matched; std::vector<std::unique_ptr<OperandRenderer>> OperandRenderers; @@ -1058,9 +1131,9 @@ private: } public: - BuildMIAction(const StringRef Name, const CodeGenInstruction *I, + BuildMIAction(unsigned InsnID, const CodeGenInstruction *I, const InstructionMatcher &Matched) - : Name(Name), I(I), Matched(Matched) {} + : InsnID(InsnID), I(I), Matched(Matched) {} template <class Kind, class... Args> Kind &addRenderer(Args&&... args) { @@ -1070,84 +1143,74 @@ public: } void emitCxxActionStmts(raw_ostream &OS, RuleMatcher &Rule, - StringRef RecycleVarName) const override { + unsigned RecycleInsnID) const override { if (canMutate()) { - OS << " " << RecycleVarName << ".setDesc(TII.get(" << I->Namespace - << "::" << I->TheDef->getName() << "));\n"; + OS << " GIR_MutateOpcode, /*InsnID*/" << InsnID + << ", /*RecycleInsnID*/ " << RecycleInsnID << ", /*Opcode*/" + << I->Namespace << "::" << I->TheDef->getName() << ",\n"; if (!I->ImplicitDefs.empty() || !I->ImplicitUses.empty()) { - OS << " auto MIB = MachineInstrBuilder(MF, &" << RecycleVarName - << ");\n"; - for (auto Def : I->ImplicitDefs) { auto Namespace = Def->getValue("Namespace") ? Def->getValueAsString("Namespace") : ""; - OS << " MIB.addDef(" << Namespace << "::" << Def->getName() - << ", RegState::Implicit);\n"; + OS << " GIR_AddImplicitDef, " << InsnID << ", " << Namespace + << "::" << Def->getName() << ",\n"; } for (auto Use : I->ImplicitUses) { auto Namespace = Use->getValue("Namespace") ? Use->getValueAsString("Namespace") : ""; - OS << " MIB.addUse(" << Namespace << "::" << Use->getName() - << ", RegState::Implicit);\n"; + OS << " GIR_AddImplicitUse, " << InsnID << ", " << Namespace + << "::" << Use->getName() << ",\n"; } } - - OS << " MachineInstr &" << Name << " = " << RecycleVarName << ";\n"; return; } // TODO: Simple permutation looks like it could be almost as common as // mutation due to commutative operations. - OS << "MachineInstrBuilder MIB = BuildMI(*I.getParent(), I, " - "I.getDebugLoc(), TII.get(" - << I->Namespace << "::" << I->TheDef->getName() << "));\n"; + OS << " GIR_BuildMI, /*InsnID*/" << InsnID << ", /*Opcode*/" + << I->Namespace << "::" << I->TheDef->getName() << ",\n"; for (const auto &Renderer : OperandRenderers) - Renderer->emitCxxRenderStmts(OS, Rule); - OS << " for (const auto *FromMI : "; - Rule.emitCxxCapturedInsnList(OS); - OS << ")\n"; - OS << " for (const auto &MMO : FromMI->memoperands())\n"; - OS << " MIB.addMemOperand(MMO);\n"; - OS << " " << RecycleVarName << ".eraseFromParent();\n"; - OS << " MachineInstr &" << Name << " = *MIB;\n"; + Renderer->emitRenderOpcodes(OS, Rule); + + OS << " GIR_MergeMemOperands, /*InsnID*/" << InsnID << ",\n" + << " GIR_EraseFromParent, /*InsnID*/" << RecycleInsnID << ",\n"; } }; /// Generates code to constrain the operands of an output instruction to the /// register classes specified by the definition of that instruction. class ConstrainOperandsToDefinitionAction : public MatchAction { - std::string Name; + unsigned InsnID; public: - ConstrainOperandsToDefinitionAction(const StringRef Name) : Name(Name) {} + ConstrainOperandsToDefinitionAction(unsigned InsnID) : InsnID(InsnID) {} void emitCxxActionStmts(raw_ostream &OS, RuleMatcher &Rule, - StringRef RecycleVarName) const override { - OS << " constrainSelectedInstRegOperands(" << Name - << ", TII, TRI, RBI);\n"; + unsigned RecycleInsnID) const override { + OS << " GIR_ConstrainSelectedInstOperands, /*InsnID*/" << InsnID << ",\n"; } }; /// Generates code to constrain the specified operand of an output instruction /// to the specified register class. class ConstrainOperandToRegClassAction : public MatchAction { - std::string Name; + unsigned InsnID; unsigned OpIdx; const CodeGenRegisterClass &RC; public: - ConstrainOperandToRegClassAction(const StringRef Name, unsigned OpIdx, + ConstrainOperandToRegClassAction(unsigned InsnID, unsigned OpIdx, const CodeGenRegisterClass &RC) - : Name(Name), OpIdx(OpIdx), RC(RC) {} + : InsnID(InsnID), OpIdx(OpIdx), RC(RC) {} void emitCxxActionStmts(raw_ostream &OS, RuleMatcher &Rule, - StringRef RecycleVarName) const override { - OS << " constrainOperandRegToRegClass(" << Name << ", " << OpIdx - << ", " << RC.getQualifiedName() << "RegClass, TII, TRI, RBI);\n"; + unsigned RecycleInsnID) const override { + OS << " GIR_ConstrainOperandRC, /*InsnID*/" << InsnID << ", /*Op*/" + << OpIdx << ", /*RC " << RC.getName() << "*/ " << RC.EnumValue << ",\n"; } }; @@ -1160,53 +1223,49 @@ void RuleMatcher::addRequiredFeature(Record *Feature) { RequiredFeatures.push_back(Feature); } +const std::vector<Record *> &RuleMatcher::getRequiredFeatures() const { + return RequiredFeatures; +} + template <class Kind, class... Args> Kind &RuleMatcher::addAction(Args &&... args) { Actions.emplace_back(llvm::make_unique<Kind>(std::forward<Args>(args)...)); return *static_cast<Kind *>(Actions.back().get()); } -std::string RuleMatcher::defineInsnVar(raw_ostream &OS, - const InstructionMatcher &Matcher, - StringRef Value) { - std::string InsnVarName = "MI" + llvm::to_string(NextInsnVarID++); - OS << "MachineInstr &" << InsnVarName << " = " << Value << ";\n"; - InsnVariableNames[&Matcher] = InsnVarName; - return InsnVarName; +unsigned +RuleMatcher::implicitlyDefineInsnVar(const InstructionMatcher &Matcher) { + unsigned NewInsnVarID = NextInsnVarID++; + InsnVariableIDs[&Matcher] = NewInsnVarID; + return NewInsnVarID; } -StringRef -RuleMatcher::getInsnVarName(const InstructionMatcher &InsnMatcher) const { - const auto &I = InsnVariableNames.find(&InsnMatcher); - if (I != InsnVariableNames.end()) - return I->second; - llvm_unreachable("Matched Insn was not captured in a local variable"); +unsigned RuleMatcher::defineInsnVar(raw_ostream &OS, + const InstructionMatcher &Matcher, + unsigned InsnID, unsigned OpIdx) { + unsigned NewInsnVarID = implicitlyDefineInsnVar(Matcher); + OS << " GIM_RecordInsn, /*DefineMI*/" << NewInsnVarID << ", /*MI*/" + << InsnID << ", /*OpIdx*/" << OpIdx << ", // MIs[" << NewInsnVarID + << "]\n"; + return NewInsnVarID; } -/// Emit a C++ initializer_list containing references to every matched -/// instruction. -void RuleMatcher::emitCxxCapturedInsnList(raw_ostream &OS) { - SmallVector<StringRef, 2> Names; - for (const auto &Pair : InsnVariableNames) - Names.push_back(Pair.second); - std::sort(Names.begin(), Names.end()); - - OS << "{"; - for (const auto &Name : Names) - OS << "&" << Name << ", "; - OS << "}"; +unsigned RuleMatcher::getInsnVarID(const InstructionMatcher &InsnMatcher) const { + const auto &I = InsnVariableIDs.find(&InsnMatcher); + if (I != InsnVariableIDs.end()) + return I->second; + llvm_unreachable("Matched Insn was not captured in a local variable"); } -/// Emit C++ statements to check the shape of the match and capture +/// Emit MatchTable opcodes to check the shape of the match and capture /// instructions into local variables. -void RuleMatcher::emitCxxCaptureStmts(raw_ostream &OS, StringRef Expr) { +void RuleMatcher::emitCaptureOpcodes(raw_ostream &OS) { assert(Matchers.size() == 1 && "Cannot handle multi-root matchers yet"); - std::string InsnVarName = defineInsnVar(OS, *Matchers.front(), Expr); - Matchers.front()->emitCxxCaptureStmts(OS, *this, InsnVarName); + unsigned InsnVarID = implicitlyDefineInsnVar(*Matchers.front()); + Matchers.front()->emitCaptureOpcodes(OS, *this, InsnVarID); } -void RuleMatcher::emit(raw_ostream &OS, - SubtargetFeatureInfoMap SubtargetFeatures) { +void RuleMatcher::emit(raw_ostream &OS) { if (Matchers.empty()) llvm_unreachable("Unexpected empty matcher!"); @@ -1221,47 +1280,34 @@ void RuleMatcher::emit(raw_ostream &OS, // on some targets but we don't need to make use of that yet. assert(Matchers.size() == 1 && "Cannot handle multi-root matchers yet"); - OS << "if ("; - OS << "[&]() {\n"; + OS << " const static int64_t MatchTable" << CurrentMatchTableID << "[] = {\n"; if (!RequiredFeatures.empty()) { - OS << " PredicateBitset ExpectedFeatures = {"; - StringRef Separator = ""; - for (const auto &Predicate : RequiredFeatures) { - const auto &I = SubtargetFeatures.find(Predicate); - assert(I != SubtargetFeatures.end() && "Didn't import predicate?"); - OS << Separator << I->second.getEnumBitName(); - Separator = ", "; - } - OS << "};\n"; - OS << "if ((AvailableFeatures & ExpectedFeatures) != ExpectedFeatures)\n" - << " return false;\n"; + OS << " GIM_CheckFeatures, " << getNameForFeatureBitset(RequiredFeatures) + << ",\n"; } - emitCxxCaptureStmts(OS, "I"); + emitCaptureOpcodes(OS); - OS << " if ("; - Matchers.front()->emitCxxPredicateExpr(OS, *this, - getInsnVarName(*Matchers.front())); - OS << ") {\n"; + Matchers.front()->emitPredicateOpcodes(OS, *this, + getInsnVarID(*Matchers.front())); // We must also check if it's safe to fold the matched instructions. - if (InsnVariableNames.size() >= 2) { + if (InsnVariableIDs.size() >= 2) { // Invert the map to create stable ordering (by var names) - SmallVector<StringRef, 2> Names; - for (const auto &Pair : InsnVariableNames) { + SmallVector<unsigned, 2> InsnIDs; + for (const auto &Pair : InsnVariableIDs) { // Skip the root node since it isn't moving anywhere. Everything else is // sinking to meet it. if (Pair.first == Matchers.front().get()) continue; - Names.push_back(Pair.second); + InsnIDs.push_back(Pair.second); } - std::sort(Names.begin(), Names.end()); + std::sort(InsnIDs.begin(), InsnIDs.end()); - for (const auto &Name : Names) { + for (const auto &InsnID : InsnIDs) { // Reject the difficult cases until we have a more accurate check. - OS << " if (!isObviouslySafeToFold(" << Name - << ")) return false;\n"; + OS << " GIM_CheckIsSafeToFold, /*InsnID*/" << InsnID << ",\n"; // FIXME: Emit checks to determine it's _actually_ safe to fold and/or // account for unsafe cases. @@ -1300,14 +1346,17 @@ void RuleMatcher::emit(raw_ostream &OS, } } - for (const auto &MA : Actions) { - MA->emitCxxActionStmts(OS, *this, "I"); - } - - OS << " return true;\n"; - OS << " }\n"; - OS << " return false;\n"; - OS << " }()) { return true; }\n\n"; + for (const auto &MA : Actions) + MA->emitCxxActionStmts(OS, *this, 0); + OS << " GIR_Done,\n" + << " };\n" + << " State.MIs.resize(1);\n" + << " DEBUG(dbgs() << \"Processing MatchTable" << CurrentMatchTableID + << "\\n\");\n" + << " if (executeMatchTable(*this, OutMIs, State, MatcherInfo, MatchTable" + << CurrentMatchTableID << ", TII, MRI, TRI, RBI, AvailableFeatures)) {\n" + << " return true;\n" + << " }\n\n"; } bool RuleMatcher::isHigherPriorityThan(const RuleMatcher &B) const { @@ -1366,7 +1415,8 @@ private: Error importRulePredicates(RuleMatcher &M, ArrayRef<Init *> Predicates); Expected<InstructionMatcher &> createAndImportSelDAGMatcher(InstructionMatcher &InsnMatcher, - const TreePatternNode *Src) const; + const TreePatternNode *Src, + unsigned &TempOpIdx) const; Error importChildMatcher(InstructionMatcher &InsnMatcher, const TreePatternNode *SrcChild, unsigned OpIdx, unsigned &TempOpIdx) const; @@ -1425,8 +1475,12 @@ GlobalISelEmitter::importRulePredicates(RuleMatcher &M, return Error::success(); } -Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher( - InstructionMatcher &InsnMatcher, const TreePatternNode *Src) const { +Expected<InstructionMatcher &> +GlobalISelEmitter::createAndImportSelDAGMatcher(InstructionMatcher &InsnMatcher, + const TreePatternNode *Src, + unsigned &TempOpIdx) const { + const CodeGenInstruction *SrcGIOrNull = nullptr; + // Start with the defined operands (i.e., the results of the root operator). if (Src->getExtTypes().size() > 1) return failedImport("Src pattern has multiple results"); @@ -1440,7 +1494,7 @@ Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher( return failedImport( "Unable to deduce gMIR opcode to handle Src (which is a leaf)"); } else { - auto SrcGIOrNull = findNodeEquiv(Src->getOperator()); + SrcGIOrNull = findNodeEquiv(Src->getOperator()); if (!SrcGIOrNull) return failedImport("Pattern operator lacks an equivalent Instruction" + explainOperator(Src->getOperator())); @@ -1451,7 +1505,6 @@ Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher( } unsigned OpIdx = 0; - unsigned TempOpIdx = 0; for (const EEVT::TypeSet &Ty : Src->getExtTypes()) { auto OpTyOrNone = MVTToLLT(Ty.getConcrete()); @@ -1474,10 +1527,27 @@ Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher( return failedImport( "Unable to deduce gMIR opcode to handle Src (which is a leaf)"); } else { + assert(SrcGIOrNull && + "Expected to have already found an equivalent Instruction"); // Match the used operands (i.e. the children of the operator). for (unsigned i = 0, e = Src->getNumChildren(); i != e; ++i) { - if (auto Error = importChildMatcher(InsnMatcher, Src->getChild(i), - OpIdx++, TempOpIdx)) + TreePatternNode *SrcChild = Src->getChild(i); + + // For G_INTRINSIC, the operand immediately following the defs is an + // intrinsic ID. + if (SrcGIOrNull->TheDef->getName() == "G_INTRINSIC" && i == 0) { + if (const CodeGenIntrinsic *II = Src->getIntrinsicInfo(CGP)) { + OperandMatcher &OM = + InsnMatcher.addOperand(OpIdx++, SrcChild->getName(), TempOpIdx); + OM.addPredicate<IntrinsicIDOperandMatcher>(II); + continue; + } + + return failedImport("Expected IntInit containing instrinsic ID)"); + } + + if (auto Error = + importChildMatcher(InsnMatcher, SrcChild, OpIdx++, TempOpIdx)) return std::move(Error); } } @@ -1513,7 +1583,7 @@ Error GlobalISelEmitter::importChildMatcher(InstructionMatcher &InsnMatcher, auto OpTyOrNone = MVTToLLT(ChildTypes.front().getConcrete()); if (!OpTyOrNone) - return failedImport("Src operand has an unsupported type"); + return failedImport("Src operand has an unsupported type (" + to_string(*SrcChild) + ")"); OM.addPredicate<LLTOperandMatcher>(*OpTyOrNone); // Check for nested instructions. @@ -1521,8 +1591,8 @@ Error GlobalISelEmitter::importChildMatcher(InstructionMatcher &InsnMatcher, // Map the node to a gMIR instruction. InstructionOperandMatcher &InsnOperand = OM.addPredicate<InstructionOperandMatcher>(); - auto InsnMatcherOrError = - createAndImportSelDAGMatcher(InsnOperand.getInsnMatcher(), SrcChild); + auto InsnMatcherOrError = createAndImportSelDAGMatcher( + InsnOperand.getInsnMatcher(), SrcChild, TempOpIdx); if (auto Error = InsnMatcherOrError.takeError()) return Error; @@ -1581,7 +1651,7 @@ Error GlobalISelEmitter::importExplicitUseRenderer( if (DstChild->getOperator()->isSubClassOf("SDNode")) { auto &ChildSDNI = CGP.getSDNodeInfo(DstChild->getOperator()); if (ChildSDNI.getSDClassName() == "BasicBlockSDNode") { - DstMIBuilder.addRenderer<CopyRenderer>(InsnMatcher, + DstMIBuilder.addRenderer<CopyRenderer>(0, InsnMatcher, DstChild->getName()); return Error::success(); } @@ -1606,13 +1676,14 @@ Error GlobalISelEmitter::importExplicitUseRenderer( return failedImport("Dst operand has an unsupported type"); if (ChildRec->isSubClassOf("Register")) { - DstMIBuilder.addRenderer<AddRegisterRenderer>(ChildRec); + DstMIBuilder.addRenderer<AddRegisterRenderer>(0, ChildRec); return Error::success(); } if (ChildRec->isSubClassOf("RegisterClass") || ChildRec->isSubClassOf("RegisterOperand")) { - DstMIBuilder.addRenderer<CopyRenderer>(InsnMatcher, DstChild->getName()); + DstMIBuilder.addRenderer<CopyRenderer>(0, InsnMatcher, + DstChild->getName()); return Error::success(); } @@ -1624,7 +1695,7 @@ Error GlobalISelEmitter::importExplicitUseRenderer( const OperandMatcher &OM = InsnMatcher.getOperand(DstChild->getName()); DstMIBuilder.addRenderer<RenderComplexPatternOperand>( - *ComplexPattern->second, DstChild->getName(), + 0, *ComplexPattern->second, DstChild->getName(), OM.getAllocatedTemporariesBaseID()); return Error::success(); } @@ -1667,12 +1738,12 @@ Expected<BuildMIAction &> GlobalISelEmitter::createAndImportInstructionRenderer( IsExtractSubReg = true; } - auto &DstMIBuilder = M.addAction<BuildMIAction>("NewI", DstI, InsnMatcher); + auto &DstMIBuilder = M.addAction<BuildMIAction>(0, DstI, InsnMatcher); // Render the explicit defs. for (unsigned I = 0; I < DstI->Operands.NumDefs; ++I) { const CGIOperandList::OperandInfo &DstIOperand = DstI->Operands[I]; - DstMIBuilder.addRenderer<CopyRenderer>(InsnMatcher, DstIOperand.Name); + DstMIBuilder.addRenderer<CopyRenderer>(0, InsnMatcher, DstIOperand.Name); } // EXTRACT_SUBREG needs to use a subregister COPY. @@ -1695,7 +1766,7 @@ Expected<BuildMIAction &> GlobalISelEmitter::createAndImportInstructionRenderer( } DstMIBuilder.addRenderer<CopySubRegRenderer>( - InsnMatcher, Dst->getChild(0)->getName(), SubIdx); + 0, InsnMatcher, Dst->getChild(0)->getName(), SubIdx); return DstMIBuilder; } @@ -1751,12 +1822,12 @@ Error GlobalISelEmitter::importDefaultOperandRenderers( } if (const DefInit *DefaultDefOp = dyn_cast<DefInit>(DefaultOp)) { - DstMIBuilder.addRenderer<AddRegisterRenderer>(DefaultDefOp->getDef()); + DstMIBuilder.addRenderer<AddRegisterRenderer>(0, DefaultDefOp->getDef()); continue; } if (const IntInit *DefaultIntOp = dyn_cast<IntInit>(DefaultOp)) { - DstMIBuilder.addRenderer<ImmRenderer>(DefaultIntOp->getValue()); + DstMIBuilder.addRenderer<ImmRenderer>(0, DefaultIntOp->getValue()); continue; } @@ -1809,7 +1880,9 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) { to_string(DstI.Operands.NumDefs) + " def(s))"); InstructionMatcher &InsnMatcherTemp = M.addInstructionMatcher(); - auto InsnMatcherOrError = createAndImportSelDAGMatcher(InsnMatcherTemp, Src); + unsigned TempOpIdx = 0; + auto InsnMatcherOrError = + createAndImportSelDAGMatcher(InsnMatcherTemp, Src, TempOpIdx); if (auto Error = InsnMatcherOrError.takeError()) return std::move(Error); InstructionMatcher &InsnMatcher = InsnMatcherOrError.get(); @@ -1875,7 +1948,7 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) { return failedImport("COPY_TO_REGCLASS operand #1 isn't a register class"); M.addAction<ConstrainOperandToRegClassAction>( - "NewI", 0, Target.getRegisterClass(DstIOpRec)); + 0, 0, Target.getRegisterClass(DstIOpRec)); // We're done with this pattern! It's eligible for GISel emission; return // it. @@ -1903,8 +1976,7 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) { return failedImport("EXTRACT_SUBREG operand #1 isn't a register class"); CodeGenSubRegIndex *SubIdx = CGRegs.getSubRegIdx(SubRegInit->getDef()); - CodeGenRegisterClass *SrcRC = CGRegs.getRegClass( - getInitValueAsRegClass(Dst->getChild(0)->getLeafValue())); + CodeGenRegisterClass *SrcRC = CGRegs.getRegClass(DstIOpRec); // It would be nice to leave this constraint implicit but we're required // to pick a register class so constrain the result to a register class @@ -1918,12 +1990,16 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) { const auto &SrcRCDstRCPair = SrcRC->getMatchingSubClassWithSubRegs(CGRegs, SubIdx); assert(SrcRCDstRCPair->second && "Couldn't find a matching subclass"); - M.addAction<ConstrainOperandToRegClassAction>("NewI", 0, - *SrcRCDstRCPair->second); - M.addAction<ConstrainOperandToRegClassAction>("NewI", 1, - *SrcRCDstRCPair->first); - } else - M.addAction<ConstrainOperandsToDefinitionAction>("NewI"); + M.addAction<ConstrainOperandToRegClassAction>(0, 0, *SrcRCDstRCPair->second); + M.addAction<ConstrainOperandToRegClassAction>(0, 1, *SrcRCDstRCPair->first); + + // We're done with this pattern! It's eligible for GISel emission; return + // it. + ++NumPatternImported; + return std::move(M); + } + + M.addAction<ConstrainOperandsToDefinitionAction>(0); // We're done with this pattern! It's eligible for GISel emission; return it. ++NumPatternImported; @@ -1969,6 +2045,14 @@ void GlobalISelEmitter::run(raw_ostream &OS) { return false; }); + std::vector<Record *> ComplexPredicates = + RK.getAllDerivedDefinitions("GIComplexOperandMatcher"); + std::sort(ComplexPredicates.begin(), ComplexPredicates.end(), + [](const Record *A, const Record *B) { + if (A->getName() < B->getName()) + return true; + return false; + }); unsigned MaxTemporaries = 0; for (const auto &Rule : Rules) MaxTemporaries = std::max(MaxTemporaries, Rule.countRendererFns()); @@ -1980,15 +2064,26 @@ void GlobalISelEmitter::run(raw_ostream &OS) { "llvm::PredicateBitsetImpl<MAX_SUBTARGET_PREDICATES>;\n" << "#endif // ifdef GET_GLOBALISEL_PREDICATE_BITSET\n\n"; - OS << "#ifdef GET_GLOBALISEL_TEMPORARIES_DECL\n"; - for (unsigned I = 0; I < MaxTemporaries; ++I) - OS << " mutable ComplexRendererFn Renderer" << I << ";\n"; - OS << "#endif // ifdef GET_GLOBALISEL_TEMPORARIES_DECL\n\n"; - - OS << "#ifdef GET_GLOBALISEL_TEMPORARIES_INIT\n"; - for (unsigned I = 0; I < MaxTemporaries; ++I) - OS << ", Renderer" << I << "(nullptr)\n"; - OS << "#endif // ifdef GET_GLOBALISEL_TEMPORARIES_INIT\n\n"; + OS << "#ifdef GET_GLOBALISEL_TEMPORARIES_DECL\n" + << " mutable MatcherState State;\n" + << " typedef " + "ComplexRendererFn(" + << Target.getName() + << "InstructionSelector::*ComplexMatcherMemFn)(MachineOperand &) const;\n" + << "const MatcherInfoTy<PredicateBitset, ComplexMatcherMemFn> " + "MatcherInfo;\n" + << "#endif // ifdef GET_GLOBALISEL_TEMPORARIES_DECL\n\n"; + + OS << "#ifdef GET_GLOBALISEL_TEMPORARIES_INIT\n" + << ", State(" << MaxTemporaries << "),\n" + << "MatcherInfo({TypeObjects, FeatureBitsets, {\n" + << " nullptr, // GICP_Invalid\n"; + for (const auto &Record : ComplexPredicates) + OS << " &" << Target.getName() + << "InstructionSelector::" << Record->getValueAsString("MatcherFn") + << ", // " << Record->getName() << "\n"; + OS << "}})\n" + << "#endif // ifdef GET_GLOBALISEL_TEMPORARIES_INIT\n\n"; OS << "#ifdef GET_GLOBALISEL_IMPL\n"; SubtargetFeatureInfo::emitSubtargetFeatureBitEnumeration(SubtargetFeatures, @@ -2016,19 +2111,107 @@ void GlobalISelEmitter::run(raw_ostream &OS) { "computeAvailableFunctionFeatures", FunctionFeatures, OS, "const MachineFunction *MF"); + // Emit a table containing the LLT objects needed by the matcher and an enum + // for the matcher to reference them with. + std::vector<LLTCodeGen> TypeObjects = { + LLT::scalar(8), LLT::scalar(16), LLT::scalar(32), + LLT::scalar(64), LLT::scalar(80), LLT::vector(8, 1), + LLT::vector(16, 1), LLT::vector(32, 1), LLT::vector(64, 1), + LLT::vector(8, 8), LLT::vector(16, 8), LLT::vector(32, 8), + LLT::vector(64, 8), LLT::vector(4, 16), LLT::vector(8, 16), + LLT::vector(16, 16), LLT::vector(32, 16), LLT::vector(2, 32), + LLT::vector(4, 32), LLT::vector(8, 32), LLT::vector(16, 32), + LLT::vector(2, 64), LLT::vector(4, 64), LLT::vector(8, 64), + }; + std::sort(TypeObjects.begin(), TypeObjects.end()); + OS << "enum {\n"; + for (const auto &TypeObject : TypeObjects) { + OS << " "; + TypeObject.emitCxxEnumValue(OS); + OS << ",\n"; + } + OS << "};\n" + << "const static LLT TypeObjects[] = {\n"; + for (const auto &TypeObject : TypeObjects) { + OS << " "; + TypeObject.emitCxxConstructorCall(OS); + OS << ",\n"; + } + OS << "};\n\n"; + + // Emit a table containing the PredicateBitsets objects needed by the matcher + // and an enum for the matcher to reference them with. + std::vector<std::vector<Record *>> FeatureBitsets; + for (auto &Rule : Rules) + FeatureBitsets.push_back(Rule.getRequiredFeatures()); + std::sort( + FeatureBitsets.begin(), FeatureBitsets.end(), + [&](const std::vector<Record *> &A, const std::vector<Record *> &B) { + if (A.size() < B.size()) + return true; + if (A.size() > B.size()) + return false; + for (const auto &Pair : zip(A, B)) { + if (std::get<0>(Pair)->getName() < std::get<1>(Pair)->getName()) + return true; + if (std::get<0>(Pair)->getName() > std::get<1>(Pair)->getName()) + return false; + } + return false; + }); + FeatureBitsets.erase( + std::unique(FeatureBitsets.begin(), FeatureBitsets.end()), + FeatureBitsets.end()); + OS << "enum {\n" + << " GIFBS_Invalid,\n"; + for (const auto &FeatureBitset : FeatureBitsets) { + if (FeatureBitset.empty()) + continue; + OS << " " << getNameForFeatureBitset(FeatureBitset) << ",\n"; + } + OS << "};\n" + << "const static PredicateBitset FeatureBitsets[] {\n" + << " {}, // GIFBS_Invalid\n"; + for (const auto &FeatureBitset : FeatureBitsets) { + if (FeatureBitset.empty()) + continue; + OS << " {"; + for (const auto &Feature : FeatureBitset) { + const auto &I = SubtargetFeatures.find(Feature); + assert(I != SubtargetFeatures.end() && "Didn't import predicate?"); + OS << I->second.getEnumBitName() << ", "; + } + OS << "},\n"; + } + OS << "};\n\n"; + + // Emit complex predicate table and an enum to reference them with. + OS << "enum {\n" + << " GICP_Invalid,\n"; + for (const auto &Record : ComplexPredicates) + OS << " GICP_" << Record->getName() << ",\n"; + OS << "};\n" + << "// See constructor for table contents\n\n"; + OS << "bool " << Target.getName() << "InstructionSelector::selectImpl(MachineInstr &I) const {\n" << " MachineFunction &MF = *I.getParent()->getParent();\n" - << " const MachineRegisterInfo &MRI = MF.getRegInfo();\n" + << " MachineRegisterInfo &MRI = MF.getRegInfo();\n" << " // FIXME: This should be computed on a per-function basis rather " "than per-insn.\n" << " AvailableFunctionFeatures = computeAvailableFunctionFeatures(&STI, " "&MF);\n" - << " const PredicateBitset AvailableFeatures = getAvailableFeatures();\n"; + << " const PredicateBitset AvailableFeatures = getAvailableFeatures();\n" + << " NewMIVector OutMIs;\n" + << " State.MIs.clear();\n" + << " State.MIs.push_back(&I);\n\n"; for (auto &Rule : Rules) { - Rule.emit(OS, SubtargetFeatures); + Rule.emit(OS); + ++CurrentMatchTableID; ++NumPatternEmitted; + assert(CurrentMatchTableID == NumPatternEmitted && + "Statistic deviates from number of emitted tables"); } OS << " return false;\n" diff --git a/utils/TableGen/InstrInfoEmitter.cpp b/utils/TableGen/InstrInfoEmitter.cpp index ab7d964cd671..e270a17356f7 100644 --- a/utils/TableGen/InstrInfoEmitter.cpp +++ b/utils/TableGen/InstrInfoEmitter.cpp @@ -67,7 +67,7 @@ private: void emitOperandTypesEnum(raw_ostream &OS, const CodeGenTarget &Target); void initOperandMapData( ArrayRef<const CodeGenInstruction *> NumberedInstructions, - const std::string &Namespace, + StringRef Namespace, std::map<std::string, unsigned> &Operands, OpNameMapTy &OperandMap); void emitOperandNameMappings(raw_ostream &OS, const CodeGenTarget &Target, @@ -207,7 +207,7 @@ void InstrInfoEmitter::EmitOperandInfo(raw_ostream &OS, /// well as the getNamedOperandIdx() function. void InstrInfoEmitter::initOperandMapData( ArrayRef<const CodeGenInstruction *> NumberedInstructions, - const std::string &Namespace, + StringRef Namespace, std::map<std::string, unsigned> &Operands, OpNameMapTy &OperandMap) { unsigned NumOperands = 0; @@ -224,7 +224,7 @@ void InstrInfoEmitter::initOperandMapData( } OpList[I->second] = Info.MIOperandNo; } - OperandMap[OpList].push_back(Namespace + "::" + + OperandMap[OpList].push_back(Namespace.str() + "::" + Inst->TheDef->getName().str()); } } @@ -243,7 +243,7 @@ void InstrInfoEmitter::initOperandMapData( void InstrInfoEmitter::emitOperandNameMappings(raw_ostream &OS, const CodeGenTarget &Target, ArrayRef<const CodeGenInstruction*> NumberedInstructions) { - const std::string &Namespace = Target.getInstNamespace(); + StringRef Namespace = Target.getInstNamespace(); std::string OpNameNS = "OpName"; // Map of operand names to their enumeration value. This will be used to // generate the OpName enum. @@ -315,7 +315,7 @@ void InstrInfoEmitter::emitOperandNameMappings(raw_ostream &OS, void InstrInfoEmitter::emitOperandTypesEnum(raw_ostream &OS, const CodeGenTarget &Target) { - const std::string &Namespace = Target.getInstNamespace(); + StringRef Namespace = Target.getInstNamespace(); std::vector<Record *> Operands = Records.getAllDerivedDefinitions("Operand"); OS << "#ifdef GET_INSTRINFO_OPERAND_TYPES_ENUM\n"; @@ -576,7 +576,7 @@ void InstrInfoEmitter::emitEnums(raw_ostream &OS) { CodeGenTarget Target(Records); // We must emit the PHI opcode first... - std::string Namespace = Target.getInstNamespace(); + StringRef Namespace = Target.getInstNamespace(); if (Namespace.empty()) PrintFatalError("No instructions defined!"); diff --git a/utils/TableGen/RegisterBankEmitter.cpp b/utils/TableGen/RegisterBankEmitter.cpp index 3f11eff1d371..880d075da427 100644 --- a/utils/TableGen/RegisterBankEmitter.cpp +++ b/utils/TableGen/RegisterBankEmitter.cpp @@ -227,7 +227,7 @@ void RegisterBankEmitter::emitBaseClassImplementation( OS << " // " << LowestIdxInWord << "-" << (LowestIdxInWord + 31) << "\n"; for (const auto &RC : RCs) { std::string QualifiedRegClassID = - (Twine(TargetName) + "::" + RC->getName() + "RegClassID").str(); + (Twine(RC->Namespace) + "::" + RC->getName() + "RegClassID").str(); OS << " (1u << (" << QualifiedRegClassID << " - " << LowestIdxInWord << ")) |\n"; } diff --git a/utils/TableGen/SearchableTableEmitter.cpp b/utils/TableGen/SearchableTableEmitter.cpp index efd4e83eca90..f73c197dee5a 100644 --- a/utils/TableGen/SearchableTableEmitter.cpp +++ b/utils/TableGen/SearchableTableEmitter.cpp @@ -230,7 +230,7 @@ void SearchableTableEmitter::emitLookupDeclaration(StringRef Name, void SearchableTableEmitter::emitMapping(Record *InstanceClass, raw_ostream &OS) { - const std::string &TableName = InstanceClass->getName(); + StringRef TableName = InstanceClass->getName(); std::vector<Record *> Items = Records.getAllDerivedDefinitions(TableName); // Gather all the records we're going to need for this particular mapping. @@ -265,8 +265,8 @@ void SearchableTableEmitter::emitMapping(Record *InstanceClass, ++Idx; } - OS << "#ifdef GET_" << StringRef(TableName).upper() << "_DECL\n"; - OS << "#undef GET_" << StringRef(TableName).upper() << "_DECL\n"; + OS << "#ifdef GET_" << TableName.upper() << "_DECL\n"; + OS << "#undef GET_" << TableName.upper() << "_DECL\n"; // Next emit the enum containing the top-level names for use in C++ code if // requested @@ -281,8 +281,8 @@ void SearchableTableEmitter::emitMapping(Record *InstanceClass, OS << "#endif\n\n"; - OS << "#ifdef GET_" << StringRef(TableName).upper() << "_IMPL\n"; - OS << "#undef GET_" << StringRef(TableName).upper() << "_IMPL\n"; + OS << "#ifdef GET_" << TableName.upper() << "_IMPL\n"; + OS << "#undef GET_" << TableName.upper() << "_IMPL\n"; // The primary data table contains all the fields defined for this map. emitPrimaryTable(TableName, FieldNames, SearchFieldNames, SearchTables, Items, diff --git a/utils/TableGen/SubtargetEmitter.cpp b/utils/TableGen/SubtargetEmitter.cpp index 16d5740b79a3..d1d873b66aaa 100644 --- a/utils/TableGen/SubtargetEmitter.cpp +++ b/utils/TableGen/SubtargetEmitter.cpp @@ -375,7 +375,7 @@ EmitStageAndOperandCycleData(raw_ostream &OS, if (FUs.empty()) continue; - const std::string &Name = ProcModel.ItinsDef->getName(); + StringRef Name = ProcModel.ItinsDef->getName(); OS << "\n// Functional units for \"" << Name << "\"\n" << "namespace " << Name << "FU {\n"; @@ -429,7 +429,7 @@ EmitStageAndOperandCycleData(raw_ostream &OS, if (!ProcModel.hasItineraries()) continue; - const std::string &Name = ProcModel.ItinsDef->getName(); + StringRef Name = ProcModel.ItinsDef->getName(); ItinList.resize(SchedModels.numInstrSchedClasses()); assert(ProcModel.ItinDefList.size() == ItinList.size() && "bad Itins"); @@ -546,9 +546,6 @@ EmitItineraries(raw_ostream &OS, if (!ItinsDefSet.insert(ItinsDef).second) continue; - // Get processor itinerary name - const std::string &Name = ItinsDef->getName(); - // Get the itinerary list for the processor. assert(ProcItinListsIter != ProcItinLists.end() && "bad iterator"); std::vector<InstrItinerary> &ItinList = *ProcItinListsIter; @@ -562,7 +559,7 @@ EmitItineraries(raw_ostream &OS, OS << "static const llvm::InstrItinerary "; // Begin processor itinerary table - OS << Name << "[] = {\n"; + OS << ItinsDef->getName() << "[] = {\n"; // For each itinerary class in CodeGenSchedClass::Index order. for (unsigned j = 0, M = ItinList.size(); j < M; ++j) { diff --git a/utils/TableGen/X86DisassemblerTables.cpp b/utils/TableGen/X86DisassemblerTables.cpp index c9e36f96736a..c80b96905b30 100644 --- a/utils/TableGen/X86DisassemblerTables.cpp +++ b/utils/TableGen/X86DisassemblerTables.cpp @@ -10,7 +10,7 @@ // This file is part of the X86 Disassembler Emitter. // It contains the implementation of the disassembler tables. // Documentation for the disassembler emitter in general can be found in -// X86DisasemblerEmitter.h. +// X86DisassemblerEmitter.h. // //===----------------------------------------------------------------------===// diff --git a/utils/TableGen/X86DisassemblerTables.h b/utils/TableGen/X86DisassemblerTables.h index 5a8688be0819..1171c7980f42 100644 --- a/utils/TableGen/X86DisassemblerTables.h +++ b/utils/TableGen/X86DisassemblerTables.h @@ -10,7 +10,7 @@ // This file is part of the X86 Disassembler Emitter. // It contains the interface of the disassembler tables. // Documentation for the disassembler emitter in general can be found in -// X86DisasemblerEmitter.h. +// X86DisassemblerEmitter.h. // //===----------------------------------------------------------------------===// diff --git a/utils/TableGen/X86ModRMFilters.h b/utils/TableGen/X86ModRMFilters.h index d919c588c644..73d5602fd91c 100644 --- a/utils/TableGen/X86ModRMFilters.h +++ b/utils/TableGen/X86ModRMFilters.h @@ -11,7 +11,7 @@ // It contains ModR/M filters that determine which values of the ModR/M byte // are valid for a partiuclar instruction. // Documentation for the disassembler emitter in general can be found in -// X86DisasemblerEmitter.h. +// X86DisassemblerEmitter.h. // //===----------------------------------------------------------------------===// diff --git a/utils/TableGen/X86RecognizableInstr.cpp b/utils/TableGen/X86RecognizableInstr.cpp index 55e75763ad69..202a71ae4dc4 100644 --- a/utils/TableGen/X86RecognizableInstr.cpp +++ b/utils/TableGen/X86RecognizableInstr.cpp @@ -10,7 +10,7 @@ // This file is part of the X86 Disassembler Emitter. // It contains the implementation of a single recognizable instruction. // Documentation for the disassembler emitter in general can be found in -// X86DisasemblerEmitter.h. +// X86DisassemblerEmitter.h. // //===----------------------------------------------------------------------===// @@ -367,7 +367,7 @@ void RecognizableInstr::handleOperand(bool optional, unsigned &operandIndex, ++operandIndex; } - const std::string &typeName = (*Operands)[operandIndex].Rec->getName(); + StringRef typeName = (*Operands)[operandIndex].Rec->getName(); OperandEncoding encoding = encodingFromString(typeName, OpSize); // Adjust the encoding type for an operand based on the instruction. diff --git a/utils/TableGen/X86RecognizableInstr.h b/utils/TableGen/X86RecognizableInstr.h index 7fe731ec8b1c..ea99935f8790 100644 --- a/utils/TableGen/X86RecognizableInstr.h +++ b/utils/TableGen/X86RecognizableInstr.h @@ -10,7 +10,7 @@ // This file is part of the X86 Disassembler Emitter. // It contains the interface of a single recognizable instruction. // Documentation for the disassembler emitter in general can be found in -// X86DisasemblerEmitter.h. +// X86DisassemblerEmitter.h. // //===----------------------------------------------------------------------===// |