Index: llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp =================================================================== --- llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp +++ llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp @@ -35,6 +35,7 @@ #include "llvm/ADT/Statistic.h" #include "llvm/CodeGen/MachineValueType.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/Error.h" #include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" #include "llvm/TableGen/TableGenBackend.h" @@ -54,35 +55,7 @@ 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 +class RuleMatcher; //===- Helper functions ---------------------------------------------------===// @@ -381,6 +354,28 @@ //===- GlobalISelEmitter class --------------------------------------------===// +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); + + /// Analyze pattern \p P, returning a matcher for it if possible. + /// Otherwise, return an Error explaining why we don't support it. + Expected runOnPattern(const PatternToMatch &P); +}; + void GlobalISelEmitter::gatherNodeEquivs() { assert(NodeEquivs.empty()); for (Record *Equiv : RK.getAllDerivedDefinitions("GINodeEquiv")) @@ -397,9 +392,12 @@ //===- Emitter ------------------------------------------------------------===// -Optional -GlobalISelEmitter::runOnPattern(const PatternToMatch &P, raw_ostream &OS) { +/// Helper function to let the emitter report skip reason error messages. +static Error failedImport(const Twine &Reason) { + return make_error(Reason, inconvertibleErrorCode()); +} +Expected GlobalISelEmitter::runOnPattern(const PatternToMatch &P) { // Keep track of the matchers and actions to emit. RuleMatcher M; M.addAction(P); @@ -407,11 +405,11 @@ // 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"}; + return failedImport("Pattern has a predicate"); // Physreg imp-defs require additional logic. Ignore the pattern. if (!P.getDstRegs().empty()) - return SkipReason{"Pattern defines a physical register"}; + return failedImport("Pattern defines a physical register"); // Next, analyze the pattern operators. TreePatternNode *Src = P.getSrcPattern(); @@ -419,19 +417,19 @@ // 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"}; + return failedImport("Dst pattern root isn't a trivial operator"); if (!isTrivialOperatorNode(Src)) - return SkipReason{"Src pattern root isn't a trivial operator"}; + return failedImport("Src pattern root isn't a trivial operator"); Record *DstOp = Dst->getOperator(); if (!DstOp->isSubClassOf("Instruction")) - return SkipReason{"Pattern operator isn't an instruction"}; + return failedImport("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"}; + return failedImport("Pattern operator lacks an equivalent Instruction"); auto &SrcGI = *SrcGIOrNull; // The operators look good: match the opcode and mutate it to the new one. @@ -442,22 +440,22 @@ // 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"}; + return failedImport("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"}; + return failedImport("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"}; + return failedImport("Dst MI def isn't a register class"); auto OpTyOrNone = MVTToLLT(Ty.getConcrete()); if (!OpTyOrNone) - return SkipReason{"Dst operand has an unsupported type"}; + return failedImport("Dst operand has an unsupported type"); OperandMatcher &OM = InsnMatcher.addOperand(OpIdx); OM.addPredicate(*OpTyOrNone); @@ -473,14 +471,14 @@ // Patterns can reorder operands. Ignore those for now. if (SrcChild->getName() != DstChild->getName()) - return SkipReason{"Src/dst pattern children not in same order"}; + return failedImport("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"}; + return failedImport("Src/dst pattern child operator mismatch"); if (SrcChild->getOperator()->isSubClassOf("SDNode")) { auto &ChildSDNI = CGP.getSDNodeInfo(SrcChild->getOperator()); @@ -489,26 +487,26 @@ continue; } } - return SkipReason{"Src pattern child isn't a leaf node"}; + return failedImport("Src pattern child isn't a leaf node"); } if (SrcChild->getLeafValue() != DstChild->getLeafValue()) - return SkipReason{"Src/dst pattern child leaf mismatch"}; + return failedImport("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"}; + return failedImport("Src pattern child has predicate"); auto *ChildRec = cast(SrcChild->getLeafValue())->getDef(); if (!ChildRec->isSubClassOf("RegisterClass")) - return SkipReason{"Src pattern child isn't a RegisterClass"}; + return failedImport("Src pattern child isn't a RegisterClass"); ArrayRef ChildTypes = SrcChild->getExtTypes(); if (ChildTypes.size() != 1) - return SkipReason{"Src pattern child has multiple results"}; + return failedImport("Src pattern child has multiple results"); auto OpTyOrNone = MVTToLLT(ChildTypes.front().getConcrete()); if (!OpTyOrNone) - return SkipReason{"Src operand has an unsupported type"}; + return failedImport("Src operand has an unsupported type"); OperandMatcher &OM = InsnMatcher.addOperand(OpIdx); OM.addPredicate(*OpTyOrNone); @@ -517,10 +515,8 @@ ++OpIdx; } - // We're done with this pattern! Emit the processed result. - M.emit(OS); - ++NumPatternEmitted; - return None; + // We're done with this pattern! It's eligible for GISel emission; return it. + return std::move(M); } void GlobalISelEmitter::run(raw_ostream &OS) { @@ -537,18 +533,30 @@ // Look through the SelectionDAG patterns we found, possibly emitting some. for (const PatternToMatch &Pat : CGP.ptms()) { ++NumPatternTotal; - if (auto SkipReason = runOnPattern(Pat, OS)) { + auto MatcherOrErr = runOnPattern(Pat); + + // The pattern analysis can fail, indicating an unsupported pattern. + // Report that if we've been asked to do so. + if (auto Err = MatcherOrErr.takeError()) { if (WarnOnSkippedPatterns) { PrintWarning(Pat.getSrcRecord()->getLoc(), - "Skipped pattern: " + SkipReason->Reason); + "Skipped pattern: " + toString(std::move(Err))); + } else { + consumeError(std::move(Err)); } ++NumPatternSkipped; + continue; } + + MatcherOrErr->emit(OS); + ++NumPatternEmitted; } OS << " return false;\n}\n"; } +} // end anonymous namespace + //===----------------------------------------------------------------------===// namespace llvm {