Index: llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp =================================================================== --- llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp +++ llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp @@ -412,6 +412,10 @@ bool hasSymbolicName() const { return !SymbolicName.empty(); } const StringRef getSymbolicName() const { return SymbolicName; } + void setSymbolicName(StringRef Name) { + assert(SymbolicName.empty() && "Operand already has a symbolic name"); + SymbolicName = Name; + } unsigned getOperandIndex() const { return OpIdx; } std::string getOperandExpr(const StringRef InsnVarName) const { @@ -567,6 +571,16 @@ return Operands.back(); } + OperandMatcher &getOperand(unsigned OpIdx) { + auto I = std::find_if(Operands.begin(), Operands.end(), + [&OpIdx](const OperandMatcher &X) { + return X.getOperandIndex() == OpIdx; + }); + if (I != Operands.end()) + return *I; + llvm_unreachable("Failed to lookup operand"); + } + Optional getOptionalOperand(StringRef SymbolicName) const { assert(!SymbolicName.empty() && "Cannot lookup unnamed operand"); const auto &I = std::find_if(Operands.begin(), Operands.end(), @@ -586,12 +600,8 @@ } unsigned getNumOperands() const { return Operands.size(); } - OperandVec::const_iterator operands_begin() const { - return Operands.begin(); - } - OperandVec::const_iterator operands_end() const { - return Operands.end(); - } + OperandVec::const_iterator operands_begin() const { return Operands.begin(); } + OperandVec::const_iterator operands_end() const { return Operands.end(); } iterator_range operands() const { return make_range(operands_begin(), operands_end()); } @@ -992,6 +1002,24 @@ void gatherNodeEquivs(); const CodeGenInstruction *findNodeEquiv(Record *N) const; + Expected importRulePredicates(RuleMatcher &M, + ArrayRef Predicates) const; + Expected + importSelDAGMatcher(InstructionMatcher &InsnMatcher, + const TreePatternNode *Src) const; + Expected importChildMatcher(InstructionMatcher &InsnMatcher, + TreePatternNode *SrcChild, unsigned OpIdx, + unsigned &TempOpIdx) const; + Expected + importInstructionRenderer(RuleMatcher &M, const TreePatternNode *Dst, + const InstructionMatcher &InsnMatcher) const; + Expected importExplicitUseRenderer( + BuildMIAction &DstMIBuilder, TreePatternNode *DstChild, + const InstructionMatcher &InsnMatcher, unsigned &TempOpIdx) const; + Expected + importImplicitDefRenderers(BuildMIAction &DstMIBuilder, + const std::vector &ImplicitDefs) const; + /// 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); @@ -1026,37 +1054,20 @@ return make_error(Reason, inconvertibleErrorCode()); } -Expected GlobalISelEmitter::runOnPattern(const PatternToMatch &P) { - unsigned TempOpIdx = 0; - - // Keep track of the matchers and actions to emit. - RuleMatcher M; - M.addAction(P); - - // First, analyze the whole pattern. - // If the entire pattern has a predicate (e.g., target features), ignore it. - if (!P.getPredicates()->getValues().empty()) +Expected +GlobalISelEmitter::importRulePredicates(RuleMatcher &M, + ArrayRef Predicates) const { + if (!Predicates.empty()) return failedImport("Pattern has a predicate"); + return true; +} - // Physreg imp-defs require additional logic. Ignore the pattern. - if (!P.getDstRegs().empty()) - return failedImport("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 failedImport("Dst pattern root isn't a trivial operator"); - if (!isTrivialOperatorNode(Src)) - return failedImport("Src pattern root isn't a trivial operator"); - - Record *DstOp = Dst->getOperator(); - if (!DstOp->isSubClassOf("Instruction")) - return failedImport("Pattern operator isn't an instruction"); - - auto &DstI = Target.getInstruction(DstOp); +Expected +GlobalISelEmitter::importSelDAGMatcher(InstructionMatcher &InsnMatcher, + const TreePatternNode *Src) const { + // 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"); auto SrcGIOrNull = findNodeEquiv(Src->getOperator()); if (!SrcGIOrNull) @@ -1064,174 +1075,268 @@ auto &SrcGI = *SrcGIOrNull; // The operators look good: match the opcode and mutate it to the new one. - InstructionMatcher &InsnMatcher = M.addInstructionMatcher(); InsnMatcher.addPredicate(&SrcGI); - auto &DstMIBuilder = M.addAction(&DstI, InsnMatcher); - - // Next, analyze the children, only accepting patterns that don't require - // any change to operands. - if (Src->getNumChildren() != Dst->getNumChildren()) - 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 failedImport("Src pattern results and dst MI defs are different"); - for (const EEVT::TypeSet &Ty : Src->getExtTypes()) { - const auto &DstIOperand = DstI.Operands[OpIdx]; - Record *DstIOpRec = DstIOperand.Rec; - if (!DstIOpRec->isSubClassOf("RegisterClass")) - return failedImport("Dst MI def isn't a register class"); - auto OpTyOrNone = MVTToLLT(Ty.getConcrete()); + if (!OpTyOrNone) - return failedImport("Dst operand has an unsupported type"); + return failedImport( + "Result of Src pattern operator has an unsupported type"); - OperandMatcher &OM = InsnMatcher.addOperand(OpIdx, DstIOperand.Name); + // Results don't have a name unless they are the root node. The caller will + // set the name if appropriate. + OperandMatcher &OM = InsnMatcher.addOperand(OpIdx++, ""); OM.addPredicate(*OpTyOrNone); - OM.addPredicate( - Target.getRegisterClass(DstIOpRec)); - DstMIBuilder.addRenderer(InsnMatcher, DstIOperand.Name); - ++OpIdx; } - // Finally match the used operands (i.e., the children of the root operator). + unsigned TempOpIdx = 0; + // Match the used operands (i.e. the children of the operator). for (unsigned i = 0, e = Src->getNumChildren(); i != e; ++i) { - auto *SrcChild = Src->getChild(i); + if (auto Error = importChildMatcher(InsnMatcher, Src->getChild(i), OpIdx++, + TempOpIdx) + .takeError()) + return std::move(Error); + } - OperandMatcher &OM = InsnMatcher.addOperand(OpIdx++, SrcChild->getName()); + return InsnMatcher; +} - // 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 (SrcChild->getOperator()->isSubClassOf("SDNode")) { - auto &ChildSDNI = CGP.getSDNodeInfo(SrcChild->getOperator()); - if (ChildSDNI.getSDClassName() == "BasicBlockSDNode") { - OM.addPredicate(); - continue; - } +Expected +GlobalISelEmitter::importChildMatcher(InstructionMatcher &InsnMatcher, + TreePatternNode *SrcChild, unsigned OpIdx, + unsigned &TempOpIdx) const { + OperandMatcher &OM = InsnMatcher.addOperand(OpIdx, SrcChild->getName()); + + if (SrcChild->hasAnyPredicate()) + return failedImport("Src pattern child has predicate"); + + ArrayRef ChildTypes = SrcChild->getExtTypes(); + if (ChildTypes.size() != 1) + return failedImport("Src pattern child has multiple results"); + + // Check MBB's before the type check since they are not a known type. + if (!SrcChild->isLeaf()) { + if (SrcChild->getOperator()->isSubClassOf("SDNode")) { + auto &ChildSDNI = CGP.getSDNodeInfo(SrcChild->getOperator()); + if (ChildSDNI.getSDClassName() == "BasicBlockSDNode") { + OM.addPredicate(); + return true; } - return failedImport("Src pattern child isn't a leaf node or an MBB"); } - if (SrcChild->hasAnyPredicate()) - return failedImport("Src pattern child has predicate"); + return failedImport("Src child operand is an unsupported type"); + } + + auto OpTyOrNone = MVTToLLT(ChildTypes.front().getConcrete()); + if (!OpTyOrNone) + return failedImport("Src operand has an unsupported type"); + OM.addPredicate(*OpTyOrNone); + + // Check for constant immediates. + if (auto *ChildInt = dyn_cast(SrcChild->getLeafValue())) { + OM.addPredicate(ChildInt->getValue()); + return true; + } - ArrayRef ChildTypes = SrcChild->getExtTypes(); + // Check for def's like register classes or ComplexPattern's. + if (auto *ChildDefInit = dyn_cast(SrcChild->getLeafValue())) { + auto *ChildRec = ChildDefInit->getDef(); + + // Check for register classes. + if (ChildRec->isSubClassOf("RegisterClass")) { + OM.addPredicate( + Target.getRegisterClass(ChildRec)); + return true; + } + + // Check for ComplexPattern's. + if (ChildRec->isSubClassOf("ComplexPattern")) { + const auto &ComplexPattern = ComplexPatternEquivs.find(ChildRec); + if (ComplexPattern == ComplexPatternEquivs.end()) + return failedImport( + "SelectionDAG ComplexPattern not mapped to GlobalISel"); + + const auto &Predicate = OM.addPredicate( + *ComplexPattern->second, TempOpIdx); + TempOpIdx += Predicate.countTemporaryOperands(); + return true; + } + + return failedImport( + "Src pattern child def is an unsupported tablegen class"); + } + + return failedImport("Src pattern child is an unsupported kind"); +} + +Expected GlobalISelEmitter::importExplicitUseRenderer( + BuildMIAction &DstMIBuilder, TreePatternNode *DstChild, + const InstructionMatcher &InsnMatcher, unsigned &TempOpIdx) const { + // 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 (!DstChild->isLeaf()) { + if (DstChild->getOperator()->isSubClassOf("SDNode")) { + auto &ChildSDNI = CGP.getSDNodeInfo(DstChild->getOperator()); + if (ChildSDNI.getSDClassName() == "BasicBlockSDNode") { + DstMIBuilder.addRenderer(InsnMatcher, + DstChild->getName()); + return true; + } + } + return failedImport("Dst pattern child isn't a leaf node or an MBB"); + } + + // Otherwise, we're looking for a bog-standard RegisterClass operand. + if (DstChild->hasAnyPredicate()) + return failedImport("Dst pattern child has predicate"); + + if (auto *ChildDefInit = dyn_cast(DstChild->getLeafValue())) { + auto *ChildRec = ChildDefInit->getDef(); + + ArrayRef ChildTypes = DstChild->getExtTypes(); if (ChildTypes.size() != 1) - return failedImport("Src pattern child has multiple results"); + return failedImport("Dst pattern child has multiple results"); auto OpTyOrNone = MVTToLLT(ChildTypes.front().getConcrete()); if (!OpTyOrNone) - return failedImport("Src operand has an unsupported type"); - OM.addPredicate(*OpTyOrNone); + return failedImport("Dst operand has an unsupported type"); - if (auto *ChildInt = dyn_cast(SrcChild->getLeafValue())) { - OM.addPredicate(ChildInt->getValue()); - continue; + if (ChildRec->isSubClassOf("Register")) { + DstMIBuilder.addRenderer(ChildRec); + return true; } - if (auto *ChildDefInit = dyn_cast(SrcChild->getLeafValue())) { - auto *ChildRec = ChildDefInit->getDef(); + if (ChildRec->isSubClassOf("RegisterClass")) { + DstMIBuilder.addRenderer(InsnMatcher, DstChild->getName()); + return true; + } - if (ChildRec->isSubClassOf("RegisterClass")) { - OM.addPredicate( - Target.getRegisterClass(ChildRec)); - continue; + if (ChildRec->isSubClassOf("ComplexPattern")) { + const auto &ComplexPattern = ComplexPatternEquivs.find(ChildRec); + if (ComplexPattern == ComplexPatternEquivs.end()) + return failedImport( + "SelectionDAG ComplexPattern not mapped to GlobalISel"); + + SmallVector RenderedOperands; + for (unsigned I = 0; + I < + InsnMatcher.getOperand(DstChild->getName()).countTemporaryOperands(); + ++I) { + RenderedOperands.push_back(OperandPlaceholder::CreateTemporary(I)); + TempOpIdx++; } + DstMIBuilder.addRenderer( + *ComplexPattern->second, RenderedOperands); + return true; + } - if (ChildRec->isSubClassOf("ComplexPattern")) { - const auto &ComplexPattern = ComplexPatternEquivs.find(ChildRec); - if (ComplexPattern == ComplexPatternEquivs.end()) - return failedImport( - "SelectionDAG ComplexPattern not mapped to GlobalISel"); - - const auto &Predicate = OM.addPredicate( - *ComplexPattern->second, TempOpIdx); - TempOpIdx += Predicate.countTemporaryOperands(); - continue; - } + return failedImport( + "Dst pattern child def is an unsupported tablegen class"); + } - return failedImport( - "Src pattern child def is an unsupported tablegen class"); - } + return failedImport("Dst pattern child is an unsupported kind"); +} + +Expected GlobalISelEmitter::importInstructionRenderer( + RuleMatcher &M, const TreePatternNode *Dst, + const InstructionMatcher &InsnMatcher) const { + Record *DstOp = Dst->getOperator(); + if (!DstOp->isSubClassOf("Instruction")) + return failedImport("Pattern operator isn't an instruction"); + auto &DstI = Target.getInstruction(DstOp); + + auto &DstMIBuilder = M.addAction(&DstI, InsnMatcher); - return failedImport("Src pattern child is an unsupported kind"); + // Render the explicit defs. + for (unsigned I = 0; I < DstI.Operands.NumDefs; ++I) { + const auto &DstIOperand = DstI.Operands[I]; + DstMIBuilder.addRenderer(InsnMatcher, DstIOperand.Name); } - TempOpIdx = 0; - // Finally render the used operands (i.e., the children of the root operator). + // Render the explicit uses. + unsigned TempOpIdx = 0; for (unsigned i = 0, e = Dst->getNumChildren(); i != e; ++i) { - auto *DstChild = Dst->getChild(i); + if (auto Error = importExplicitUseRenderer(DstMIBuilder, Dst->getChild(i), + InsnMatcher, TempOpIdx) + .takeError()) + return std::move(Error); + } - // 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 (!DstChild->isLeaf()) { - if (DstChild->getOperator()->isSubClassOf("SDNode")) { - auto &ChildSDNI = CGP.getSDNodeInfo(DstChild->getOperator()); - if (ChildSDNI.getSDClassName() == "BasicBlockSDNode") { - DstMIBuilder.addRenderer(InsnMatcher, - DstChild->getName()); - continue; - } - } - return failedImport("Dst pattern child isn't a leaf node or an MBB"); - } + return DstMIBuilder; +} - // Otherwise, we're looking for a bog-standard RegisterClass operand. - if (DstChild->hasAnyPredicate()) - return failedImport("Dst pattern child has predicate"); - - if (auto *ChildDefInit = dyn_cast(DstChild->getLeafValue())) { - auto *ChildRec = ChildDefInit->getDef(); - - ArrayRef ChildTypes = DstChild->getExtTypes(); - if (ChildTypes.size() != 1) - return failedImport("Dst pattern child has multiple results"); - - auto OpTyOrNone = MVTToLLT(ChildTypes.front().getConcrete()); - if (!OpTyOrNone) - return failedImport("Dst operand has an unsupported type"); - - if (ChildRec->isSubClassOf("Register")) { - DstMIBuilder.addRenderer(ChildRec); - continue; - } +Expected GlobalISelEmitter::importImplicitDefRenderers( + BuildMIAction &DstMIBuilder, + const std::vector &ImplicitDefs) const { + if (!ImplicitDefs.empty()) + return failedImport("Pattern defines a physical register"); + return true; +} - if (ChildRec->isSubClassOf("RegisterClass")) { - DstMIBuilder.addRenderer(InsnMatcher, - DstChild->getName()); - continue; - } +Expected GlobalISelEmitter::runOnPattern(const PatternToMatch &P) { + // Keep track of the matchers and actions to emit. + RuleMatcher M; + M.addAction(P); - if (ChildRec->isSubClassOf("ComplexPattern")) { - const auto &ComplexPattern = ComplexPatternEquivs.find(ChildRec); - if (ComplexPattern == ComplexPatternEquivs.end()) - return failedImport( - "SelectionDAG ComplexPattern not mapped to GlobalISel"); - - SmallVector RenderedOperands; - for (unsigned I = 0; I < InsnMatcher.getOperand(DstChild->getName()) - .countTemporaryOperands(); - ++I) { - RenderedOperands.push_back(OperandPlaceholder::CreateTemporary(I)); - TempOpIdx++; - } - DstMIBuilder.addRenderer( - *ComplexPattern->second, - RenderedOperands); - continue; - } + if (auto Error = + importRulePredicates(M, P.getPredicates()->getValues()).takeError()) + return std::move(Error); - return failedImport( - "Dst pattern child def is an unsupported tablegen class"); - } + // 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 failedImport("Dst pattern root isn't a trivial operator"); + if (!isTrivialOperatorNode(Src)) + return failedImport("Src pattern root isn't a trivial operator"); + + Record *DstOp = Dst->getOperator(); + if (!DstOp->isSubClassOf("Instruction")) + return failedImport("Pattern operator isn't an instruction"); + + auto &DstI = Target.getInstruction(DstOp); + if (DstI.Operands.NumDefs != Src->getExtTypes().size()) + return failedImport("Src pattern results and dst MI defs are different"); + + InstructionMatcher &InsnMatcherTemp = M.addInstructionMatcher(); + auto InsnMatcherOrError = importSelDAGMatcher(InsnMatcherTemp, Src); + if (auto Error = InsnMatcherOrError.takeError()) + return std::move(Error); + InstructionMatcher &InsnMatcher = InsnMatcherOrError.get(); + + // The root of the match also has constraints on the register bank so that it + // matches the result instruction. + unsigned OpIdx = 0; + for (const EEVT::TypeSet &Ty : Src->getExtTypes()) { + (void)Ty; - return failedImport("Dst pattern child is an unsupported kind"); + const auto &DstIOperand = DstI.Operands[OpIdx]; + Record *DstIOpRec = DstIOperand.Rec; + if (!DstIOpRec->isSubClassOf("RegisterClass")) + return failedImport("Dst MI def isn't a register class"); + + OperandMatcher &OM = InsnMatcher.getOperand(OpIdx); + OM.setSymbolicName(DstIOperand.Name); + OM.addPredicate( + Target.getRegisterClass(DstIOpRec)); + ++OpIdx; } + auto DstMIBuilderOrError = importInstructionRenderer(M, Dst, InsnMatcher); + if (auto Error = DstMIBuilderOrError.takeError()) + return std::move(Error); + BuildMIAction &DstMIBuilder = DstMIBuilderOrError.get(); + + // Render the implicit defs. + // These are only added to the root of the result. + if (auto Error = + importImplicitDefRenderers(DstMIBuilder, P.getDstRegs()).takeError()) + return std::move(Error); + // We're done with this pattern! It's eligible for GISel emission; return it. ++NumPatternImported; return std::move(M);