//===- GlobalISelEmitter.cpp - Generate an instruction selector -----------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // /// \file /// This tablegen backend emits code for use by the GlobalISel instruction /// selector. See include/llvm/CodeGen/TargetGlobalISel.td. /// /// This file analyzes the patterns recognized by the SelectionDAGISel tablegen /// backend, filters out the ones that are unsupported, maps /// SelectionDAG-specific constructs to their GlobalISel counterpart /// (when applicable: MVT to LLT; SDNode to generic Instruction). /// /// Not all patterns are supported: pass the tablegen invocation /// "-warn-on-skipped-patterns" to emit a warning when a pattern is skipped, /// as well as why. /// /// The generated file defines a single method: /// bool InstructionSelector::selectImpl(MachineInstr &I) const; /// intended to be used in InstructionSelector::select as the first-step /// selector for the patterns that don't require complex C++. /// /// FIXME: We'll probably want to eventually define a base /// "TargetGenInstructionSelector" class. /// //===----------------------------------------------------------------------===// #include "CodeGenDAGPatterns.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/Statistic.h" #include "llvm/CodeGen/MachineValueType.h" #include "llvm/Support/CommandLine.h" #include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" #include "llvm/TableGen/TableGenBackend.h" #include using namespace llvm; #define DEBUG_TYPE "gisel-emitter" STATISTIC(NumPatternTotal, "Total number of patterns"); STATISTIC(NumPatternSkipped, "Number of patterns skipped"); STATISTIC(NumPatternEmitted, "Number of patterns emitted"); static cl::opt WarnOnSkippedPatterns( "warn-on-skipped-patterns", cl::desc("Explain why a pattern was skipped for inclusion " "in the GlobalISel selector"), cl::init(false)); namespace { class GlobalISelEmitter { public: explicit GlobalISelEmitter(RecordKeeper &RK); void run(raw_ostream &OS); private: const RecordKeeper &RK; const CodeGenDAGPatterns CGP; const CodeGenTarget &Target; /// Keep track of the equivalence between SDNodes and Instruction. /// This is defined using 'GINodeEquiv' in the target description. DenseMap NodeEquivs; void gatherNodeEquivs(); const CodeGenInstruction *findNodeEquiv(Record *N); struct SkipReason { std::string Reason; }; /// Analyze pattern \p P, possibly emitting matching code for it to \p OS. /// Otherwise, return a reason why this pattern was skipped for emission. Optional runOnPattern(const PatternToMatch &P, raw_ostream &OS); }; } // end anonymous namespace //===- Helper functions ---------------------------------------------------===// /// Convert an MVT to an equivalent LLT if possible, or the invalid LLT() for /// MVTs that don't map cleanly to an LLT (e.g., iPTR, *any, ...). static Optional MVTToLLT(MVT::SimpleValueType SVT) { std::string TyStr; raw_string_ostream OS(TyStr); MVT VT(SVT); if (VT.isVector() && VT.getVectorNumElements() != 1) { OS << "LLT::vector(" << VT.getVectorNumElements() << ", " << VT.getScalarSizeInBits() << ")"; } else if (VT.isInteger() || VT.isFloatingPoint()) { OS << "LLT::scalar(" << VT.getSizeInBits() << ")"; } else { return None; } OS.flush(); return TyStr; } static bool isTrivialOperatorNode(const TreePatternNode *N) { return !N->isLeaf() && !N->hasAnyPredicate() && !N->getTransformFn(); } //===- Matchers -----------------------------------------------------------===// struct Matcher { virtual ~Matcher() {} virtual void emit(raw_ostream &OS) const = 0; }; raw_ostream &operator<<(raw_ostream &S, const Matcher &M) { M.emit(S); return S; } struct MatchAction { virtual ~MatchAction() {} virtual void emit(raw_ostream &OS) const = 0; }; raw_ostream &operator<<(raw_ostream &S, const MatchAction &A) { A.emit(S); return S; } struct MatchOpcode : public Matcher { MatchOpcode(const CodeGenInstruction *I) : I(I) {} const CodeGenInstruction *I; virtual void emit(raw_ostream &OS) const { OS << "I.getOpcode() == " << I->Namespace << "::" << I->TheDef->getName(); } }; struct MatchRegOpType : public Matcher { MatchRegOpType(unsigned OpIdx, std::string Ty) : OpIdx(OpIdx), Ty(Ty) {} unsigned OpIdx; std::string Ty; virtual void emit(raw_ostream &OS) const { OS << "MRI.getType(I.getOperand(" << OpIdx << ").getReg()) == (" << Ty << ")"; } }; struct MatchRegOpBank : public Matcher { MatchRegOpBank(unsigned OpIdx, const CodeGenRegisterClass &RC) : OpIdx(OpIdx), RC(RC) {} unsigned OpIdx; const CodeGenRegisterClass &RC; virtual void emit(raw_ostream &OS) const { OS << "(&RBI.getRegBankFromRegClass(" << RC.getQualifiedName() << "RegClass) == RBI.getRegBank(I.getOperand(" << OpIdx << ").getReg(), MRI, TRI))"; } }; struct MatchMBBOp : public Matcher { MatchMBBOp(unsigned OpIdx) : OpIdx(OpIdx) {} unsigned OpIdx; virtual void emit(raw_ostream &OS) const { OS << "I.getOperand(" << OpIdx << ").isMBB()"; } }; struct MutateOpcode : public MatchAction { MutateOpcode(const CodeGenInstruction *I) : I(I) {} const CodeGenInstruction *I; virtual void emit(raw_ostream &OS) const { OS << "I.setDesc(TII.get(" << I->Namespace << "::" << I->TheDef->getName() << "));"; } }; class MatcherEmitter { const PatternToMatch &P; public: std::vector> Matchers; std::vector> Actions; MatcherEmitter(const PatternToMatch &P) : P(P) {} void emit(raw_ostream &OS) { if (Matchers.empty()) llvm_unreachable("Unexpected empty matcher!"); OS << " // Src: " << *P.getSrcPattern() << "\n" << " // Dst: " << *P.getDstPattern() << "\n"; OS << " if ((" << *Matchers.front() << ")"; for (auto &MA : makeArrayRef(Matchers).drop_front()) OS << " &&\n (" << *MA << ")"; OS << ") {\n"; for (auto &MA : Actions) OS << " " << *MA << "\n"; OS << " constrainSelectedInstRegOperands(I, TII, TRI, RBI);\n"; OS << " return true;\n"; OS << " }\n"; } }; //===- GlobalISelEmitter class --------------------------------------------===// void GlobalISelEmitter::gatherNodeEquivs() { assert(NodeEquivs.empty()); for (Record *Equiv : RK.getAllDerivedDefinitions("GINodeEquiv")) NodeEquivs[Equiv->getValueAsDef("Node")] = &Target.getInstruction(Equiv->getValueAsDef("I")); } const CodeGenInstruction *GlobalISelEmitter::findNodeEquiv(Record *N) { return NodeEquivs.lookup(N); } GlobalISelEmitter::GlobalISelEmitter(RecordKeeper &RK) : RK(RK), CGP(RK), Target(CGP.getTargetInfo()) {} //===- Emitter ------------------------------------------------------------===// Optional GlobalISelEmitter::runOnPattern(const PatternToMatch &P, raw_ostream &OS) { // Keep track of the matchers and actions to emit. MatcherEmitter M(P); // First, analyze the whole pattern. // If the entire pattern has a predicate (e.g., target features), ignore it. if (!P.getPredicates()->getValues().empty()) return SkipReason{"Pattern has a predicate"}; // Physreg imp-defs require additional logic. Ignore the pattern. if (!P.getDstRegs().empty()) return SkipReason{"Pattern defines a physical register"}; // Next, analyze the pattern operators. TreePatternNode *Src = P.getSrcPattern(); TreePatternNode *Dst = P.getDstPattern(); // If the root of either pattern isn't a simple operator, ignore it. if (!isTrivialOperatorNode(Dst)) return SkipReason{"Dst pattern root isn't a trivial operator"}; if (!isTrivialOperatorNode(Src)) return SkipReason{"Src pattern root isn't a trivial operator"}; Record *DstOp = Dst->getOperator(); if (!DstOp->isSubClassOf("Instruction")) return SkipReason{"Pattern operator isn't an instruction"}; auto &DstI = Target.getInstruction(DstOp); auto SrcGIOrNull = findNodeEquiv(Src->getOperator()); if (!SrcGIOrNull) return SkipReason{"Pattern operator lacks an equivalent Instruction"}; auto &SrcGI = *SrcGIOrNull; // The operators look good: match the opcode and mutate it to the new one. M.Matchers.emplace_back(new MatchOpcode(&SrcGI)); M.Actions.emplace_back(new MutateOpcode(&DstI)); // Next, analyze the children, only accepting patterns that don't require // any change to operands. if (Src->getNumChildren() != Dst->getNumChildren()) return SkipReason{"Src/dst patterns have a different # of children"}; unsigned OpIdx = 0; // Start with the defined operands (i.e., the results of the root operator). if (DstI.Operands.NumDefs != Src->getExtTypes().size()) return SkipReason{"Src pattern results and dst MI defs are different"}; for (const EEVT::TypeSet &Ty : Src->getExtTypes()) { Record *DstIOpRec = DstI.Operands[OpIdx].Rec; if (!DstIOpRec->isSubClassOf("RegisterClass")) return SkipReason{"Dst MI def isn't a register class"}; auto OpTyOrNone = MVTToLLT(Ty.getConcrete()); if (!OpTyOrNone) return SkipReason{"Dst operand has an unsupported type"}; M.Matchers.emplace_back(new MatchRegOpType(OpIdx, *OpTyOrNone)); M.Matchers.emplace_back( new MatchRegOpBank(OpIdx, Target.getRegisterClass(DstIOpRec))); ++OpIdx; } // Finally match the used operands (i.e., the children of the root operator). for (unsigned i = 0, e = Src->getNumChildren(); i != e; ++i) { auto *SrcChild = Src->getChild(i); auto *DstChild = Dst->getChild(i); // Patterns can reorder operands. Ignore those for now. if (SrcChild->getName() != DstChild->getName()) return SkipReason{"Src/dst pattern children not in same order"}; // The only non-leaf child we accept is 'bb': it's an operator because // BasicBlockSDNode isn't inline, but in MI it's just another operand. if (!SrcChild->isLeaf()) { if (DstChild->isLeaf() || SrcChild->getOperator() != DstChild->getOperator()) return SkipReason{"Src/dst pattern child operator mismatch"}; if (SrcChild->getOperator()->isSubClassOf("SDNode")) { auto &ChildSDNI = CGP.getSDNodeInfo(SrcChild->getOperator()); if (ChildSDNI.getSDClassName() == "BasicBlockSDNode") { M.Matchers.emplace_back(new MatchMBBOp(OpIdx++)); continue; } } return SkipReason{"Src pattern child isn't a leaf node"}; } if (SrcChild->getLeafValue() != DstChild->getLeafValue()) return SkipReason{"Src/dst pattern child leaf mismatch"}; // Otherwise, we're looking for a bog-standard RegisterClass operand. if (SrcChild->hasAnyPredicate()) return SkipReason{"Src pattern child has predicate"}; auto *ChildRec = cast(SrcChild->getLeafValue())->getDef(); if (!ChildRec->isSubClassOf("RegisterClass")) return SkipReason{"Src pattern child isn't a RegisterClass"}; ArrayRef ChildTypes = SrcChild->getExtTypes(); if (ChildTypes.size() != 1) return SkipReason{"Src pattern child has multiple results"}; auto OpTyOrNone = MVTToLLT(ChildTypes.front().getConcrete()); if (!OpTyOrNone) return SkipReason{"Src operand has an unsupported type"}; M.Matchers.emplace_back(new MatchRegOpType(OpIdx, *OpTyOrNone)); M.Matchers.emplace_back( new MatchRegOpBank(OpIdx, Target.getRegisterClass(ChildRec))); ++OpIdx; } // We're done with this pattern! Emit the processed result. M.emit(OS); ++NumPatternEmitted; return None; } void GlobalISelEmitter::run(raw_ostream &OS) { // Track the GINodeEquiv definitions. gatherNodeEquivs(); emitSourceFileHeader(("Global Instruction Selector for the " + Target.getName() + " target").str(), OS); OS << "bool " << Target.getName() << "InstructionSelector::selectImpl" "(MachineInstr &I) const {\n const MachineRegisterInfo &MRI = " "I.getParent()->getParent()->getRegInfo();\n"; // Look through the SelectionDAG patterns we found, possibly emitting some. for (const PatternToMatch &Pat : CGP.ptms()) { ++NumPatternTotal; if (auto SkipReason = runOnPattern(Pat, OS)) { if (WarnOnSkippedPatterns) { PrintWarning(Pat.getSrcRecord()->getLoc(), "Skipped pattern: " + SkipReason->Reason); } ++NumPatternSkipped; } } OS << " return false;\n}\n"; } //===----------------------------------------------------------------------===// namespace llvm { void EmitGlobalISel(RecordKeeper &RK, raw_ostream &OS) { GlobalISelEmitter(RK).run(OS); } } // End llvm namespace