[llvm-branch-commits] [llvm] [tablegen] Implement multiple outputs for patterns (PR #123775)

Tomas Matheson via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Tue Jan 21 08:24:55 PST 2025


https://github.com/tmatheson-arm created https://github.com/llvm/llvm-project/pull/123775

None

>From 85c7ec7fee92ba634f3d2bec502eab94d4fbf18e Mon Sep 17 00:00:00 2001
From: Tomas Matheson <tomas.matheson at arm.com>
Date: Fri, 9 Feb 2024 15:56:02 +0000
Subject: [PATCH 1/4] Add TreePattern constructor that takes multiple patterns

---
 llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp | 8 ++++++++
 llvm/utils/TableGen/Common/CodeGenDAGPatterns.h   | 4 ++++
 2 files changed, 12 insertions(+)

diff --git a/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp b/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp
index b95fe4eedda83e..5a9aec2ed7e5e5 100644
--- a/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp
+++ b/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp
@@ -2800,6 +2800,14 @@ TreePattern::TreePattern(const Record *TheRec, TreePatternNodePtr Pat,
   Trees.push_back(Pat);
 }
 
+TreePattern::TreePattern(Record *TheRec,
+                         const std::vector<TreePatternNodePtr> &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;
diff --git a/llvm/utils/TableGen/Common/CodeGenDAGPatterns.h b/llvm/utils/TableGen/Common/CodeGenDAGPatterns.h
index f8c39172938256..d06623c743fe15 100644
--- a/llvm/utils/TableGen/Common/CodeGenDAGPatterns.h
+++ b/llvm/utils/TableGen/Common/CodeGenDAGPatterns.h
@@ -925,8 +925,12 @@ class TreePattern {
               CodeGenDAGPatterns &ise);
   TreePattern(const Record *TheRec, const DagInit *Pat, bool isInput,
               CodeGenDAGPatterns &ise);
+  /// Construct from a single pattern
   TreePattern(const Record *TheRec, TreePatternNodePtr Pat, bool isInput,
               CodeGenDAGPatterns &ise);
+  /// Construct from multiple patterns
+  TreePattern(Record *TheRec, const std::vector<TreePatternNodePtr> &Pat,
+              bool isInput, CodeGenDAGPatterns &ise);
 
   /// getTrees - Return the tree patterns which corresponds to this pattern.
   ///

>From daf6bcf1af8600eff9876e366c4c9334f30df100 Mon Sep 17 00:00:00 2001
From: Tomas Matheson <tomas.matheson at arm.com>
Date: Fri, 9 Feb 2024 15:57:38 +0000
Subject: [PATCH 2/4] Add TreePattern::hasProperTypeByHwMode

Change-Id: I3ac2e64b86233dd4c8b4f7f6effa50ed29759f25
---
 llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp | 6 ++++++
 llvm/utils/TableGen/Common/CodeGenDAGPatterns.h   | 2 ++
 2 files changed, 8 insertions(+)

diff --git a/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp b/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp
index 5a9aec2ed7e5e5..96a98c2bac0250 100644
--- a/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp
+++ b/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp
@@ -2816,6 +2816,12 @@ void TreePattern::error(const Twine &Msg) {
   HasError = true;
 }
 
+bool TreePattern::hasProperTypeByHwMode() const {
+  return llvm::any_of(getTrees(),
+                      [](auto &T) { return T->hasProperTypeByHwMode(); });
+}
+
+
 void TreePattern::ComputeNamedNodes() {
   for (TreePatternNodePtr &Tree : Trees)
     ComputeNamedNodes(*Tree);
diff --git a/llvm/utils/TableGen/Common/CodeGenDAGPatterns.h b/llvm/utils/TableGen/Common/CodeGenDAGPatterns.h
index d06623c743fe15..3fdb70a91544e1 100644
--- a/llvm/utils/TableGen/Common/CodeGenDAGPatterns.h
+++ b/llvm/utils/TableGen/Common/CodeGenDAGPatterns.h
@@ -988,6 +988,8 @@ class TreePattern {
 
   TypeInfer &getInfer() { return Infer; }
 
+  bool hasProperTypeByHwMode() const;
+
   void print(raw_ostream &OS) const;
   void dump() const;
 

>From 0d2594fac0c3eb8b3bd3e43d62cd58ad4afb7c8c Mon Sep 17 00:00:00 2001
From: Tomas Matheson <tomas.matheson at arm.com>
Date: Sat, 10 Feb 2024 11:21:09 +0000
Subject: [PATCH 3/4] Implement multiple output patterns

See also D154945. It took me a while to track down the source of the
problems with the existing patterns.

Tablegen patterns for instrucion selection can generate multiple
instructions, but only if there is a data dependency between them so
that they can be expressed as a DAG. For example, something like:

(store (load %src), %dst)
For some patterns, we might want to generate a sequence of instructions
which do not have a data dependency. For example on AArch64 some atomic
instructions are implemented like this:

LDP %ptr
DMB ISH
Currently, sequences like this can not be selected with tablegen
patterns. To work around this we need to do custom selection, which has
several disadvantages compared to using patterns, such as needing
separate implementations for SelectionDAG and GlobalISel.

This patch adds basic support for tablegen Patterns which have a list
of output instructions. Pattern already has the ability to express this
but it looks like it was never implemented.

Multiple result instructions in an output pattern will be chained
together.

The GlobalISel pattern importer will skip these patterns for now. I
intend to implement this soon.
---
 .../dag-isel-multiple-instructions.td         | 204 ++++++++++++++++++
 .../TableGen/Common/CodeGenDAGPatterns.cpp    | 166 +++++++++-----
 .../TableGen/Common/CodeGenDAGPatterns.h      |  15 +-
 llvm/utils/TableGen/DAGISelEmitter.cpp        |  18 ++
 llvm/utils/TableGen/DAGISelMatcherGen.cpp     | 118 ++++++----
 llvm/utils/TableGen/FastISelEmitter.cpp       |  12 +-
 llvm/utils/TableGen/GlobalISelEmitter.cpp     |  13 +-
 7 files changed, 440 insertions(+), 106 deletions(-)
 create mode 100644 llvm/test/TableGen/dag-isel-multiple-instructions.td

diff --git a/llvm/test/TableGen/dag-isel-multiple-instructions.td b/llvm/test/TableGen/dag-isel-multiple-instructions.td
new file mode 100644
index 00000000000000..531068e8269e49
--- /dev/null
+++ b/llvm/test/TableGen/dag-isel-multiple-instructions.td
@@ -0,0 +1,204 @@
+// 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: static const unsigned char MatcherTable[] = {
+// CHECK-NEXT: /*     0*/ OPC_SwitchOpcode /*5 cases */, 57, TARGET_VAL(ISD::STORE),// ->61
+// 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_CheckChild1TypeI32,
+// CHECK-NEXT: /*     8*/  OPC_MoveChild2,
+// CHECK-NEXT: /*     9*/  OPC_CheckOpcode, TARGET_VAL(ISD::LOAD),
+// CHECK-NEXT: /*    12*/  OPC_RecordMemRef,
+// CHECK-NEXT: /*    13*/  OPC_RecordNode, // #2 = 'ld' chained node
+// CHECK-NEXT: /*    14*/  OPC_CheckFoldableChainNode,
+// CHECK-NEXT: /*    15*/  OPC_MoveChild1,
+// CHECK-NEXT: /*    16*/  OPC_CheckOpcode, TARGET_VAL(ISD::ADD),
+// CHECK-NEXT: /*    19*/  OPC_RecordChild0, // #3 = $ptr
+// CHECK-NEXT: /*    20*/  OPC_RecordChild1, // #4 = $offset
+// CHECK-NEXT: /*    21*/  OPC_MoveParent,
+// CHECK-NEXT: /*    22*/  OPC_CheckPredicate0,  // Predicate_unindexedload
+// CHECK-NEXT: /*    23*/  OPC_CheckPredicate1,  // Predicate_load
+// CHECK-NEXT: /*    24*/  OPC_MoveParent,
+// CHECK-NEXT: /*    25*/  OPC_CheckPredicate2,  // Predicate_unindexedstore
+// CHECK-NEXT: /*    26*/  OPC_CheckPredicate3,  // Predicate_store
+// CHECK-NEXT: /*    27*/  OPC_EmitMergeInputChains, 2, 0, 2,
+// CHECK-NEXT: /*    31*/  OPC_EmitNode0, TARGET_VAL(::FENCE), 0|OPFL_Chain|OPFL_MemRefs,
+// CHECK-NEXT:                 0/*#Ops*/,
+// CHECK-NEXT: /*    36*/  OPC_EmitNode1Chain, TARGET_VAL(::ADD),
+// CHECK-NEXT:                 MVT::i32, 2/*#Ops*/, 3, 4,  // Results = #5
+// CHECK-NEXT: /*    43*/  OPC_EmitNode1Chain, TARGET_VAL(::LOAD),
+// CHECK-NEXT:                 MVT::i32, 1/*#Ops*/, 5,  // Results = #6
+// CHECK-NEXT: /*    49*/  OPC_EmitNode0, TARGET_VAL(::STORE), 0|OPFL_Chain|OPFL_MemRefs,
+// CHECK-NEXT:                 2/*#Ops*/, 1, 6,
+// CHECK-NEXT: /*    56*/  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))<<P:Predicate_unindexedload>><<P:Predicate_load>>)<<P:Predicate_unindexedstore>><<P:Predicate_store>> - Complexity = 11
+// CHECK-NEXT:             // Dst: ONE_TO_MANY: [
+// CHECK-NEXT: 	(FENCE)
+// CHECK-NEXT: 	(STORE i32:{ *:[i32] }:$val, (LOAD:{ *:[i32] } (ADD:{ *:[i32] } i32:{ *:[i32] }:$ptr, i32:{ *:[i32] }:$offset)))
+// CHECK-NEXT: 	(FENCE)
+// CHECK-NEXT: ]
+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-EMPTY:
+// CHECK-NEXT: /*    61*/ /*SwitchOpcode*/ 21, TARGET_VAL(ISD::CALLSEQ_START),// ->85
+// CHECK-NEXT: /*    64*/  OPC_RecordNode, // #0 = 'AArch64callseq_start' chained node
+// CHECK-NEXT: /*    65*/  OPC_RecordChild1, // #1 = $amt1
+// CHECK-NEXT: /*    66*/  OPC_MoveChild1,
+// CHECK-NEXT: /*    67*/  OPC_CheckOpcode, TARGET_VAL(ISD::TargetConstant),
+// CHECK-NEXT: /*    70*/  OPC_MoveSibling2,
+// CHECK-NEXT: /*    71*/  OPC_CheckOpcode, TARGET_VAL(ISD::TargetConstant),
+// CHECK-NEXT: /*    74*/  OPC_RecordNode, // #2 = $amt2
+// CHECK-NEXT: /*    75*/  OPC_MoveParent,
+// CHECK-NEXT: /*    76*/  OPC_EmitMergeInputChains1_0,
+// CHECK-NEXT: /*    77*/  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-EMPTY:
+// CHECK-NEXT: /*    85*/ /*SwitchOpcode*/ 43, TARGET_VAL(ISD::UDIVREM),// ->131
+// CHECK-NEXT: /*    88*/  OPC_RecordChild0, // #0 = $t0
+// CHECK-NEXT: /*    89*/  OPC_RecordChild1, // #1 = $t1
+// CHECK-NEXT: /*    90*/  OPC_Scope, 12, /*->104*/ // 2 children in Scope
+// CHECK-NEXT: /*    92*/   OPC_EmitNode2None, TARGET_VAL(::INSTR),
+// CHECK-NEXT:                  MVT::i32, MVT::i32, 2/*#Ops*/, 0, 1,  // Results = #2 #3
+// CHECK-NEXT: /*   100*/   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-EMPTY:
+// CHECK-NEXT: /*   104*/  /*Scope*/ 25, /*->130*/
+// CHECK-NEXT: /*   105*/   OPC_EmitNode0Chain, TARGET_VAL(::FENCE),
+// CHECK-NEXT:                  0/*#Ops*/,
+// CHECK-NEXT: /*   109*/   OPC_EmitNode1Chain, TARGET_VAL(::DIV),
+// CHECK-NEXT:                  MVT::i32, 2/*#Ops*/, 0, 1,  // Results = #2
+// CHECK-NEXT: /*   116*/   OPC_EmitNode0Chain, TARGET_VAL(::FENCE),
+// CHECK-NEXT:                  0/*#Ops*/,
+// CHECK-NEXT: /*   120*/   OPC_EmitNode1Chain, TARGET_VAL(::LOAD),
+// CHECK-NEXT:                  MVT::i32, 1/*#Ops*/, 0,  // Results = #3
+// CHECK-NEXT: /*   126*/   OPC_CompleteMatch, 2, 2, 3,
+// CHECK-NEXT:               // Src: (udivrem:{ *:[i32] }:{ *:[i32] } i32:{ *:[i32] }:$t0, i32:{ *:[i32] }:$t1) - Complexity = 3
+// CHECK-NEXT:               // Dst: COLLECT_RESULTS: [
+// CHECK-NEXT: 	(FENCE)
+// CHECK-NEXT: 	(DIV:{ *:[i32] } i32:{ *:[i32] }:$t0, i32:{ *:[i32] }:$t1)
+// CHECK-NEXT: 	(FENCE)
+// CHECK-NEXT: 	(LOAD:{ *:[i32] } i32:{ *:[i32] }:$t0)
+// CHECK-NEXT: ]
+def COLLECT_RESULTS : Pattern<(udivrem i32:$t0, i32:$t1),
+  [
+    (FENCE),
+    (DIV i32:$t0, i32:$t1),
+    (FENCE),
+    (LOAD i32:$t0),
+  ]>;
+
+
+// CHECK-EMPTY:
+// CHECK-NEXT: /*   130*/  0, /*End of Scope*/
+// CHECK-NEXT: /*   131*/ /*SwitchOpcode*/ 9, TARGET_VAL(ISD::SUB),// ->143
+// CHECK-NEXT: /*   134*/  OPC_RecordChild0, // #0 = $t0
+// CHECK-NEXT: /*   135*/  OPC_RecordChild1, // #1 = $t1
+// CHECK-NEXT: /*   136*/  OPC_MorphNodeTo1None, TARGET_VAL(::SUB),
+// 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-EMPTY:
+// CHECK-NEXT: /*   143*/ /*SwitchOpcode*/ 16, TARGET_VAL(ISD::MUL),// ->162
+// CHECK-NEXT: /*   146*/  OPC_RecordChild0, // #0 = $t0
+// CHECK-NEXT: /*   147*/  OPC_RecordChild1, // #1 = $t1
+// CHECK-NEXT: /*   148*/  OPC_EmitNode1Chain, TARGET_VAL(::MUL),
+// CHECK-NEXT:                 MVT::i32, 2/*#Ops*/, 0, 1,  // Results = #2
+// CHECK-NEXT: /*   155*/  OPC_EmitNode0Chain, TARGET_VAL(::FENCE),
+// CHECK-NEXT:                 0/*#Ops*/,
+// CHECK-NEXT: /*   159*/  OPC_CompleteMatch, 1, 2,
+// CHECK-NEXT:              // Src: (mul:{ *:[i32] } i32:{ *:[i32] }:$t0, i32:{ *:[i32] }:$t1) - Complexity = 3
+// CHECK-NEXT:              // Dst: ONE_TO_TWO: [
+// CHECK-NEXT: 	(MUL:{ *:[i32] } i32:{ *:[i32] }:$t0, i32:{ *:[i32] }:$t1)
+// CHECK-NEXT: 	(FENCE)
+// CHECK-NEXT: ]
+def ONE_TO_TWO : Pattern<(mul i32:$t0, i32:$t1),
+  [
+    (MUL i32:$t0, i32:$t1),
+    (FENCE)
+  ]>;
+
+// CHECK-EMPTY:
+// CHECK-NEXT: /*   162*/ 0, // EndSwitchOpcode
+// CHECK-NEXT:     0
+// CHECK-NEXT:   }; // Total Array size is 164 bytes
diff --git a/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp b/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp
index 96a98c2bac0250..50dc9f73be6fae 100644
--- a/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp
+++ b/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp
@@ -2808,6 +2808,13 @@ TreePattern::TreePattern(Record *TheRec,
   Trees = Pats;
 }
 
+TreePattern TreePattern::clone() const {
+  TreePattern New = *this;
+  for(TreePatternNodePtr& Tree : New.Trees)
+    Tree = Tree->clone();
+  return New;
+}
+
 void TreePattern::error(const Twine &Msg) {
   if (HasError)
     return;
@@ -3171,11 +3178,11 @@ void TreePattern::print(raw_ostream &OS) const {
   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)
@@ -3739,6 +3746,13 @@ static void getInstructionsInTree(const TreePatternNode &Tree,
     getInstructionsInTree(Child, Instrs);
 }
 
+/// Get all the instructions in all trees in a pattern.
+static void getInstructionsInPattern(const TreePattern &Pat,
+                                     SmallVectorImpl<Record *> &Instrs) {
+  for (const auto &Tree : Pat.getTrees())
+    getInstructionsInTree(*Tree, Instrs);
+}
+
 /// Check the class of a pattern leaf node against the instruction operand it
 /// represents.
 static bool checkOperandClass(CGIOperandList::OperandInfo &OI,
@@ -4043,7 +4057,8 @@ void CodeGenDAGPatterns::AddPatternToMatch(TreePattern *Pattern,
   // same type.
   std::map<std::string, NameRecord> SrcNames, DstNames;
   FindNames(PTM.getSrcPattern(), SrcNames, Pattern);
-  FindNames(PTM.getDstPattern(), DstNames, Pattern);
+  for (const auto &Tree : PTM.getDstPattern().getTrees())
+    FindNames(*Tree, DstNames, Pattern);
 
   // Scan all of the named values in the destination pattern, rejecting them if
   // they don't exist in the input pattern.
@@ -4076,7 +4091,7 @@ void CodeGenDAGPatterns::InferInstructionFlags() {
     // We can only infer from single-instruction patterns, otherwise we won't
     // know which instruction should get the flags.
     SmallVector<const Record *, 8> PatInstrs;
-    getInstructionsInTree(PTM.getDstPattern(), PatInstrs);
+    getInstructionsInPattern(PTM.getDstPattern(), PatInstrs);
     if (PatInstrs.size() != 1)
       continue;
 
@@ -4133,7 +4148,7 @@ void CodeGenDAGPatterns::VerifyInstructionFlags() {
   unsigned Errors = 0;
   for (const PatternToMatch &PTM : ptms()) {
     SmallVector<const Record *, 8> Instrs;
-    getInstructionsInTree(PTM.getDstPattern(), Instrs);
+    getInstructionsInPattern(PTM.getDstPattern(), Instrs);
     if (Instrs.empty())
       continue;
 
@@ -4248,11 +4263,6 @@ void CodeGenDAGPatterns::ParseOnePattern(
   Pattern.InlinePatternFragments();
   Result.InlinePatternFragments();
 
-  if (Result.getNumTrees() != 1) {
-    Result.error("Cannot use multi-alternative fragments in result pattern!");
-    return;
-  }
-
   // Infer types.
   bool IterateInference;
   bool InferredAllPatternTypes, InferredAllResultTypes;
@@ -4268,19 +4278,51 @@ void CodeGenDAGPatterns::ParseOnePattern(
 
     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<TypeSetByHwMode> FlatOutTypes;
+    using FlatInstrRange =
+        std::pair<unsigned, unsigned>; // instr idx, number of results
+    std::vector<FlatInstrRange> FlatOutRanges;
+    for (unsigned iTree = 0; iTree < Result.getNumTrees(); ++iTree) {
+      const TreePatternNodePtr &OutTree = Result.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 : Pattern.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], Result);
+      // 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 |= Result.getTree(InstrIdx)->UpdateNodeType(
+              i, InTree->getExtType(gIdx++), Result);
+        }
       }
+    }
 
     // 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
@@ -4292,8 +4334,8 @@ void CodeGenDAGPatterns::ParseOnePattern(
     // 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), Result);
+      for (const TreePatternNodePtr &OT : Result.getTrees())
+        IterateInference |= ForceArbitraryInstResultType(*OT, Result);
   } while (IterateInference);
 
   // Verify that we inferred enough types that we can do something with the
@@ -4306,10 +4348,13 @@ void CodeGenDAGPatterns::ParseOnePattern(
   }
 
   // Promote xform function to be an explicit node wherever set.
-  TreePatternNodePtr DstShared = PromoteXForms(Result.getOnlyTree());
+  std::vector<TreePatternNodePtr> ExpandedOutTrees;
+  for (auto &RT : Result.getTrees())
+    ExpandedOutTrees.push_back(PromoteXForms(RT));
 
-  TreePattern Temp(Result.getRecord(), DstShared, false, *this);
-  Temp.InferAllTypes();
+  TreePattern ExpandedOutPattern(Result.getRecord(), ExpandedOutTrees, false,
+                                 *this);
+  ExpandedOutPattern.InferAllTypes();
 
   const ListInit *Preds = TheDef->getValueAsListInit("Predicates");
   int Complexity = TheDef->getValueAsInt("AddedComplexity");
@@ -4324,23 +4369,33 @@ void CodeGenDAGPatterns::ParseOnePattern(
   // 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(), ShouldIgnore));
+  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: ";
+        Pattern.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 : Pattern.getTrees()) {
+    if (InTree->hasPossibleType())
+      AddPatternToMatch(&Pattern,
+                        PatternToMatch(TheDef, Preds, InTree,
+                                       ExpandedOutPattern, InstImpResults,
+                                       Complexity, TheDef->getID()), ShouldIgnore);
   }
 }
 
@@ -4361,10 +4416,6 @@ void CodeGenDAGPatterns::ParsePatterns() {
     // 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<std::string, TreePatternNodePtr> InstInputs;
     MapVector<std::string, TreePatternNodePtr, std::map<std::string, unsigned>>
@@ -4388,6 +4439,12 @@ static void collectModes(std::set<unsigned> &Modes, const TreePatternNode &N) {
     collectModes(Modes, Child);
 }
 
+static void collectModes(std::set<unsigned> &Modes,
+                         const TreePattern &Pattern) {
+  for (const auto &Tree : Pattern.getTrees())
+    collectModes(Modes, *Tree);
+}
+
 void CodeGenDAGPatterns::ExpandHwModeBasedTypes() {
   const CodeGenHwModes &CGH = getTargetInfo().getHwModes();
   if (CGH.getNumModeIds() == 1)
@@ -4399,19 +4456,22 @@ void CodeGenDAGPatterns::ExpandHwModeBasedTypes() {
   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().clone();
+    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),
+                                 std::move(NewSrc), NewDst,
                                  P.getDstRegs(), P.getAddedComplexity(),
                                  getNewUID(), P.getGISelShouldIgnore(), Check);
   };
 
   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())
@@ -4775,7 +4835,7 @@ void CodeGenDAGPatterns::GenerateVariants() {
       // 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(), getNewUID(),
           PatternsToMatch[i].getGISelShouldIgnore(),
diff --git a/llvm/utils/TableGen/Common/CodeGenDAGPatterns.h b/llvm/utils/TableGen/Common/CodeGenDAGPatterns.h
index 3fdb70a91544e1..598ba65a27c0e5 100644
--- a/llvm/utils/TableGen/Common/CodeGenDAGPatterns.h
+++ b/llvm/utils/TableGen/Common/CodeGenDAGPatterns.h
@@ -932,6 +932,9 @@ class TreePattern {
   TreePattern(Record *TheRec, const std::vector<TreePatternNodePtr> &Pat,
               bool isInput, CodeGenDAGPatterns &ise);
 
+  /// Return a new copy of the TreePattern, with cloned Trees.
+  TreePattern clone() const;
+
   /// getTrees - Return the tree patterns which corresponds to this pattern.
   ///
   const std::vector<TreePatternNodePtr> &getTrees() const { return Trees; }
@@ -999,6 +1002,11 @@ class TreePattern {
   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,
                                             TreePattern &TP) {
@@ -1076,7 +1084,7 @@ class PatternToMatch {
   const Record *SrcRecord;       // Originating Record for the pattern.
   const ListInit *Predicates;    // Top level predicate conditions to match.
   TreePatternNodePtr SrcPattern; // Source pattern to match.
-  TreePatternNodePtr DstPattern; // Resulting pattern.
+  TreePattern DstPattern;        // Resulting pattern.
   std::vector<const Record *> Dstregs; // Physical register defs being matched.
   std::string HwModeFeatures;
   int AddedComplexity;    // Add to matching pattern complexity.
@@ -1085,7 +1093,7 @@ class PatternToMatch {
 
 public:
   PatternToMatch(const Record *srcrecord, const ListInit *preds,
-                 TreePatternNodePtr src, TreePatternNodePtr dst,
+                 TreePatternNodePtr src, TreePattern dst,
                  ArrayRef<const Record *> dstregs, int complexity, unsigned uid,
                  bool ignore, const Twine &hwmodefeatures = "")
       : SrcRecord(srcrecord), Predicates(preds), SrcPattern(src),
@@ -1096,8 +1104,7 @@ class PatternToMatch {
   const ListInit *getPredicates() const { return Predicates; }
   TreePatternNode &getSrcPattern() const { return *SrcPattern; }
   TreePatternNodePtr getSrcPatternShared() const { return SrcPattern; }
-  TreePatternNode &getDstPattern() const { return *DstPattern; }
-  TreePatternNodePtr getDstPatternShared() const { return DstPattern; }
+  const TreePattern &getDstPattern() const { return DstPattern; }
   ArrayRef<const Record *> getDstRegs() const { return Dstregs; }
   StringRef getHwModeFeatures() const { return HwModeFeatures; }
   int getAddedComplexity() const { return AddedComplexity; }
diff --git a/llvm/utils/TableGen/DAGISelEmitter.cpp b/llvm/utils/TableGen/DAGISelEmitter.cpp
index 6d6d72eb70a5b8..10b8bf7f2c72d0 100644
--- a/llvm/utils/TableGen/DAGISelEmitter.cpp
+++ b/llvm/utils/TableGen/DAGISelEmitter.cpp
@@ -62,6 +62,15 @@ static unsigned getResultPatternCost(const TreePatternNode &P,
 
 /// getResultPatternCodeSize - Compute the code size 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, CGP);
+  return Cost;
+}
+
+/// Compute the code size of instructions for this tree.
 static unsigned getResultPatternSize(const TreePatternNode &P,
                                      const CodeGenDAGPatterns &CGP) {
   if (P.isLeaf())
@@ -77,6 +86,15 @@ static unsigned getResultPatternSize(const TreePatternNode &P,
   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, 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
diff --git a/llvm/utils/TableGen/DAGISelMatcherGen.cpp b/llvm/utils/TableGen/DAGISelMatcherGen.cpp
index e1c25075e384d4..2d0f1b32b703a9 100644
--- a/llvm/utils/TableGen/DAGISelMatcherGen.cpp
+++ b/llvm/utils/TableGen/DAGISelMatcherGen.cpp
@@ -13,8 +13,10 @@
 #include "Common/CodeGenTarget.h"
 #include "Common/DAGISelMatcher.h"
 #include "Common/InfoByHwMode.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 <utility>
@@ -777,6 +779,14 @@ static unsigned numNodesThatMayLoadOrStore(const TreePatternNode &N,
   return Count;
 }
 
+static unsigned numNodesThatMayLoadOrStore(const TreePattern &Pattern,
+                                           const CodeGenDAGPatterns &CGP) {
+  unsigned Count = 0;
+  for (const auto &Tree : Pattern.getTrees())
+    Count += numNodesThatMayLoadOrStore(*Tree, CGP);
+  return Count;
+}
+
 void MatcherGen::EmitResultInstructionAsOperand(
     const TreePatternNode &N, SmallVectorImpl<unsigned> &OutputOps) {
   const Record *Op = N.getOperator();
@@ -784,19 +794,23 @@ void MatcherGen::EmitResultInstructionAsOperand(
   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.get(); });
+
+  const TreePatternNode &SrcPat = Pattern.getSrcPattern();
 
-  // TreeHasOutGlue - True if this tree has glue.
-  bool TreeHasInGlue = false, TreeHasOutGlue = false;
-  if (isRoot) {
+  bool TreeHasInGlue = false;
+  if (IsFirstRoot) {
     const TreePatternNode &SrcPat = Pattern.getSrcPattern();
     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);
   }
+  const bool TreeHasOutGlue =
+      IsLastRoot && SrcPat.TreeHasProperty(SDNPOutGlue, CGP);
 
   // NumResults - This is the number of results produced by the instruction in
   // the "outs" list.
@@ -884,7 +898,7 @@ void MatcherGen::EmitResultInstructionAsOperand(
   // 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,10 +919,11 @@ void MatcherGen::EmitResultInstructionAsOperand(
   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 ...))
-  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.
     const Record *HandledReg = nullptr;
@@ -925,36 +940,40 @@ void MatcherGen::EmitResultInstructionAsOperand(
   // 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 =
+  bool NodeTakesMemRefs = false;
+  if (Pattern.getSrcPattern().TreeHasProperty(SDNPMemOperand, CGP)) {
+    const unsigned NumNodesThatLoadOrStore =
         numNodesThatMayLoadOrStore(Pattern.getDstPattern(), CGP);
-    bool NodeIsUniqueLoadOrStore =
-        mayInstNodeLoadOrStore(N, CGP) && NumNodesThatLoadOrStore == 1;
-    NodeHasMemRefs =
-        NodeIsUniqueLoadOrStore || (isRoot && (mayInstNodeLoadOrStore(N, CGP) ||
-                                               NumNodesThatLoadOrStore != 1));
+    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<>
@@ -962,20 +981,25 @@ void MatcherGen::EmitResultInstructionAsOperand(
     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) {
@@ -1033,7 +1057,11 @@ void MatcherGen::EmitResultCode() {
 
   // Codegen the root of the result pattern, capturing the resulting values.
   SmallVector<unsigned, 8> Ops;
-  EmitResultOperand(Pattern.getDstPattern(), Ops);
+  for (const TreePatternNodePtr &Tree : Pattern.getDstPattern().getTrees()) {
+    SmallVector<unsigned, 8> Tmp;
+    EmitResultOperand(*Tree, 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
@@ -1048,7 +1076,7 @@ void MatcherGen::EmitResultCode() {
     // If the root came from an implicit def in the instruction handling stuff,
     // don't re-add it.
     const Record *HandledReg = nullptr;
-    const TreePatternNode &DstPat = Pattern.getDstPattern();
+    const TreePatternNode &DstPat = *Pattern.getDstPattern().getOnlyTree();
     if (!DstPat.isLeaf() && DstPat.getOperator()->isSubClassOf("Instruction")) {
       const CodeGenTarget &CGT = CGP.getTargetInfo();
       CodeGenInstruction &II = CGT.getInstruction(DstPat.getOperator());
@@ -1067,9 +1095,19 @@ void MatcherGen::EmitResultCode() {
   SmallVector<unsigned, 8> Results(Ops);
 
   // 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
index 6963bb239e9d87..d5f850be44e9dc 100644
--- a/llvm/utils/TableGen/FastISelEmitter.cpp
+++ b/llvm/utils/TableGen/FastISelEmitter.cpp
@@ -457,7 +457,9 @@ void FastISelMap::collectPatterns(const CodeGenDAGPatterns &CGP) {
 
     // 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 (Pattern.getDstPattern().getNumTrees() > 1)
+      continue;
+    const TreePatternNode &Dst = *Pattern.getDstPattern().getOnlyTree();
     if (Dst.isLeaf())
       continue;
     const Record *Op = Dst.getOperator();
@@ -476,7 +478,8 @@ void FastISelMap::collectPatterns(const CodeGenDAGPatterns &CGP) {
 
     // For now, ignore multi-instruction patterns.
     bool MultiInsts = false;
-    for (const TreePatternNode &ChildOp : Dst.children()) {
+    for (unsigned i = 0, e = Dst.getNumChildren(); i != e; ++i) {
+      const TreePatternNode &ChildOp = Dst.getChild(i);
       if (ChildOp.isLeaf())
         continue;
       if (ChildOp.getOperator()->isSubClassOf("Instruction")) {
@@ -586,8 +589,9 @@ void FastISelMap::collectPatterns(const CodeGenDAGPatterns &CGP) {
     std::string PredicateCheck = Pattern.getPredicateCheck();
 
     // Ok, we found a pattern that we can handle. Remember it.
-    InstructionMemo Memo(Pattern.getDstPattern().getOperator()->getName(),
-                         DstRC, std::move(SubRegNo), std::move(PhysRegInputs),
+    InstructionMemo Memo(
+        Pattern.getDstPattern().getOnlyTree()->getOperator()->getName(), DstRC,
+        std::move(SubRegNo), std::move(PhysRegInputs),
                          PredicateCheck);
 
     int complexity = Pattern.getPatternComplexity(CGP);
diff --git a/llvm/utils/TableGen/GlobalISelEmitter.cpp b/llvm/utils/TableGen/GlobalISelEmitter.cpp
index 5466d315c05a49..fe8a913ce01c6e 100644
--- a/llvm/utils/TableGen/GlobalISelEmitter.cpp
+++ b/llvm/utils/TableGen/GlobalISelEmitter.cpp
@@ -2035,9 +2035,14 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
   int Score = P.getPatternComplexity(CGP);
   RuleMatcher M(P.getSrcRecord()->getLoc());
   RuleMatcherScores[M.getRuleID()] = Score;
-  M.addAction<DebugCommentAction>(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();
+  TreePatternNode &Src = P.getSrcPattern();
+
+  M.addAction<DebugCommentAction>(llvm::to_string(Src) + "  =>  " +
+                                  llvm::to_string(Dst));
 
   SmallVector<const Record *, 4> Predicates;
   P.getPredicateRecords(Predicates);
@@ -2048,8 +2053,6 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
     M.addHwModeIdx(declareHwModeCheck(P.getHwModeFeatures()));
 
   // 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))

>From 7e7ba17845cd66e3fcbbe19097f4a60407e13ef4 Mon Sep 17 00:00:00 2001
From: Tomas Matheson <tomas.matheson at arm.com>
Date: Tue, 21 Jan 2025 14:12:12 +0000
Subject: [PATCH 4/4] fixup merge conflict resolution errors

---
 llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp | 6 +++---
 llvm/utils/TableGen/Common/CodeGenDAGPatterns.h   | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp b/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp
index 50dc9f73be6fae..fcff67b030851d 100644
--- a/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp
+++ b/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp
@@ -2800,7 +2800,7 @@ TreePattern::TreePattern(const Record *TheRec, TreePatternNodePtr Pat,
   Trees.push_back(Pat);
 }
 
-TreePattern::TreePattern(Record *TheRec,
+TreePattern::TreePattern(const Record *TheRec,
                          const std::vector<TreePatternNodePtr> &Pats,
                          bool isInput, CodeGenDAGPatterns &cdp)
     : TheRecord(TheRec), CDP(cdp), isInputPattern(isInput), HasError(false),
@@ -3748,7 +3748,7 @@ static void getInstructionsInTree(const TreePatternNode &Tree,
 
 /// Get all the instructions in all trees in a pattern.
 static void getInstructionsInPattern(const TreePattern &Pat,
-                                     SmallVectorImpl<Record *> &Instrs) {
+                                     SmallVectorImpl<const Record *> &Instrs) {
   for (const auto &Tree : Pat.getTrees())
     getInstructionsInTree(*Tree, Instrs);
 }
@@ -4395,7 +4395,7 @@ void CodeGenDAGPatterns::ParseOnePattern(
       AddPatternToMatch(&Pattern,
                         PatternToMatch(TheDef, Preds, InTree,
                                        ExpandedOutPattern, InstImpResults,
-                                       Complexity, TheDef->getID()), ShouldIgnore);
+                                       Complexity, TheDef->getID(), ShouldIgnore));
   }
 }
 
diff --git a/llvm/utils/TableGen/Common/CodeGenDAGPatterns.h b/llvm/utils/TableGen/Common/CodeGenDAGPatterns.h
index 598ba65a27c0e5..a96ba3f72efa54 100644
--- a/llvm/utils/TableGen/Common/CodeGenDAGPatterns.h
+++ b/llvm/utils/TableGen/Common/CodeGenDAGPatterns.h
@@ -929,7 +929,7 @@ class TreePattern {
   TreePattern(const Record *TheRec, TreePatternNodePtr Pat, bool isInput,
               CodeGenDAGPatterns &ise);
   /// Construct from multiple patterns
-  TreePattern(Record *TheRec, const std::vector<TreePatternNodePtr> &Pat,
+  TreePattern(const Record *TheRec, const std::vector<TreePatternNodePtr> &Pat,
               bool isInput, CodeGenDAGPatterns &ise);
 
   /// Return a new copy of the TreePattern, with cloned Trees.



More information about the llvm-branch-commits mailing list