GlobalISel: Try to widen merges with other merges

If the requested source type an be used as a merge source type, create
a merge of merges. This avoids creating large, illegal extensions and
bit-ops directly to the result type.

llvm-svn: 364841
diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
index d62e786..6958303 100644
--- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
@@ -794,12 +794,38 @@
   if (!DstTy.isScalar())
     return UnableToLegalize;
 
+  Register Src1 = MI.getOperand(1).getReg();
+  LLT SrcTy = MRI.getType(Src1);
+  int NumMerge = DstTy.getSizeInBits() / WideTy.getSizeInBits();
+
+  // Try to turn this into a merge of merges if we can use the requested type as
+  // the source.
+
+  // TODO: Pad with undef if DstTy > WideTy
+  if (NumMerge > 1 && WideTy.getSizeInBits() % SrcTy.getSizeInBits() == 0) {
+    int PartsPerMerge = WideTy.getSizeInBits() / SrcTy.getSizeInBits();
+    SmallVector<Register, 4> Parts;
+    SmallVector<Register, 4> SubMerges;
+
+    for (int I = 0; I != NumMerge; ++I) {
+      for (int J = 0; J != PartsPerMerge; ++J)
+        Parts.push_back(MI.getOperand(I * PartsPerMerge + J + 1).getReg());
+
+      auto SubMerge = MIRBuilder.buildMerge(WideTy, Parts);
+      SubMerges.push_back(SubMerge.getReg(0));
+      Parts.clear();
+    }
+
+    MIRBuilder.buildMerge(DstReg, SubMerges);
+    MI.eraseFromParent();
+    return Legalized;
+  }
+
   unsigned NumOps = MI.getNumOperands();
   unsigned NumSrc = MI.getNumOperands() - 1;
   unsigned PartSize = DstTy.getSizeInBits() / NumSrc;
 
-  Register Src1 = MI.getOperand(1).getReg();
-  Register ResultReg = MIRBuilder.buildZExt(DstTy, Src1)->getOperand(0).getReg();
+  Register ResultReg = MIRBuilder.buildZExt(DstTy, Src1).getReg(0);
 
   for (unsigned I = 2; I != NumOps; ++I) {
     const unsigned Offset = (I - 1) * PartSize;