[GlobalISel] Introduce G_BUILD_VECTOR, G_BUILD_VECTOR_TRUNC and G_CONCAT_VECTOR opcodes.

These opcodes are intended to subsume some of the capability of G_MERGE_VALUES,
as it was too powerful and thus complex to add deal with throughout the GISel
pipeline.

G_BUILD_VECTOR creates a vector value from a sequence of uniformly typed
scalar values. G_BUILD_VECTOR_TRUNC is a special opcode for handling scalar
operands which are larger than the destination vector element type, and
therefore does an implicit truncate.

G_CONCAT_VECTOR creates a vector by concatenating smaller, uniformly typed,
vectors together.

These will be used in a subsequent commit. This commit just adds the initial
infrastructure.

Differential Revision: https://reviews.llvm.org/D53594

llvm-svn: 348430
diff --git a/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp b/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp
index 9f99640..54e007d 100644
--- a/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp
@@ -519,6 +519,64 @@
   return MIB;
 }
 
+MachineInstrBuilder
+MachineIRBuilderBase::buildBuildVector(unsigned Res, ArrayRef<unsigned> Ops) {
+#ifndef NDEBUG
+  assert((!Ops.empty() || Ops.size() < 2) && "Must have at least 2 operands");
+  assert(getMRI()->getType(Res).isVector() && "Res type must be a vector");
+  LLT Ty = getMRI()->getType(Ops[0]);
+  for (auto Reg : Ops)
+    assert(getMRI()->getType(Reg) == Ty && "type mismatch in input list");
+  assert(Ops.size() * Ty.getSizeInBits() ==
+             getMRI()->getType(Res).getSizeInBits() &&
+         "input scalars do not exactly cover the outpur vector register");
+#endif
+  MachineInstrBuilder MIB = buildInstr(TargetOpcode::G_BUILD_VECTOR);
+  MIB.addDef(Res);
+  for (auto Op : Ops)
+    MIB.addUse(Op);
+  return MIB;
+}
+
+MachineInstrBuilder
+MachineIRBuilderBase::buildBuildVectorTrunc(unsigned Res,
+                                            ArrayRef<unsigned> Ops) {
+#ifndef NDEBUG
+  assert((!Ops.empty() || Ops.size() < 2) && "Must have at least 2 operands");
+  LLT Ty = getMRI()->getType(Ops[0]);
+  for (auto Reg : Ops)
+    assert(getMRI()->getType(Reg) == Ty && "type mismatch in input list");
+#endif
+  if (getMRI()->getType(Ops[0]).getSizeInBits() ==
+      getMRI()->getType(Res).getElementType().getSizeInBits())
+    return buildBuildVector(Res, Ops);
+  MachineInstrBuilder MIB = buildInstr(TargetOpcode::G_BUILD_VECTOR_TRUNC);
+  MIB.addDef(Res);
+  for (auto Op : Ops)
+    MIB.addUse(Op);
+  return MIB;
+}
+
+MachineInstrBuilder
+MachineIRBuilderBase::buildConcatVectors(unsigned Res, ArrayRef<unsigned> Ops) {
+  #ifndef NDEBUG
+  assert((!Ops.empty() || Ops.size() < 2) && "Must have at least 2 operands");
+  LLT Ty = getMRI()->getType(Ops[0]);
+  for (auto Reg : Ops) {
+    assert(getMRI()->getType(Reg).isVector() && "expected vector operand");
+    assert(getMRI()->getType(Reg) == Ty && "type mismatch in input list");
+  }
+  assert(Ops.size() * Ty.getSizeInBits() ==
+             getMRI()->getType(Res).getSizeInBits() &&
+         "input vectors do not exactly cover the outpur vector register");
+  #endif
+  MachineInstrBuilder MIB = buildInstr(TargetOpcode::G_CONCAT_VECTORS);
+  MIB.addDef(Res);
+  for (auto Op : Ops)
+    MIB.addUse(Op);
+  return MIB;
+}
+
 MachineInstrBuilder MachineIRBuilderBase::buildInsert(unsigned Res,
                                                       unsigned Src, unsigned Op,
                                                       unsigned Index) {
diff --git a/llvm/lib/CodeGen/MachineVerifier.cpp b/llvm/lib/CodeGen/MachineVerifier.cpp
index b37c421..7970dff 100644
--- a/llvm/lib/CodeGen/MachineVerifier.cpp
+++ b/llvm/lib/CodeGen/MachineVerifier.cpp
@@ -1055,6 +1055,63 @@
     }
     break;
   }
