Subzero. ARM32. Fixes Insert/Extract v(8|16)i1 bug.

Subzero emits the following sequence when extracting elements from a
vector of i1:

vmov.8 Rt, Dm[I]

I should be scaled when accessing v4i1, and v8i1, i.e., to extract the
n-th boolean in a v8i1, the emitted code should be

vmov.8 Rt, Dm[I*n]

Insertions are handled by changing the operands' types, so that a
v4i1 is handled as a v4i32, and a v8i1, as a v8i16. I.e., to insert
the n-th boolean into a v8i1, the emitted code should be

mov.16 Dt[I], Rm

instead of

mov.8 Dt[I*n], Rm

This clears the upper bits for that element.

BUG=
R=eholk@chromium.org

Review URL: https://codereview.chromium.org/1876083004 .
diff --git a/src/IceInstARM32.cpp b/src/IceInstARM32.cpp
index 92a57e0..718360f 100644
--- a/src/IceInstARM32.cpp
+++ b/src/IceInstARM32.cpp
@@ -1108,8 +1108,27 @@
   }
 }
 
-constexpr uint32_t getDIndex(uint32_t NumElements, uint32_t Index) {
-  return (Index < NumElements / 2) ? Index : Index - (NumElements / 2);
+uint32_t adjustDIndex(Type Ty, uint32_t DIndex) {
+  // If Ty is a vector of i1, we may need to adjust DIndex. This is needed
+  // because, e.g., the second i1 in a v4i1 is accessed with a
+  //
+  // vmov.s8 Qd[4], Rn
+  switch (Ty) {
+  case IceType_v4i1:
+    return DIndex * 4;
+  case IceType_v8i1:
+    return DIndex * 2;
+  case IceType_v16i1:
+    return DIndex;
+  default:
+    return DIndex;
+  }
+}
+
+uint32_t getDIndex(Type Ty, uint32_t NumElements, uint32_t Index) {
+  const uint32_t DIndex =
+      (Index < NumElements / 2) ? Index : Index - (NumElements / 2);
+  return adjustDIndex(Ty, DIndex);
 }
 
 // For floating point values, we can insertelement or extractelement by moving
@@ -1152,12 +1171,13 @@
     getDest()->emit(Func);
     Str << ", ";
 
-    const size_t VectorSize = typeNumElements(Src->getType());
+    const Type SrcTy = Src->getType();
+    const size_t VectorSize = typeNumElements(SrcTy);
 
     const Register SrcReg = getDRegister(Src, Index);
 
     Str << RegARM32::RegTable[SrcReg].Name;
-    Str << "[" << getDIndex(VectorSize, Index) << "]";
+    Str << "[" << getDIndex(SrcTy, VectorSize, Index) << "]";
   } else if (isFloatingType(DestTy)) {
     const Register SrcReg = getSRegister(Src, Index);
 
@@ -1175,11 +1195,12 @@
   const Operand *Dest = getDest();
   const Type DestTy = Dest->getType();
   const Operand *Src = getSrc(0);
+  const Type SrcTy = Src->getType();
   assert(isVectorType(Src->getType()));
   assert(DestTy == typeElementType(Src->getType()));
   auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
   if (isIntegerType(DestTy)) {
-    Asm->vmovrqi(Dest, Src, Index, getPredicate());
+    Asm->vmovrqi(Dest, Src, adjustDIndex(SrcTy, Index), getPredicate());
     assert(!Asm->needsTextFixup());
     return;
   }
@@ -1188,12 +1209,28 @@
   assert(!Asm->needsTextFixup());
 }
 
