From: Ahmed Bougacha Date: Fri, 10 Feb 2017 04:00:17 +0000 (+0000) Subject: [GlobalISel] Return an Expected for each SDAG pattern. NFC. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=de17164c61a65ce9c26bebddf7568e89b725f980;p=llvm [GlobalISel] Return an Expected for each SDAG pattern. NFC. Instead of emitting the matcher code directly, return the rule matcher and the skip reason as an Expected. This will let us record all matchers and process them before emission. It's a somewhat unconventional use of Error, but it's nicer than, say, std::pair, because of the bool conversions. Differential Revision: https://reviews.llvm.org/D29743 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@294706 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/utils/TableGen/GlobalISelEmitter.cpp b/utils/TableGen/GlobalISelEmitter.cpp index 9dac9e0e093..a31fba7f212 100644 --- a/utils/TableGen/GlobalISelEmitter.cpp +++ b/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 @@ static cl::opt WarnOnSkippedPatterns( 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 @@ public: //===- 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 @@ GlobalISelEmitter::GlobalISelEmitter(RecordKeeper &RK) //===- 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 @@ GlobalISelEmitter::runOnPattern(const PatternToMatch &P, raw_ostream &OS) { // 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 @@ GlobalISelEmitter::runOnPattern(const PatternToMatch &P, raw_ostream &OS) { // 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 @@ GlobalISelEmitter::runOnPattern(const PatternToMatch &P, raw_ostream &OS) { // 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 @@ GlobalISelEmitter::runOnPattern(const PatternToMatch &P, raw_ostream &OS) { // 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 @@ GlobalISelEmitter::runOnPattern(const PatternToMatch &P, raw_ostream &OS) { 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 @@ GlobalISelEmitter::runOnPattern(const PatternToMatch &P, raw_ostream &OS) { ++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 @@ void GlobalISelEmitter::run(raw_ostream &OS) { // 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 {