Add "vmov.<dt> <Qd>, #<imm>" to integrated ARM assembler.

Adds the VMOV instruction to the integrated assembler. Because #<imm> is
complex, and we don't currently have a special ARM class to encode
constants defined by ARM method AdvSIMDExpandImm(), it currently only
accepts (nonnegative) integer32 constants that can fit into 8 bits.

There are no tests for this instruction, since there currently no
callers to this instruction. However, John will be checking in a CL
shortly that will use this instruction.

Add example generator for vector add.

BUG= https://bugs.chromium.org/p/nativeclient/issues/detail?id=4334
R=jpp@chromium.org

Review URL: https://codereview.chromium.org/1879463003 .
diff --git a/src/DartARM32/assembler_arm.h b/src/DartARM32/assembler_arm.h
index 6d7432a..9bc4e2d 100644
--- a/src/DartARM32/assembler_arm.h
+++ b/src/DartARM32/assembler_arm.h
@@ -1410,6 +1410,7 @@
   // ARM32::AssemblerARM32::vld1qr()
   // ARM32::AssemblerARM32::vst1qr()
   // ARM32::AssemblerARM32::vmorqi()
+  // ARM32::AssemblerARM32::vmovqc()
 #endif
 
   DISALLOW_ALLOCATION();
diff --git a/src/IceAssemblerARM32.cpp b/src/IceAssemblerARM32.cpp
index bba8e16..ebc95a4 100644
--- a/src/IceAssemblerARM32.cpp
+++ b/src/IceAssemblerARM32.cpp
@@ -215,6 +215,28 @@
 
 IValueT getXXXXInRegYXXXX(IValueT RegYXXXX) { return RegYXXXX & 0x0f; }
 
+// Figures out Op/Cmode values for given Value. Returns true if able to encode.
+bool encodeAdvSIMDExpandImm(IValueT Value, Type ElmtTy, IValueT &Op,
+                            IValueT &Cmode, IValueT &Imm8) {
+  // TODO(kschimpf): Handle other shifted 8-bit values.
+  constexpr IValueT Imm8Mask = 0xFF;
+  if ((Value & IValueT(~Imm8Mask)) != 0)
+    return false;
+  Imm8 = Value;
+  switch (ElmtTy) {
+  case IceType_i16:
+    Op = 0;
+    Cmode = 8; // 100:0
+    return true;
+  case IceType_i32:
+    Op = 0;
+    Cmode = 0; // 000:0
+    return true;
+  default:
+    return false;
+  }
+}
+
 // Defines layouts of an operand representing a (register) memory address,
 // possibly modified by an immediate value.
 enum EncodedImmAddress {
@@ -2710,6 +2732,36 @@
   emitVMem1Op(Opcode, Dd, Rn, Rm, DRegListSize2, ElmtSize, Align, Vld1qr);
 }
 
+bool AssemblerARM32::vmovqc(const Operand *OpQd, const ConstantInteger32 *Imm) {
+  // VMOV (immediate) - ARM section A8.8.320, encoding A1:
+  //   VMOV.<dt> <Qd>, #<Imm>
+  // 1111001x1D000yyyddddcccc01p1zzzz where Qd=Ddddd, Imm=xyyyzzzz, cmode=cccc,
+  // and Op=p.
+  constexpr const char *Vmovc = "vmovc";
+  const IValueT Dd = mapQRegToDReg(encodeQRegister(OpQd, "Qd", Vmovc));
+  IValueT Value = Imm->getValue();
+  const Type VecTy = OpQd->getType();
+  if (!isVectorType(VecTy))
+    return false;
+
+  IValueT Op;
+  IValueT Cmode;
+  IValueT Imm8;
+  if (!encodeAdvSIMDExpandImm(Value, typeElementType(VecTy), Op, Cmode, Imm8))
+    return false;
+  if (Op == 0 && mask(Cmode, 0, 1) == 1)
+    return false;
+  if (Op == 1 && Cmode != 13)
+    return false;
+  const IValueT Encoding =
+      (0xF << kConditionShift) | B25 | B23 | B6 | B4 |
+      (mask(Imm8, 7, 1) << 24) | (getYInRegYXXXX(Dd) << 22) |
+      (mask(Imm8, 4, 3) << 16) | (getXXXXInRegYXXXX(Dd) << 12) | (Cmode << 8) |
+      (Op << 5) | mask(Imm8, 0, 4);
+  emitInst(Encoding);
+  return true;
+}
+
 void AssemblerARM32::vmovd(const Operand *OpDd,
                            const OperandARM32FlexFpImm *OpFpImm,
                            CondARM32::Cond Cond) {
diff --git a/src/IceAssemblerARM32.h b/src/IceAssemblerARM32.h
index e3f9b4c..694113e 100644
--- a/src/IceAssemblerARM32.h
+++ b/src/IceAssemblerARM32.h
@@ -419,6 +419,10 @@
     vld1qr(ElmtSize, OpQd, OpRn, TInfo);
   }
 
+  // Qn[i] = Imm for all i in vector. Returns true iff Imm can be defined as an
+  // Imm8 using AdvSIMDExpandImm().
+  bool vmovqc(const Operand *OpQd, const ConstantInteger32 *Imm);
+
   // Dn = FpImm
   void vmovd(const Operand *OpDn, const OperandARM32FlexFpImm *OpFpImm,
              CondARM32::Cond Cond);
diff --git a/src/IceInstARM32.cpp b/src/IceInstARM32.cpp
index 718360f..e2d8a14 100644
--- a/src/IceInstARM32.cpp
+++ b/src/IceInstARM32.cpp
@@ -1616,12 +1616,18 @@
   case IceType_v4i32:
   case IceType_v4f32:
     assert(CondARM32::isUnconditional(Cond) &&
-           "Moves on <4 x f32> must be unconditional!");
-    // Mov between different Src and Dest types is used for bitcasting vectors.
-    // We still want to make sure SrcTy is a vector type.
-    assert(isVectorType(SrcTy) && "Mov between vector and scalar.");
-    Asm->vorrq(Dest, Src0, Src0);
-    return;
+           "Moves on vector must be unconditional!");
+    if (isVectorType(SrcTy)) {
+      // Mov between different Src and Dest types is used for bitcasting
+      // vectors.  We still want to make sure SrcTy is a vector type.
+      Asm->vorrq(Dest, Src0, Src0);
+      return;
+    } else if (const auto *C = llvm::dyn_cast<ConstantInteger32>(Src0)) {
+      // Mov with constant argument, allowing the initializing all elements of
+      // the vector.
+      if (Asm->vmovqc(Dest, C))
+        return;
+    }
   }
   llvm::report_fatal_error("Mov: don't know how to move " +
                            typeStdString(SrcTy) + " to " +