+namespace {
+Type insertionType(Type Ty) {
+  assert(isVectorType(Ty));
+  switch (Ty) {
+  case IceType_v4i1:
+    return IceType_v4i32;
+  case IceType_v8i1:
+    return IceType_v8i16;
+  case IceType_v16i1:
+    return IceType_v16i8;
+  default:
+    return Ty;
+  }
+}
+} // end of anonymous namespace
+
 void InstARM32Insert::emit(const Cfg *Func) const {
   Ostream &Str = Func->getContext()->getStrEmit();
   const Variable *Dest = getDest();
-  const Type DestTy = getDest()->getType();
-
   const auto *Src = llvm::cast<Variable>(getSrc(0));
+  const Type DestTy = insertionType(getDest()->getType());
+  assert(isVectorType(DestTy));
 
   if (isIntegerType(DestTy)) {
     Str << "\t"
@@ -1203,7 +1240,8 @@
 
     const size_t VectorSize = typeNumElements(DestTy);
     const Register DestReg = getDRegister(Dest, Index);
-    const uint32_t Index = getDIndex(VectorSize, this->Index);
+    const uint32_t Index =
+        getDIndex(insertionType(DestTy), VectorSize, this->Index);
     Str << RegARM32::RegTable[DestReg].Name;
     Str << "[" << Index << "], ";
     Src->emit(Func);
@@ -1221,14 +1259,16 @@
 
 void InstARM32Insert::emitIAS(const Cfg *Func) const {
   const Variable *Dest = getDest();
-  const Operand *Src = getSrc(0);
-  const Type SrcTy = Src->getType();
-  assert(isVectorType(Dest->getType()));
-  assert(typeElementType(Dest->getType()) == SrcTy);
+  const auto *Src = llvm::cast<Variable>(getSrc(0));
+  const Type DestTy = insertionType(Dest->getType());
+  const Type SrcTy = typeElementType(DestTy);
+  assert(SrcTy == Src->getType() || Src->getType() == IceType_i1);
+  assert(isVectorType(DestTy));
   auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
   if (isIntegerType(SrcTy)) {
-    const Operand *Src = getSrc(0);
-    Asm->vmovqir(Dest, Index, Src, getPredicate());
+    Asm->vmovqir(Dest->asType(Func, DestTy, Dest->getRegNum()),
+                 adjustDIndex(DestTy, Index),
+                 Src->asType(Func, SrcTy, Src->getRegNum()), getPredicate());
     assert(!Asm->needsTextFixup());
     return;
   }
diff --git a/tests_lit/assembler/arm32/select-vec.ll b/tests_lit/assembler/arm32/select-vec.ll
index 0edbcf4..8d6165e 100644
--- a/tests_lit/assembler/arm32/select-vec.ll
+++ b/tests_lit/assembler/arm32/select-vec.ll
@@ -24,7 +24,7 @@
 ; ASM-NEXT:	tst	r0, #1
 ; ASM-NEXT:	vmovne.f32	s17, s16
 ; ASM-NEXT:	vmov.f32	s12, s17
-; ASM-NEXT:	vmov.s8	r0, d0[1]
+; ASM-NEXT:	vmov.s8	r0, d0[4]
 ; ASM-NEXT:	vmov.f32	s16, s5
 ; ASM-NEXT:	vmov.f32	s17, s9
 ; ASM-NEXT:	tst	r0, #1
@@ -36,7 +36,7 @@
 ; ASM-NEXT:	tst	r0, #1
 ; ASM-NEXT:	vmovne.f32	s17, s16
 ; ASM-NEXT:	vmov.f32	s14, s17
-; ASM-NEXT:	vmov.s8	r0, d1[1]
+; ASM-NEXT:	vmov.s8	r0, d1[4]
 ; ASM-NEXT:	vmov.f32	s4, s7
 ; ASM-NEXT:	vmov.f32	s8, s11
 ; ASM-NEXT:	tst	r0, #1
@@ -65,7 +65,7 @@
 ; ASM-NEXT:	tst	r0, #1
 ; ASM-NEXT:	movne	r2, r1
 ; ASM-NEXT:	vmov.32	d6[0], r2
-; ASM-NEXT:	vmov.s8	r0, d0[1]
+; ASM-NEXT:	vmov.s8	r0, d0[4]
 ; ASM-NEXT:	vmov.32	r1, d2[1]
 ; ASM-NEXT:	vmov.32	r2, d4[1]
 ; ASM-NEXT:	tst	r0, #1
@@ -77,7 +77,7 @@
 ; ASM-NEXT:	tst	r0, #1
 ; ASM-NEXT:	movne	r2, r1
 ; ASM-NEXT:	vmov.32	d7[0], r2
-; ASM-NEXT:	vmov.s8	r0, d1[1]
+; ASM-NEXT:	vmov.s8	r0, d1[4]
 ; ASM-NEXT:	vmov.32	r1, d3[1]
 ; ASM-NEXT:	vmov.32	r2, d5[1]
 ; ASM-NEXT:	tst	r0, #1
@@ -103,19 +103,19 @@
 ; ASM-NEXT:	tst	r0, #1
 ; ASM-NEXT:	movne	r2, r1
 ; ASM-NEXT:	vmov.16	d6[0], r2
-; ASM-NEXT:	vmov.s8	r0, d0[1]
+; ASM-NEXT:	vmov.s8	r0, d0[2]
 ; ASM-NEXT:	vmov.s16	r1, d2[1]
 ; ASM-NEXT:	vmov.s16	r2, d4[1]
 ; ASM-NEXT:	tst	r0, #1
 ; ASM-NEXT:	movne	r2, r1
 ; ASM-NEXT:	vmov.16	d6[1], r2
-; ASM-NEXT:	vmov.s8	r0, d0[2]
+; ASM-NEXT:	vmov.s8	r0, d0[4]
 ; ASM-NEXT:	vmov.s16	r1, d2[2]
 ; ASM-NEXT:	vmov.s16	r2, d4[2]
 ; ASM-NEXT:	tst	r0, #1
 ; ASM-NEXT:	movne	r2, r1
 ; ASM-NEXT:	vmov.16	d6[2], r2
-; ASM-NEXT:	vmov.s8	r0, d0[3]
+; ASM-NEXT:	vmov.s8	r0, d0[6]
 ; ASM-NEXT:	vmov.s16	r1, d2[3]
 ; ASM-NEXT:	vmov.s16	r2, d4[3]
 ; ASM-NEXT:	tst	r0, #1
@@ -127,19 +127,19 @@
 ; ASM-NEXT:	tst	r0, #1
 ; ASM-NEXT:	movne	r2, r1
 ; ASM-NEXT:	vmov.16	d7[0], r2
-; ASM-NEXT:	vmov.s8	r0, d1[1]
+; ASM-NEXT:	vmov.s8	r0, d1[2]
 ; ASM-NEXT:	vmov.s16	r1, d3[1]
 ; ASM-NEXT:	vmov.s16	r2, d5[1]
 ; ASM-NEXT:	tst	r0, #1
 ; ASM-NEXT:	movne	r2, r1
 ; ASM-NEXT:	vmov.16	d7[1], r2
-; ASM-NEXT:	vmov.s8	r0, d1[2]
+; ASM-NEXT:	vmov.s8	r0, d1[4]
 ; ASM-NEXT:	vmov.s16	r1, d3[2]
 ; ASM-NEXT:	vmov.s16	r2, d5[2]
 ; ASM-NEXT:	tst	r0, #1
 ; ASM-NEXT:	movne	r2, r1
 ; ASM-NEXT:	vmov.16	d7[2], r2
-; ASM-NEXT:	vmov.s8	r0, d1[3]
+; ASM-NEXT:	vmov.s8	r0, d1[6]
 ; ASM-NEXT:	vmov.s16	r1, d3[3]
 ; ASM-NEXT:	vmov.s16	r2, d5[3]
 ; ASM-NEXT:	tst	r0, #1