diff --git a/llvm/test/TableGen/dag-isel-multiple-instructions.td b/llvm/test/TableGen/dag-isel-multiple-instructions.td new file mode 100644 --- /dev/null +++ b/llvm/test/TableGen/dag-isel-multiple-instructions.td @@ -0,0 +1,181 @@ +// RUN: llvm-tblgen -gen-dag-isel -I %p/../../include %s | FileCheck %s + +include "llvm/Target/Target.td" + +def TestTargetInstrInfo : InstrInfo; + +def TestTarget : Target { + let InstructionSet = TestTargetInstrInfo; +} + +def REG : Register<"REG">; +def GPR : RegisterClass<"TestTarget", [i32], 32, (add REG)>; + + +def FENCE : Instruction { + let OutOperandList = (outs); + let InOperandList = (ins); +} + +def LOAD : Instruction { + let OutOperandList = (outs GPR:$r0); + let InOperandList = (ins GPR:$t0); + let mayLoad = 1; +} + +def STORE : Instruction { + let OutOperandList = (outs); + let InOperandList = (ins GPR:$t0, GPR:$t1); + let mayStore = 1; +} + +class BINOP : Instruction { + let OutOperandList = (outs GPR:$r0); + let InOperandList = (ins GPR:$t0, GPR:$t1); +} +def ADD : BINOP; +def SUB : BINOP; +def MUL : BINOP; +def DIV : BINOP; + +def UDIVREM : Instruction { + let OutOperandList = (outs GPR:$r1, GPR:$r0); + let InOperandList = (ins GPR:$t0, GPR:$t1); +} + +// The patterns are written here in the order that the emitter sorts them, so +// that the CHECK lines can stay next to them. + +// CHECK-LABEL: /* 0*/ OPC_SwitchOpcode /*5 cases */, 64, TARGET_VAL(ISD::STORE),// ->68 +// CHECK-NEXT: /* 4*/ OPC_RecordMemRef, +// CHECK-NEXT: /* 5*/ OPC_RecordNode, // #0 = 'st' chained node +// CHECK-NEXT: /* 6*/ OPC_RecordChild1, // #1 = $val +// CHECK-NEXT: /* 7*/ OPC_CheckChild1Type, MVT::i32, +// CHECK-NEXT: /* 9*/ OPC_MoveChild2, +// CHECK-NEXT: /* 10*/ OPC_CheckOpcode, TARGET_VAL(ISD::LOAD), +// CHECK-NEXT: /* 13*/ OPC_RecordMemRef, +// CHECK-NEXT: /* 14*/ OPC_RecordNode, // #2 = 'ld' chained node +// CHECK-NEXT: /* 15*/ OPC_CheckFoldableChainNode, +// CHECK-NEXT: /* 16*/ OPC_MoveChild1, +// CHECK-NEXT: /* 17*/ OPC_CheckOpcode, TARGET_VAL(ISD::ADD), +// CHECK-NEXT: /* 20*/ OPC_RecordChild0, // #3 = $ptr +// CHECK-NEXT: /* 21*/ OPC_RecordChild1, // #4 = $offset +// CHECK-NEXT: /* 22*/ OPC_MoveParent, +// CHECK-NEXT: /* 23*/ OPC_CheckPredicate, 0, // Predicate_unindexedload +// CHECK-NEXT: /* 25*/ OPC_CheckPredicate, 1, // Predicate_load +// CHECK-NEXT: /* 27*/ OPC_MoveParent, +// CHECK-NEXT: /* 28*/ OPC_CheckPredicate, 2, // Predicate_unindexedstore +// CHECK-NEXT: /* 30*/ OPC_CheckPredicate, 3, // Predicate_store +// CHECK-NEXT: /* 32*/ OPC_EmitMergeInputChains, 2, 0, 2, +// CHECK-NEXT: /* 36*/ OPC_EmitNode0, TARGET_VAL(::FENCE), 0|OPFL_Chain|OPFL_MemRefs, +// CHECK-NEXT: 0/*#Ops*/, +// CHECK-NEXT: /* 41*/ OPC_EmitNode1, TARGET_VAL(::ADD), 0|OPFL_Chain, +// CHECK-NEXT: MVT::i32, 2/*#Ops*/, 3, 4, // Results = #5 +// CHECK-NEXT: /* 49*/ OPC_EmitNode1, TARGET_VAL(::LOAD), 0|OPFL_Chain, +// CHECK-NEXT: MVT::i32, 1/*#Ops*/, 5, // Results = #6 +// CHECK-NEXT: /* 56*/ OPC_EmitNode0, TARGET_VAL(::STORE), 0|OPFL_Chain|OPFL_MemRefs, +// CHECK-NEXT: 2/*#Ops*/, 1, 6, +// CHECK-NEXT: /* 63*/ OPC_MorphNodeTo0, TARGET_VAL(::FENCE), 0|OPFL_Chain|OPFL_MemRefs, +// CHECK-NEXT: 0/*#Ops*/, +// CHECK-NEXT: // Src: (st i32:{ *:[i32] }:$val, (ld:{ *:[iPTR] } (add:{ *:[i32] } i32:{ *:[i32] }:$ptr, i32:{ *:[i32] }:$offset))<><>)<><> - Complexity = 11 +// CHECK-NEXT: // Dst: ONE_TO_MANY: [(FENCE), (STORE i32:{ *:[i32] }:$val, (LOAD:{ *:[i32] } (ADD:{ *:[i32] } i32:{ *:[i32] }:$ptr, i32:{ *:[i32] }:$offset))), (FENCE), ] +def ONE_TO_MANY : Pattern<(store i32:$val, (load (add i32:$ptr, i32:$offset))), + [ + (FENCE), + (STORE i32:$val, (LOAD (ADD i32:$ptr, i32:$offset))), + (FENCE) + ]>; + + +// CHECK-LABEL: /* 68*/ /*SwitchOpcode*/ 22, TARGET_VAL(ISD::CALLSEQ_START),// ->93 +// CHECK-NEXT: /* 71*/ OPC_RecordNode, // #0 = 'AArch64callseq_start' chained node +// CHECK-NEXT: /* 72*/ OPC_RecordChild1, // #1 = $amt1 +// CHECK-NEXT: /* 73*/ OPC_MoveChild1, +// CHECK-NEXT: /* 74*/ OPC_CheckOpcode, TARGET_VAL(ISD::TargetConstant), +// CHECK-NEXT: /* 77*/ OPC_MoveParent, +// CHECK-NEXT: /* 78*/ OPC_RecordChild2, // #2 = $amt2 +// CHECK-NEXT: /* 79*/ OPC_MoveChild2, +// CHECK-NEXT: /* 80*/ OPC_CheckOpcode, TARGET_VAL(ISD::TargetConstant), +// CHECK-NEXT: /* 83*/ OPC_MoveParent, +// CHECK-NEXT: /* 84*/ OPC_EmitMergeInputChains1_0, +// CHECK-NEXT: /* 85*/ OPC_MorphNodeTo1, TARGET_VAL(::ADJCALLSTACKDOWN), 0|OPFL_Chain|OPFL_GlueOutput, +// CHECK-NEXT: MVT::i32, 2/*#Ops*/, 1, 2, +// CHECK-NEXT: // Src: (AArch64callseq_start (timm:{ *:[i32] }):$amt1, (timm:{ *:[i32] }):$amt2) - Complexity = 9 +// CHECK-NEXT: // Dst: ADJCALLSTACKDOWN: (ADJCALLSTACKDOWN:{ *:[i32] } (timm:{ *:[i32] }):$amt1, (timm:{ *:[i32] }):$amt2), +// Instruction with an implicit result (REG) in output pattern +def AArch64callseq_start : SDNode<"ISD::CALLSEQ_START", + SDCallSeqStart<[ SDTCisVT<0, i32>, SDTCisVT<1, i32> ]>, + [SDNPHasChain, SDNPOutGlue]>; +def ADJCALLSTACKDOWN : Instruction { + dag OutOperandList = (outs); + dag InOperandList = (ins i32imm:$amt1, i32imm:$amt2); + let Pattern = [(AArch64callseq_start timm:$amt1, timm:$amt2)]; + let Defs = [REG]; +} + + +// CHECK-LABEL: /* 93*/ /*SwitchOpcode*/ 48, TARGET_VAL(ISD::UDIVREM),// ->144 +// CHECK-NEXT: /* 96*/ OPC_RecordChild0, // #0 = $t0 +// CHECK-NEXT: /* 97*/ OPC_RecordChild1, // #1 = $t1 +// CHECK-NEXT: /* 98*/ OPC_Scope, 13, /*->113*/ // 2 children in Scope +// CHECK-NEXT: /* 100*/ OPC_EmitNode2, TARGET_VAL(::INSTR), 0, +// CHECK-NEXT: MVT::i32, MVT::i32, 2/*#Ops*/, 0, 1, // Results = #2 #3 +// CHECK-NEXT: /* 109*/ OPC_CompleteMatch, 2, 3, 2, +// CHECK-NEXT: // Src: (udivrem:{ *:[i32] }:{ *:[i32] } i32:{ *:[i32] }:$t0, i32:{ *:[i32] }:$t1) - Complexity = 3 +// CHECK-NEXT: // Dst: INSTR: (INSTR:{ *:[i32] }:{ *:[i32] } i32:{ *:[i32] }:$t0, i32:{ *:[i32] }:$t1), +// An instruction with a pattern +def INSTR : Instruction { + let OutOperandList = (outs GPR:$r1, GPR:$r0); + let InOperandList = (ins GPR:$t0, GPR:$t1); + let Pattern = [(set i32:$r0, i32:$r1, (udivrem i32:$t0, i32:$t1))]; +} + +// CHECK-NEXT: /* 113*/ /*Scope*/ 29, /*->143*/ +// CHECK-NEXT: /* 114*/ OPC_EmitNode0, TARGET_VAL(::FENCE), 0|OPFL_Chain, +// CHECK-NEXT: 0/*#Ops*/, +// CHECK-NEXT: /* 119*/ OPC_EmitNode1, TARGET_VAL(::DIV), 0|OPFL_Chain, +// CHECK-NEXT: MVT::i32, 2/*#Ops*/, 0, 1, // Results = #2 +// CHECK-NEXT: /* 127*/ OPC_EmitNode0, TARGET_VAL(::FENCE), 0|OPFL_Chain, +// CHECK-NEXT: 0/*#Ops*/, +// CHECK-NEXT: /* 132*/ OPC_EmitNode1, TARGET_VAL(::LOAD), 0|OPFL_Chain, +// CHECK-NEXT: MVT::i32, 1/*#Ops*/, 0, // Results = #3 +// CHECK-NEXT: /* 139*/ OPC_CompleteMatch, 2, 2, 3, +// CHECK-NEXT: // Src: (udivrem:{ *:[i32] }:{ *:[i32] } i32:{ *:[i32] }:$t0, i32:{ *:[i32] }:$t1) - Complexity = 3 +// CHECK-NEXT: // Dst: COLLECT_RESULTS: [(FENCE), (DIV:{ *:[i32] } i32:{ *:[i32] }:$t0, i32:{ *:[i32] }:$t1), (FENCE), (LOAD:{ *:[i32] } i32:{ *:[i32] }:$t0), ] +def COLLECT_RESULTS : Pattern<(udivrem i32:$t0, i32:$t1), + [ + (FENCE), + (DIV i32:$t0, i32:$t1), + (FENCE), + (LOAD i32:$t0), + ]>; + + +// CHECK-LABEL: /* 144*/ /*SwitchOpcode*/ 10, TARGET_VAL(ISD::SUB),// ->157 +// CHECK-NEXT: /* 147*/ OPC_RecordChild0, // #0 = $t0 +// CHECK-NEXT: /* 148*/ OPC_RecordChild1, // #1 = $t1 +// CHECK-NEXT: /* 149*/ OPC_MorphNodeTo1, TARGET_VAL(::SUB), 0, +// CHECK-NEXT: MVT::i32, 2/*#Ops*/, 0, 1, +// CHECK-NEXT: // Src: (sub:{ *:[i32] } i32:{ *:[i32] }:$t0, i32:{ *:[i32] }:$t1) - Complexity = 3 +// CHECK-NEXT: // Dst: ONE_TO_ONE: (SUB:{ *:[i32] } i32:{ *:[i32] }:$t0, i32:{ *:[i32] }:$t1), +def ONE_TO_ONE : Pattern<(sub i32:$t0, i32:$t1), + [ + (SUB i32:$t0, i32:$t1) + ]>; + + +// CHECK-LABEL: /* 157*/ /*SwitchOpcode*/ 18, TARGET_VAL(ISD::MUL),// ->178 +// CHECK-NEXT: /* 160*/ OPC_RecordChild0, // #0 = $t0 +// CHECK-NEXT: /* 161*/ OPC_RecordChild1, // #1 = $t1 +// CHECK-NEXT: /* 162*/ OPC_EmitNode1, TARGET_VAL(::MUL), 0|OPFL_Chain, +// CHECK-NEXT: MVT::i32, 2/*#Ops*/, 0, 1, // Results = #2 +// CHECK-NEXT: /* 170*/ OPC_EmitNode0, TARGET_VAL(::FENCE), 0|OPFL_Chain, +// CHECK-NEXT: 0/*#Ops*/, +// CHECK-NEXT: /* 175*/ OPC_CompleteMatch, 1, 2, +// CHECK-NEXT: // Src: (mul:{ *:[i32] } i32:{ *:[i32] }:$t0, i32:{ *:[i32] }:$t1) - Complexity = 3 +// CHECK-NEXT: // Dst: ONE_TO_TWO: [(MUL:{ *:[i32] } i32:{ *:[i32] }:$t0, i32:{ *:[i32] }:$t1), (FENCE), ] +def ONE_TO_TWO : Pattern<(mul i32:$t0, i32:$t1), + [ + (MUL i32:$t0, i32:$t1), + (FENCE) + ]>; diff --git a/llvm/utils/TableGen/CodeGenDAGPatterns.h b/llvm/utils/TableGen/CodeGenDAGPatterns.h --- a/llvm/utils/TableGen/CodeGenDAGPatterns.h +++ b/llvm/utils/TableGen/CodeGenDAGPatterns.h @@ -256,6 +256,7 @@ raw_ostream &operator<<(raw_ostream &OS, const TypeSetByHwMode &T); +/// Only ever used by TreePattern struct TypeInfer { TypeInfer(TreePattern &T) : TP(T) {} @@ -353,6 +354,7 @@ bool SavedValidate; }; + /// Reference to the TreePattern which owns this TypeInfer instance. TreePattern &TP; bool Validate = true; // Indicate whether to validate types. @@ -917,8 +919,12 @@ CodeGenDAGPatterns &ise); TreePattern(Record *TheRec, DagInit *Pat, bool isInput, CodeGenDAGPatterns &ise); + /// Construct from a single pattern TreePattern(Record *TheRec, TreePatternNodePtr Pat, bool isInput, CodeGenDAGPatterns &ise); + /// Construct from multiple patterns + TreePattern(Record *TheRec, std::vector &Pat, + bool isInput, CodeGenDAGPatterns &ise); /// getTrees - Return the tree patterns which corresponds to this pattern. /// @@ -980,6 +986,8 @@ TypeInfer &getInfer() { return Infer; } + bool hasProperTypeByHwMode() const; + void print(raw_ostream &OS) const; void dump() const; @@ -989,6 +997,10 @@ void ComputeNamedNodes(TreePatternNode *N); }; +inline raw_ostream &operator<<(raw_ostream &OS, const TreePattern &TP) { + TP.print(OS); + return OS; +} inline bool TreePatternNode::UpdateNodeType(unsigned ResNo, const TypeSetByHwMode &InTy, @@ -1065,31 +1077,28 @@ /// PatternToMatch - Used by CodeGenDAGPatterns to keep tab of patterns /// processed to produce isel. class PatternToMatch { - Record *SrcRecord; // Originating Record for the pattern. - ListInit *Predicates; // Top level predicate conditions to match. - TreePatternNodePtr SrcPattern; // Source pattern to match. - TreePatternNodePtr DstPattern; // Resulting pattern. - std::vector Dstregs; // Physical register defs being matched. - std::string HwModeFeatures; - int AddedComplexity; // Add to matching pattern complexity. - unsigned ID; // Unique ID for the record. + Record *SrcRecord; // Originating Record for the pattern. + ListInit *Predicates; // Top level predicate conditions to match. + TreePatternNodePtr SrcTree; // Source pattern to match. + TreePattern DstPattern; // Resulting pattern. May contain multiple nodes. + std::vector Dstregs; // Physical register defs being matched. + std::string HwModeFeatures; + int AddedComplexity; // Add to matching pattern complexity. + unsigned ID; // Unique ID for the record. public: PatternToMatch(Record *srcrecord, ListInit *preds, TreePatternNodePtr src, - TreePatternNodePtr dst, std::vector dstregs, - int complexity, unsigned uid, - const Twine &hwmodefeatures = "") - : SrcRecord(srcrecord), Predicates(preds), SrcPattern(src), - DstPattern(dst), Dstregs(std::move(dstregs)), - HwModeFeatures(hwmodefeatures.str()), AddedComplexity(complexity), - ID(uid) {} + TreePattern dst, std::vector dstregs, int complexity, + unsigned uid, const Twine &hwmodefeatures = "") + : SrcRecord(srcrecord), Predicates(preds), SrcTree(src), DstPattern(dst), + Dstregs(std::move(dstregs)), HwModeFeatures(hwmodefeatures.str()), + AddedComplexity(complexity), ID(uid) {} Record *getSrcRecord() const { return SrcRecord; } ListInit *getPredicates() const { return Predicates; } - TreePatternNode *getSrcPattern() const { return SrcPattern.get(); } - TreePatternNodePtr getSrcPatternShared() const { return SrcPattern; } - TreePatternNode *getDstPattern() const { return DstPattern.get(); } - TreePatternNodePtr getDstPatternShared() const { return DstPattern; } + TreePatternNode *getSrcPattern() const { return SrcTree.get(); } + TreePatternNodePtr getSrcPatternShared() const { return SrcTree; } + const TreePattern &getDstPattern() const { return DstPattern; } const std::vector &getDstRegs() const { return Dstregs; } StringRef getHwModeFeatures() const { return HwModeFeatures; } int getAddedComplexity() const { return AddedComplexity; } diff --git a/llvm/utils/TableGen/CodeGenDAGPatterns.cpp b/llvm/utils/TableGen/CodeGenDAGPatterns.cpp --- a/llvm/utils/TableGen/CodeGenDAGPatterns.cpp +++ b/llvm/utils/TableGen/CodeGenDAGPatterns.cpp @@ -2829,6 +2829,13 @@ Trees.push_back(Pat); } +TreePattern::TreePattern(Record *TheRec, std::vector &Pats, + bool isInput, CodeGenDAGPatterns &cdp) + : TheRecord(TheRec), CDP(cdp), isInputPattern(isInput), HasError(false), + Infer(*this) { + Trees = Pats; +} + void TreePattern::error(const Twine &Msg) { if (HasError) return; @@ -3149,6 +3156,11 @@ return !HasUnresolvedTypes; } +bool TreePattern::hasProperTypeByHwMode() const { + return llvm::any_of(getTrees(), + [](auto &T) { return T->hasProperTypeByHwMode(); }); +} + void TreePattern::print(raw_ostream &OS) const { OS << getRecord()->getName(); if (!Args.empty()) { @@ -3161,11 +3173,10 @@ OS << ": "; if (Trees.size() > 1) - OS << "[\n"; + OS << "["; for (const TreePatternNodePtr &Tree : Trees) { - OS << "\t"; Tree->print(OS); - OS << "\n"; + OS << ", "; } if (Trees.size() > 1) @@ -3743,8 +3754,8 @@ } /// Get all the instructions in a tree. -static void -getInstructionsInTree(TreePatternNode *Tree, SmallVectorImpl &Instrs) { +static void getInstructionsInTree(const TreePatternNode *Tree, + SmallVectorImpl &Instrs) { if (Tree->isLeaf()) return; if (Tree->getOperator()->isSubClassOf("Instruction")) @@ -3752,6 +3763,12 @@ for (unsigned i = 0, e = Tree->getNumChildren(); i != e; ++i) getInstructionsInTree(Tree->getChild(i), Instrs); } +/// Get all the instructions in all trees in a pattern. +static void getInstructionsInPattern(const TreePattern &Pat, + SmallVectorImpl &Instrs) { + for (const auto &Tree : Pat.getTrees()) + getInstructionsInTree(Tree.get(), Instrs); +} /// Check the class of a pattern leaf node against the instruction operand it /// represents. @@ -4053,7 +4070,8 @@ // same type. std::map SrcNames, DstNames; FindNames(PTM.getSrcPattern(), SrcNames, Pattern); - FindNames(PTM.getDstPattern(), DstNames, Pattern); + for (const auto &Tree : PTM.getDstPattern().getTrees()) + FindNames(Tree.get(), DstNames, Pattern); // Scan all of the named values in the destination pattern, rejecting them if // they don't exist in the input pattern. @@ -4086,7 +4104,7 @@ // We can only infer from single-instruction patterns, otherwise we won't // know which instruction should get the flags. SmallVector PatInstrs; - getInstructionsInTree(PTM.getDstPattern(), PatInstrs); + getInstructionsInPattern(PTM.getDstPattern(), PatInstrs); if (PatInstrs.size() != 1) continue; @@ -4144,7 +4162,7 @@ unsigned Errors = 0; for (const PatternToMatch &PTM : ptms()) { SmallVector Instrs; - getInstructionsInTree(PTM.getDstPattern(), Instrs); + getInstructionsInPattern(PTM.getDstPattern(), Instrs); if (Instrs.empty()) continue; @@ -4252,16 +4270,13 @@ return N; } -void CodeGenDAGPatterns::ParseOnePattern(Record *TheDef, - TreePattern &Pattern, TreePattern &Result, - const std::vector &InstImpResults) { +void CodeGenDAGPatterns::ParseOnePattern( + Record *TheDef, TreePattern &InPattern, TreePattern &OutPattern, + const std::vector &InstImpResults) { // Inline pattern fragments and expand multiple alternatives. - Pattern.InlinePatternFragments(); - Result.InlinePatternFragments(); - - if (Result.getNumTrees() != 1) - Result.error("Cannot use multi-alternative fragments in result pattern!"); + InPattern.InlinePatternFragments(); + OutPattern.InlinePatternFragments(); // Infer types. bool IterateInference; @@ -4270,28 +4285,61 @@ // Infer as many types as possible. If we cannot infer all of them, we // can never do anything with this pattern: report it to the user. InferredAllPatternTypes = - Pattern.InferAllTypes(&Pattern.getNamedNodesMap()); + InPattern.InferAllTypes(&InPattern.getNamedNodesMap()); // Infer as many types as possible. If we cannot infer all of them, we // can never do anything with this pattern: report it to the user. InferredAllResultTypes = - Result.InferAllTypes(&Pattern.getNamedNodesMap()); + OutPattern.InferAllTypes(&InPattern.getNamedNodesMap()); IterateInference = false; - // Apply the type of the result to the source pattern. This helps us - // resolve cases where the input type is known to be a pointer type (which - // is considered resolved), but the result knows it needs to be 32- or - // 64-bits. Infer the other way for good measure. - for (const auto &T : Pattern.getTrees()) - for (unsigned i = 0, e = std::min(Result.getOnlyTree()->getNumTypes(), - T->getNumTypes()); - i != e; ++i) { - IterateInference |= T->UpdateNodeType( - i, Result.getOnlyTree()->getExtType(i), Result); - IterateInference |= Result.getOnlyTree()->UpdateNodeType( - i, T->getExtType(i), Result); + // For output patterns with multiple trees, the result types of each tree + // are simply concatenated. We need to track which of the output trees each + // result corresponds to, and how many results that tree produced. + std::vector FlatOutTypes; + using FlatInstrRange = + std::pair; // instr idx, number of results + std::vector FlatOutRanges; + for (unsigned iTree = 0; iTree < OutPattern.getNumTrees(); ++iTree) { + const TreePatternNodePtr &OutTree = OutPattern.getTree(iTree); + // Note: getNumTypes() may include one(?) implicit def. + FlatOutRanges.emplace_back(iTree, OutTree->getNumTypes()); + for (const TypeSetByHwMode &TypeSet : OutTree->getExtTypes()) { + FlatOutTypes.push_back(TypeSet); } + } + + // Apply the type of each result to each source pattern and vice versa. This + // helps us resolve cases where the input type is known to be a pointer type + // (which is considered resolved), but the result knows it needs to be 32- + // or 64-bits. + for (const TreePatternNodePtr &InTree : InPattern.getTrees()) { + // Apply output pattern types to input tree + const unsigned N = + std::min(InTree->getNumTypes(), (unsigned)FlatOutTypes.size()); + for (unsigned i = 0; i < N; ++i) + IterateInference |= + InTree->UpdateNodeType(i, FlatOutTypes[i], OutPattern); + // Apply input pattern types to output tree + for (const FlatInstrRange &Range : FlatOutRanges) { + unsigned InstrIdx = Range.first; + unsigned NumResults = Range.second; + unsigned gIdx = 0; // total number of results handled so far + for (unsigned i = 0; i < NumResults; ++i) { + // If implicit def type has been added to the result types, we can + // end up with NumResults exceeding the number of input results. + // However, in the case of multiple results, we don't know which + // instruction the implicit def(s) came from. So just make sure we + // don't go out of bounds. + // FIXME all of the implicit def handling needs cleaned up. + if (gIdx >= InTree->getNumResults()) + break; + IterateInference |= OutPattern.getTree(InstrIdx)->UpdateNodeType( + i, InTree->getExtType(gIdx++), OutPattern); + } + } + } // If our iteration has converged and the input pattern's types are fully // resolved but the result pattern is not fully resolved, we may have a @@ -4302,32 +4350,34 @@ // // In any case, to handle this, we just go through and disambiguate some // arbitrary types to the result pattern's nodes. - if (!IterateInference && InferredAllPatternTypes && - !InferredAllResultTypes) - IterateInference = - ForceArbitraryInstResultType(Result.getTree(0).get(), Result); + if (!IterateInference && InferredAllPatternTypes && !InferredAllResultTypes) + for (const TreePatternNodePtr &OT : OutPattern.getTrees()) + IterateInference = ForceArbitraryInstResultType(OT.get(), OutPattern); } while (IterateInference); // Verify that we inferred enough types that we can do something with the // pattern and result. If these fire the user has to add type casts. if (!InferredAllPatternTypes) - Pattern.error("Could not infer all types in pattern!"); + InPattern.error("Could not infer all types in pattern!"); if (!InferredAllResultTypes) { - Pattern.dump(); - Result.error("Could not infer all types in pattern result!"); + InPattern.dump(); + OutPattern.error("Could not infer all types in pattern result!"); } // Promote xform function to be an explicit node wherever set. - TreePatternNodePtr DstShared = PromoteXForms(Result.getOnlyTree()); + std::vector ExpandedOutTrees; + for (auto &RT : OutPattern.getTrees()) + ExpandedOutTrees.push_back(PromoteXForms(RT)); - TreePattern Temp(Result.getRecord(), DstShared, false, *this); - Temp.InferAllTypes(); + TreePattern ExpandedOutPattern(OutPattern.getRecord(), ExpandedOutTrees, + false, *this); + ExpandedOutPattern.InferAllTypes(); ListInit *Preds = TheDef->getValueAsListInit("Predicates"); int Complexity = TheDef->getValueAsInt("AddedComplexity"); if (PatternRewriter) - PatternRewriter(&Pattern); + PatternRewriter(&InPattern); // A pattern may end up with an "impossible" type, i.e. a situation // where all types have been eliminated for some node in this pattern. @@ -4336,23 +4386,33 @@ // that register class does not accept that type, the type inference // will lead to a contradiction, which is not an error however, but // a sign that this pattern will simply never match. - if (Temp.getOnlyTree()->hasPossibleType()) { - for (const auto &T : Pattern.getTrees()) { - if (T->hasPossibleType()) - AddPatternToMatch(&Pattern, - PatternToMatch(TheDef, Preds, T, Temp.getOnlyTree(), - InstImpResults, Complexity, - TheDef->getID())); + for (const auto &OutTree : ExpandedOutPattern.getTrees()) { + if (!OutTree->hasPossibleType()) { + // Show a message about a dropped pattern with some info to make it + // easier to identify it in the .td files. + LLVM_DEBUG({ + dbgs() << "Dropping: "; + InPattern.dump(); + ExpandedOutPattern.dump(); + dbgs() << "\n"; + if (ExpandedOutPattern.getNumTrees() > 1) { + dbgs() << " ...because this result tree has no possible types: "; + OutTree->dump(); + dbgs() << "\n"; + } + }); + return; } - } else { - // Show a message about a dropped pattern with some info to make it - // easier to identify it in the .td files. - LLVM_DEBUG({ - dbgs() << "Dropping: "; - Pattern.dump(); - Temp.getOnlyTree()->dump(); - dbgs() << "\n"; - }); + } + + // All result trees have possible types. Add a PatternToMatch for each input + // tree which has possible types. + for (const auto &InTree : InPattern.getTrees()) { + if (InTree->hasPossibleType()) + AddPatternToMatch(&InPattern, + PatternToMatch(TheDef, Preds, InTree, + ExpandedOutPattern, InstImpResults, + Complexity, TheDef->getID())); } } @@ -4374,10 +4434,6 @@ // Parse the instruction. TreePattern Result(CurPattern, LI, false, *this); - if (Result.getNumTrees() != 1) - Result.error("Cannot handle instructions producing instructions " - "with temporaries yet!"); - // Validate that the input pattern is correct. std::map InstInputs; MapVector> @@ -4400,6 +4456,12 @@ collectModes(Modes, N->getChild(i)); } +static void collectModes(std::set &Modes, + const TreePattern &Pattern) { + for (const auto &Tree : Pattern.getTrees()) + collectModes(Modes, Tree.get()); +} + void CodeGenDAGPatterns::ExpandHwModeBasedTypes() { const CodeGenHwModes &CGH = getTargetInfo().getHwModes(); if (CGH.getNumModeIds() == 1) @@ -4411,10 +4473,12 @@ auto AppendPattern = [this](PatternToMatch &P, unsigned Mode, StringRef Check) { TreePatternNodePtr NewSrc = P.getSrcPattern()->clone(); - TreePatternNodePtr NewDst = P.getDstPattern()->clone(); - if (!NewSrc->setDefaultMode(Mode) || !NewDst->setDefaultMode(Mode)) { + TreePattern NewDst = P.getDstPattern(); + if (!NewSrc->setDefaultMode(Mode)) return; - } + for (auto &DstTree : NewDst.getTrees()) + if (!DstTree->setDefaultMode(Mode)) + return; PatternsToMatch.emplace_back(P.getSrcRecord(), P.getPredicates(), std::move(NewSrc), std::move(NewDst), @@ -4423,11 +4487,12 @@ }; for (PatternToMatch &P : Copy) { - const TreePatternNode *SrcP = nullptr, *DstP = nullptr; + const TreePatternNode *SrcP = nullptr; + const TreePattern *DstP = nullptr; if (P.getSrcPattern()->hasProperTypeByHwMode()) SrcP = P.getSrcPattern(); - if (P.getDstPattern()->hasProperTypeByHwMode()) - DstP = P.getDstPattern(); + if (P.getDstPattern().hasProperTypeByHwMode()) + DstP = &P.getDstPattern(); if (!SrcP && !DstP) { PatternsToMatch.push_back(P); continue; @@ -4437,7 +4502,7 @@ if (SrcP) collectModes(Modes, SrcP); if (DstP) - collectModes(Modes, DstP); + collectModes(Modes, *DstP); // The predicate for the default mode needs to be constructed for each // pattern separately. @@ -4787,7 +4852,7 @@ // Otherwise, add it to the list of patterns we have. PatternsToMatch.emplace_back( PatternsToMatch[i].getSrcRecord(), PatternsToMatch[i].getPredicates(), - Variant, PatternsToMatch[i].getDstPatternShared(), + Variant, PatternsToMatch[i].getDstPattern(), PatternsToMatch[i].getDstRegs(), PatternsToMatch[i].getAddedComplexity(), Record::getNewUID(Records), PatternsToMatch[i].getHwModeFeatures()); diff --git a/llvm/utils/TableGen/DAGISelEmitter.cpp b/llvm/utils/TableGen/DAGISelEmitter.cpp --- a/llvm/utils/TableGen/DAGISelEmitter.cpp +++ b/llvm/utils/TableGen/DAGISelEmitter.cpp @@ -37,12 +37,13 @@ // DAGISelEmitter Helper methods // -/// getResultPatternCost - Compute the number of instructions for this pattern. +/// Compute the number of instructions for this tree. /// This is a temporary hack. We should really include the instruction /// latencies in this calculation. -static unsigned getResultPatternCost(TreePatternNode *P, - CodeGenDAGPatterns &CGP) { - if (P->isLeaf()) return 0; +static unsigned getResultPatternCost(const TreePatternNode *P, + const CodeGenDAGPatterns &CGP) { + if (P->isLeaf()) + return 0; unsigned Cost = 0; Record *Op = P->getOperator(); @@ -57,11 +58,20 @@ return Cost; } -/// getResultPatternCodeSize - Compute the code size of instructions for this -/// pattern. -static unsigned getResultPatternSize(TreePatternNode *P, - CodeGenDAGPatterns &CGP) { - if (P->isLeaf()) return 0; +/// Compute the number of instructions for this pattern. +static unsigned getResultPatternCost(const TreePattern &P, + const CodeGenDAGPatterns &CGP) { + unsigned Cost = 0; + for (const TreePatternNodePtr &Tree : P.getTrees()) + Cost += getResultPatternCost(Tree.get(), CGP); + return Cost; +} + +/// Compute the code size of instructions for this tree. +static unsigned getResultPatternSize(const TreePatternNode *P, + const CodeGenDAGPatterns &CGP) { + if (P->isLeaf()) + return 0; unsigned Cost = 0; Record *Op = P->getOperator(); @@ -73,6 +83,15 @@ return Cost; } +/// Compute the code size of instructions for this pattern. +static unsigned getResultPatternSize(const TreePattern &P, + const CodeGenDAGPatterns &CGP) { + unsigned Size = 0; + for (const TreePatternNodePtr &Tree : P.getTrees()) + Size += getResultPatternSize(Tree.get(), CGP); + return Size; +} + namespace { // PatternSortingPredicate - return true if we prefer to match LHS before RHS. // In particular, we want to match maximal patterns first and lowest cost within @@ -149,7 +168,7 @@ errs() << "PATTERN: "; I->getSrcPattern()->dump(); errs() << "\nRESULT: "; - I->getDstPattern()->dump(); + I->getDstPattern().dump(); errs() << "\n"; }); diff --git a/llvm/utils/TableGen/DAGISelMatcher.cpp b/llvm/utils/TableGen/DAGISelMatcher.cpp --- a/llvm/utils/TableGen/DAGISelMatcher.cpp +++ b/llvm/utils/TableGen/DAGISelMatcher.cpp @@ -305,7 +305,7 @@ void CompleteMatchMatcher::printImpl(raw_ostream &OS, unsigned indent) const { OS.indent(indent) << "CompleteMatch \n"; OS.indent(indent) << "Src = " << *Pattern.getSrcPattern() << "\n"; - OS.indent(indent) << "Dst = " << *Pattern.getDstPattern() << "\n"; + OS.indent(indent) << "Dst = " << Pattern.getDstPattern() << "\n"; } bool CheckOpcodeMatcher::isEqualImpl(const Matcher *M) const { diff --git a/llvm/utils/TableGen/DAGISelMatcherEmitter.cpp b/llvm/utils/TableGen/DAGISelMatcherEmitter.cpp --- a/llvm/utils/TableGen/DAGISelMatcherEmitter.cpp +++ b/llvm/utils/TableGen/DAGISelMatcherEmitter.cpp @@ -22,6 +22,7 @@ #include "llvm/ADT/TinyPtrVector.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Format.h" +#include "llvm/Support/ScopedPrinter.h" // for llvm::to_string #include "llvm/Support/SourceMgr.h" #include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" @@ -166,13 +167,6 @@ }; } // end anonymous namespace. -static std::string GetPatFromTreePatternNode(const TreePatternNode *N) { - std::string str; - raw_string_ostream Stream(str); - Stream << *N; - return str; -} - static unsigned GetVBRSize(unsigned Val) { if (Val <= 127) return 1; @@ -757,10 +751,8 @@ if (const MorphNodeToMatcher *SNT = dyn_cast(N)) { NumCoveredBytes = 3; OS << "OPC_Coverage, "; - std::string src = - GetPatFromTreePatternNode(SNT->getPattern().getSrcPattern()); - std::string dst = - GetPatFromTreePatternNode(SNT->getPattern().getDstPattern()); + std::string src = to_string(*SNT->getPattern().getSrcPattern()); + std::string dst = to_string(SNT->getPattern().getDstPattern()); Record *PatRecord = SNT->getPattern().getSrcRecord(); std::string include_src = getIncludePath(PatRecord); unsigned Offset = @@ -821,8 +813,8 @@ OS.indent(FullIndexWidth + Indent) << "// Src: " << *SNT->getPattern().getSrcPattern() << " - Complexity = " << SNT->getPattern().getPatternComplexity(CGP) << '\n'; - OS.indent(FullIndexWidth + Indent) << "// Dst: " - << *SNT->getPattern().getDstPattern() << '\n'; + OS.indent(FullIndexWidth + Indent) + << "// Dst: " << SNT->getPattern().getDstPattern() << '\n'; } } else OS << '\n'; @@ -836,10 +828,8 @@ if (InstrumentCoverage) { NumCoveredBytes = 3; OS << "OPC_Coverage, "; - std::string src = - GetPatFromTreePatternNode(CM->getPattern().getSrcPattern()); - std::string dst = - GetPatFromTreePatternNode(CM->getPattern().getDstPattern()); + std::string src = to_string(*CM->getPattern().getSrcPattern()); + std::string dst = to_string(CM->getPattern().getDstPattern()); Record *PatRecord = CM->getPattern().getSrcRecord(); std::string include_src = getIncludePath(PatRecord); unsigned Offset = @@ -856,8 +846,8 @@ OS.indent(FullIndexWidth + Indent) << " // Src: " << *CM->getPattern().getSrcPattern() << " - Complexity = " << CM->getPattern().getPatternComplexity(CGP) << '\n'; - OS.indent(FullIndexWidth + Indent) << " // Dst: " - << *CM->getPattern().getDstPattern(); + OS.indent(FullIndexWidth + Indent) + << " // Dst: " << CM->getPattern().getDstPattern(); } OS << '\n'; return 2 + NumResultBytes + NumCoveredBytes; diff --git a/llvm/utils/TableGen/DAGISelMatcherGen.cpp b/llvm/utils/TableGen/DAGISelMatcherGen.cpp --- a/llvm/utils/TableGen/DAGISelMatcherGen.cpp +++ b/llvm/utils/TableGen/DAGISelMatcherGen.cpp @@ -13,8 +13,10 @@ #include "DAGISelMatcher.h" #include "InfoByHwMode.h" #include "SDNodeProperties.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" #include @@ -774,6 +776,14 @@ return Count; } +static unsigned numNodesThatMayLoadOrStore(const TreePattern &Pattern, + const CodeGenDAGPatterns &CGP) { + unsigned Count = 0; + for (const auto &Tree : Pattern.getTrees()) + Count += numNodesThatMayLoadOrStore(Tree.get(), CGP); + return Count; +} + void MatcherGen:: EmitResultInstructionAsOperand(const TreePatternNode *N, SmallVectorImpl &OutputOps) { @@ -782,19 +792,24 @@ CodeGenInstruction &II = CGT.getInstruction(Op); const DAGInstruction &Inst = CGP.getInstruction(Op); - bool isRoot = N == Pattern.getDstPattern(); + // Is this the root of the first/last tree in the output TreePattern? + const bool isFirstRoot = N == Pattern.getDstPattern().getTrees().front(); + const bool isLastRoot = N == Pattern.getDstPattern().getTrees().back(); + // Is this any one of the roots? + const bool isAnyRoot = llvm::any_of(Pattern.getDstPattern().getTrees(), + [&](auto &T) { return N == T; }); + + const TreePatternNode *SrcPat = Pattern.getSrcPattern(); - // TreeHasOutGlue - True if this tree has glue. - bool TreeHasInGlue = false, TreeHasOutGlue = false; - if (isRoot) { - const TreePatternNode *SrcPat = Pattern.getSrcPattern(); + bool TreeHasInGlue = false; + if (isFirstRoot) { TreeHasInGlue = SrcPat->TreeHasProperty(SDNPOptInGlue, CGP) || SrcPat->TreeHasProperty(SDNPInGlue, CGP); - - // FIXME2: this is checking the entire pattern, not just the node in - // question, doing this just for the root seems like a total hack. - TreeHasOutGlue = SrcPat->TreeHasProperty(SDNPOutGlue, CGP); } + // FIXME2: this is checking the entire pattern, not just the node in + // question, doing this just for the root seems like a total hack. + const bool TreeHasOutGlue = + isLastRoot && SrcPat->TreeHasProperty(SDNPOutGlue, CGP); // NumResults - This is the number of results produced by the instruction in // the "outs" list. @@ -883,7 +898,7 @@ // If this node has input glue or explicitly specified input physregs, we // need to add chained and glued copyfromreg nodes and materialize the glue // input. - if (isRoot && !PhysRegInputs.empty()) { + if (isFirstRoot && !PhysRegInputs.empty()) { // Emit all of the CopyToReg nodes for the input physical registers. These // occur in patterns like (mul:i8 AL:i8, GR8:i8:$src). for (unsigned i = 0, e = PhysRegInputs.size(); i != e; ++i) { @@ -905,12 +920,13 @@ for (unsigned i = 0, e = N->getNumTypes(); i != e; ++i) ResultVTs.push_back(N->getSimpleType(i)); - // If this is the root instruction of a pattern that has physical registers in - // its result pattern, add output VTs for them. For example, X86 has: + // If this is the last root instruction of a pattern that has physical + // registers in its result pattern, add output VTs for them. For example, X86 + // has: // (set AL, (mul ...)) // This also handles implicit results like: // (implicit EFLAGS) - if (isRoot && !Pattern.getDstRegs().empty()) { + if (isLastRoot && !Pattern.getDstRegs().empty()) { // If the root came from an implicit def in the instruction handling stuff, // don't re-add it. Record *HandledReg = nullptr; @@ -926,37 +942,40 @@ // If this is the root of the pattern and the pattern we're matching includes // a node that is variadic, mark the generated node as variadic so that it // gets the excess operands from the input DAG. + const bool srcIsVariadic = + Pattern.getSrcPattern()->NodeHasProperty(SDNPVariadic, CGP); + if (Pattern.getDstPattern().getNumTrees() > 1 && srcIsVariadic) + llvm_unreachable("Unimplemented: Variadic patterns with multiple outputs"); int NumFixedArityOperands = -1; - if (isRoot && - Pattern.getSrcPattern()->NodeHasProperty(SDNPVariadic, CGP)) + if (isFirstRoot && srcIsVariadic) NumFixedArityOperands = Pattern.getSrcPattern()->getNumChildren(); - // If this is the root node and multiple matched nodes in the input pattern - // have MemRefs in them, have the interpreter collect them and plop them onto - // this node. If there is just one node with MemRefs, leave them on that node - // even if it is not the root. + // NodeTakesMemRefs indicates that OPFL_MemRefs will be set for the node, + // which results in *all* of the MemRefs from the input pattern being applied + // to it. This should be modelled more accurately, but for now we + // conservatively set it for *all* top level (root) instructions (unless we + // can identify a unique memory-accessing instruction). // // FIXME3: This is actively incorrect for result patterns with multiple // memory-referencing instructions. - bool PatternHasMemOperands = - Pattern.getSrcPattern()->TreeHasProperty(SDNPMemOperand, CGP); - - bool NodeHasMemRefs = false; - if (PatternHasMemOperands) { - unsigned NumNodesThatLoadOrStore = - numNodesThatMayLoadOrStore(Pattern.getDstPattern(), CGP); - bool NodeIsUniqueLoadOrStore = mayInstNodeLoadOrStore(N, CGP) && - NumNodesThatLoadOrStore == 1; - NodeHasMemRefs = - NodeIsUniqueLoadOrStore || (isRoot && (mayInstNodeLoadOrStore(N, CGP) || - NumNodesThatLoadOrStore != 1)); + bool NodeTakesMemRefs = false; + if (Pattern.getSrcPattern()->TreeHasProperty(SDNPMemOperand, CGP)) { + const unsigned NumNodesThatLoadOrStore = + numNodesThatMayLoadOrStore(Pattern.getDstPattern(), CGP); + const bool NMayLoadOrStore = mayInstNodeLoadOrStore(N, CGP); + const bool NodeIsUniqueLoadOrStore = + NMayLoadOrStore && NumNodesThatLoadOrStore == 1; + NodeTakesMemRefs = + NodeIsUniqueLoadOrStore || + (isAnyRoot && (NMayLoadOrStore || NumNodesThatLoadOrStore != 1)); } // Determine whether we need to attach a chain to this node. bool NodeHasChain = false; if (Pattern.getSrcPattern()->TreeHasProperty(SDNPHasChain, CGP)) { // For some instructions, we were able to infer from the pattern whether - // they should have a chain. Otherwise, attach the chain to the root. + // they should have a chain. Otherwise, attach the chain to all top level + // instructions (roots). // // FIXME2: This is extremely dubious for several reasons, not the least of // which it gives special status to instructions with patterns that Pat<> @@ -964,20 +983,25 @@ if (II.hasChain_Inferred) NodeHasChain = II.hasChain; else - NodeHasChain = isRoot; + NodeHasChain = isAnyRoot; // Instructions which load and store from memory should have a chain, // regardless of whether they happen to have a pattern saying so. if (II.hasCtrlDep || II.mayLoad || II.mayStore || II.canFoldAsLoad || II.hasSideEffects) NodeHasChain = true; } + // Any instruction which is one of multiple outputs must have a chain + if (Pattern.getDstPattern().getNumTrees() > 1) + NodeHasChain = true; - assert((!ResultVTs.empty() || TreeHasOutGlue || NodeHasChain) && - "Node has no result"); + if ((ResultVTs.empty() && !TreeHasOutGlue && !NodeHasChain)) { + errs() << *N << '\n'; + PrintFatalError("Node has no results"); + } - AddMatcher(new EmitNodeMatcher(II, ResultVTs, InstOps, NodeHasChain, - TreeHasInGlue, TreeHasOutGlue, NodeHasMemRefs, - NumFixedArityOperands, NextRecordedOperandNo)); + AddMatcher(new EmitNodeMatcher( + II, ResultVTs, InstOps, NodeHasChain, TreeHasInGlue, TreeHasOutGlue, + NodeTakesMemRefs, NumFixedArityOperands, NextRecordedOperandNo)); // The non-chain and non-glue results of the newly emitted node get recorded. for (unsigned i = 0, e = ResultVTs.size(); i != e; ++i) { @@ -1034,7 +1058,11 @@ // Codegen the root of the result pattern, capturing the resulting values. SmallVector Ops; - EmitResultOperand(Pattern.getDstPattern(), Ops); + for (const TreePatternNodePtr &Tree : Pattern.getDstPattern().getTrees()) { + SmallVector Tmp; + EmitResultOperand(Tree.get(), Tmp); + Ops.append(Tmp); + } // At this point, we have however many values the result pattern produces. // However, the input pattern might not need all of these. If there are @@ -1049,7 +1077,7 @@ // If the root came from an implicit def in the instruction handling stuff, // don't re-add it. Record *HandledReg = nullptr; - const TreePatternNode *DstPat = Pattern.getDstPattern(); + const TreePatternNodePtr DstPat = Pattern.getDstPattern().getOnlyTree(); if (!DstPat->isLeaf() &&DstPat->getOperator()->isSubClassOf("Instruction")){ const CodeGenTarget &CGT = CGP.getTargetInfo(); CodeGenInstruction &II = CGT.getInstruction(DstPat->getOperator()); @@ -1064,12 +1092,22 @@ } } - SmallVector Results(Ops); + SmallVector Results(Ops.size()); // Apply result permutation. - for (unsigned ResNo = 0; ResNo < Pattern.getDstPattern()->getNumResults(); - ++ResNo) { - Results[ResNo] = Ops[Pattern.getDstPattern()->getResultIndex(ResNo)]; + // If there are multiple result instructions, the results of each root are + // added in order but each set may be permuted. + // + // e.g. inst1 and inst2 results appear in order, but inst2 results are + // permuted: + // src pattern: a, b, c = some_ops(); + // dst pattern: [a = inst1(); c, b = inst2();] + unsigned ResBase = 0; + for (const auto &Tree : Pattern.getDstPattern().getTrees()) { + for (unsigned i = 0; i < Tree->getNumTypes(); ++i) { + Results[ResBase + i] = Ops[ResBase + Tree->getResultIndex(i)]; + } + ResBase += Tree->getNumTypes(); } Results.resize(NumSrcResults); diff --git a/llvm/utils/TableGen/FastISelEmitter.cpp b/llvm/utils/TableGen/FastISelEmitter.cpp --- a/llvm/utils/TableGen/FastISelEmitter.cpp +++ b/llvm/utils/TableGen/FastISelEmitter.cpp @@ -448,8 +448,11 @@ // For now, just look at Instructions, so that we don't have to worry // about emitting multiple instructions for a pattern. - TreePatternNode *Dst = Pattern.getDstPattern(); - if (Dst->isLeaf()) continue; + if (Pattern.getDstPattern().getNumTrees() > 1) + continue; + const TreePatternNodePtr &Dst = Pattern.getDstPattern().getOnlyTree(); + if (Dst->isLeaf()) + continue; Record *Op = Dst->getOperator(); if (!Op->isSubClassOf("Instruction")) continue; @@ -576,12 +579,8 @@ // Ok, we found a pattern that we can handle. Remember it. InstructionMemo Memo( - Pattern.getDstPattern()->getOperator()->getName(), - DstRC, - SubRegNo, - PhysRegInputs, - PredicateCheck - ); + Pattern.getDstPattern().getOnlyTree()->getOperator()->getName(), DstRC, + SubRegNo, PhysRegInputs, PredicateCheck); int complexity = Pattern.getPatternComplexity(CGP); diff --git a/llvm/utils/TableGen/GlobalISelEmitter.cpp b/llvm/utils/TableGen/GlobalISelEmitter.cpp --- a/llvm/utils/TableGen/GlobalISelEmitter.cpp +++ b/llvm/utils/TableGen/GlobalISelEmitter.cpp @@ -1899,9 +1899,15 @@ int Score = P.getPatternComplexity(CGP); RuleMatcher M(P.getSrcRecord()->getLoc()); RuleMatcherScores[M.getRuleID()] = Score; - M.addAction(llvm::to_string(*P.getSrcPattern()) + - " => " + - llvm::to_string(*P.getDstPattern())); + + if (P.getDstPattern().getNumTrees() > 1) + return failedImport("Dst pattern with multiple roots not implemented yet."); + + TreePatternNode *Dst = P.getDstPattern().getOnlyTree().get(); + TreePatternNode *Src = P.getSrcPattern(); + + M.addAction(llvm::to_string(*Src) + " => " + + llvm::to_string(*Dst)); SmallVector Predicates; P.getPredicateRecords(Predicates); @@ -1909,8 +1915,6 @@ return std::move(Error); // 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 (auto Err = isTrivialOperatorNode(Dst))