+  case TargetOpcode::G_BUILD_VECTOR: {
+    // Source types must be scalars, dest type a vector. Total size of scalars
+    // must match the dest vector size.
+    LLT DstTy = MRI->getType(MI->getOperand(0).getReg());
+    LLT SrcEltTy = MRI->getType(MI->getOperand(1).getReg());
+    if (!DstTy.isVector() || SrcEltTy.isVector())
+      report("G_BUILD_VECTOR must produce a vector from scalar operands", MI);
+    for (unsigned i = 2; i < MI->getNumOperands(); ++i) {
+      if (MRI->getType(MI->getOperand(1).getReg()) !=
+          MRI->getType(MI->getOperand(i).getReg()))
+        report("G_BUILD_VECTOR source operand types are not homogeneous", MI);
+    }
+    if (DstTy.getSizeInBits() !=
+        SrcEltTy.getSizeInBits() * (MI->getNumOperands() - 1))
+      report("G_BUILD_VECTOR src operands total size don't match dest "
+             "size.",
+             MI);
+    break;
+  }
+  case TargetOpcode::G_BUILD_VECTOR_TRUNC: {
+    // Source types must be scalars, dest type a vector. Scalar types must be
+    // larger than the dest vector elt type, as this is a truncating operation.
+    LLT DstTy = MRI->getType(MI->getOperand(0).getReg());
+    LLT SrcEltTy = MRI->getType(MI->getOperand(1).getReg());
+    if (!DstTy.isVector() || SrcEltTy.isVector())
+      report("G_BUILD_VECTOR_TRUNC must produce a vector from scalar operands",
+             MI);
+    for (unsigned i = 2; i < MI->getNumOperands(); ++i) {
+      if (MRI->getType(MI->getOperand(1).getReg()) !=
+          MRI->getType(MI->getOperand(i).getReg()))
+        report("G_BUILD_VECTOR_TRUNC source operand types are not homogeneous",
+               MI);
+    }
+    if (SrcEltTy.getSizeInBits() <= DstTy.getElementType().getSizeInBits())
+      report("G_BUILD_VECTOR_TRUNC source operand types are not larger than "
+             "dest elt type",
+             MI);
+    break;
+  }
+  case TargetOpcode::G_CONCAT_VECTORS: {
+    // Source types should be vectors, and total size should match the dest
+    // vector size.
+    LLT DstTy = MRI->getType(MI->getOperand(0).getReg());
+    LLT SrcTy = MRI->getType(MI->getOperand(1).getReg());
+    if (!DstTy.isVector() || !SrcTy.isVector())
+      report("G_CONCAT_VECTOR requires vector source and destination operands",
+             MI);
+    for (unsigned i = 2; i < MI->getNumOperands(); ++i) {
+      if (MRI->getType(MI->getOperand(1).getReg()) !=
+          MRI->getType(MI->getOperand(i).getReg()))
+        report("G_CONCAT_VECTOR source operand types are not homogeneous", MI);
+    }
+    if (DstTy.getNumElements() !=
+        SrcTy.getNumElements() * (MI->getNumOperands() - 1))
+      report("G_CONCAT_VECTOR num dest and source elements should match", MI);
+    break;
+  }
   case TargetOpcode::COPY: {
     if (foundErrors)
       break;