Index: utils/TableGen/GlobalISelEmitter.cpp =================================================================== --- utils/TableGen/GlobalISelEmitter.cpp +++ utils/TableGen/GlobalISelEmitter.cpp @@ -145,7 +145,52 @@ return None; } -static bool isTrivialOperatorNode(const TreePatternNode *N) { +static std::string explainPredicates(const TreePatternNode *N) { + std::string Explanation = ""; + StringRef Separator = ""; + for (const auto &P : N->getPredicateFns()) { + Explanation += + (Separator + P.getOrigPatFragRecord()->getRecord()->getName()).str(); + if (P.isAlwaysTrue()) + Explanation += " always-true"; + if (P.isImmediatePattern()) + Explanation += " immediate"; + } + return Explanation; +} + +static std::string explainRulePredicates(const ArrayRef Predicates) { + std::string Explanation = ""; + StringRef Separator = ""; + for (const auto *P : Predicates) { + Explanation += Separator; + + if (const DefInit *PDef = dyn_cast(P)) { + Explanation += PDef->getDef()->getName(); + } else + Explanation += ""; + } + return Explanation; +} + +static bool isTrivialOperatorNode(const TreePatternNode *N, + std::string &Explanation) { + std::string Separator = ""; + if (N->isLeaf()) { + Explanation = "Is a leaf"; + Separator = ", "; + } + + if (N->hasAnyPredicate()) { + Explanation = Separator + "Has a predicate (" + explainPredicates(N) + ")"; + Separator = ", "; + } + + if (N->getTransformFn()) { + Explanation += Separator + "Has a transform function"; + Separator = ", "; + } + return !N->isLeaf() && !N->hasAnyPredicate() && !N->getTransformFn(); } @@ -1245,7 +1290,8 @@ GlobalISelEmitter::importRulePredicates(RuleMatcher &M, ArrayRef Predicates) const { if (!Predicates.empty()) - return failedImport("Pattern has a predicate"); + return failedImport("Pattern has a rule predicate (" + + explainRulePredicates(Predicates) + ")"); return true; } @@ -1257,8 +1303,23 @@ return failedImport("Src pattern has multiple results"); auto SrcGIOrNull = findNodeEquiv(Src->getOperator()); - if (!SrcGIOrNull) - return failedImport("Pattern operator lacks an equivalent Instruction"); + if (!SrcGIOrNull) { + std::string Explanation = ""; + + if (Src->getOperator()->isSubClassOf("SDNode")) { + std::string Opcode = Src->getOperator()->getValueAsString("Opcode"); + if (StringRef(Opcode).startswith("ISD::")) + Explanation = " (Operator is a standard SDNode, " + Opcode + ")"; + else + Explanation = " (Operator is a custom SDNode, " + Opcode + ")"; + } else if (Src->getOperator()->isSubClassOf("Intrinsic")) + Explanation = + (" (Operator is an Intrinsic, " + Src->getOperator()->getName() + ")") + .str(); + + return failedImport("Pattern operator lacks an equivalent Instruction" + + Explanation); + } auto &SrcGI = *SrcGIOrNull; // The operators look good: match the opcode and mutate it to the new one. @@ -1297,7 +1358,8 @@ OperandMatcher &OM = InsnMatcher.addOperand(OpIdx, SrcChild->getName(), TempOpIdx); if (SrcChild->hasAnyPredicate()) - return failedImport("Src pattern child has predicate"); + return failedImport("Src pattern child has predicate (" + + explainPredicates(SrcChild) + ")"); ArrayRef ChildTypes = SrcChild->getExtTypes(); if (ChildTypes.size() != 1) @@ -1353,8 +1415,8 @@ if (ChildRec->isSubClassOf("ComplexPattern")) { const auto &ComplexPattern = ComplexPatternEquivs.find(ChildRec); if (ComplexPattern == ComplexPatternEquivs.end()) - return failedImport( - "SelectionDAG ComplexPattern not mapped to GlobalISel"); + return failedImport("SelectionDAG ComplexPattern (" + + ChildRec->getName() + ") not mapped to GlobalISel"); const auto &Predicate = OM.addPredicate( OM, *ComplexPattern->second); @@ -1362,6 +1424,11 @@ return true; } + if (ChildRec->isSubClassOf("ImmLeaf")) { + return failedImport( + "Src pattern child def is an unsupported tablegen class (ImmLeaf)"); + } + return failedImport( "Src pattern child def is an unsupported tablegen class"); } @@ -1388,7 +1455,8 @@ // Otherwise, we're looking for a bog-standard RegisterClass operand. if (DstChild->hasAnyPredicate()) - return failedImport("Dst pattern child has predicate"); + return failedImport("Dst pattern child has predicate (" + + explainPredicates(DstChild) + ")"); if (auto *ChildDefInit = dyn_cast(DstChild->getLeafValue())) { auto *ChildRec = ChildDefInit->getDef(); @@ -1427,6 +1495,10 @@ return true; } + if (ChildRec->isSubClassOf("SDNodeXForm")) + return failedImport("Dst pattern child def is an unsupported tablegen " + "class (SDNodeXForm)"); + return failedImport( "Dst pattern child def is an unsupported tablegen class"); } @@ -1438,8 +1510,12 @@ RuleMatcher &M, const TreePatternNode *Dst, const InstructionMatcher &InsnMatcher) const { Record *DstOp = Dst->getOperator(); - if (!DstOp->isSubClassOf("Instruction")) + if (!DstOp->isSubClassOf("Instruction")) { + if (DstOp->isSubClassOf("ValueType")) + return failedImport( + "Pattern operator isn't an instruction (it's a ValueType)"); return failedImport("Pattern operator isn't an instruction"); + } auto &DstI = Target.getInstruction(DstOp); auto &DstMIBuilder = M.addAction(&DstI, InsnMatcher); @@ -1536,10 +1612,13 @@ TreePatternNode *Dst = P.getDstPattern(); // If the root of either pattern isn't a simple operator, ignore it. - if (!isTrivialOperatorNode(Dst)) - return failedImport("Dst pattern root isn't a trivial operator"); - if (!isTrivialOperatorNode(Src)) - return failedImport("Src pattern root isn't a trivial operator"); + std::string ExtraReason; + if (!isTrivialOperatorNode(Dst, ExtraReason)) + return failedImport("Dst pattern root isn't a trivial operator (" + + ExtraReason + ")"); + if (!isTrivialOperatorNode(Src, ExtraReason)) + return failedImport("Src pattern root isn't a trivial operator (" + + ExtraReason + ")"); // Start with the defined operands (i.e., the results of the root operator). Record *DstOp = Dst->getOperator(); @@ -1548,7 +1627,9 @@ auto &DstI = Target.getInstruction(DstOp); if (DstI.Operands.NumDefs != Src->getExtTypes().size()) - return failedImport("Src pattern results and dst MI defs are different"); + return failedImport("Src pattern results and dst MI defs are different (" + + llvm::to_string(Src->getExtTypes().size()) + " def(s) vs " + + llvm::to_string(DstI.Operands.NumDefs) + " def(s))"); InstructionMatcher &InsnMatcherTemp = M.addInstructionMatcher(); auto InsnMatcherOrError = importSelDAGMatcher(InsnMatcherTemp, Src);