Vector codegen improvements


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@62458 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
index 6877b31..6e140da 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -631,6 +631,8 @@
   case X86::BI__builtin_ia32_vec_ext_v2di:
   case X86::BI__builtin_ia32_vec_ext_v4sf:
   case X86::BI__builtin_ia32_vec_ext_v4si:
+  case X86::BI__builtin_ia32_vec_ext_v8hi:
+  case X86::BI__builtin_ia32_vec_ext_v4hi:
   case X86::BI__builtin_ia32_vec_ext_v2df:
     return Builder.CreateExtractElement(Ops[0], Ops[1], "result");
   case X86::BI__builtin_ia32_cmpordss:
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index 2d51efa..5c304d1 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -309,8 +309,8 @@
   return EmitObjCPropertyGet(LV.getKVCRefExpr());
 }
 
-// If this is a reference to a subset of the elements of a vector, either
-// shuffle the input or extract/insert them as appropriate.
+// If this is a reference to a subset of the elements of a vector, create an
+// appropriate shufflevector.
 RValue CodeGenFunction::EmitLoadOfExtVectorElementLValue(LValue LV,
                                                          QualType ExprType) {
   llvm::Value *Vec = Builder.CreateLoad(LV.getExtVectorAddr(),
@@ -326,41 +326,21 @@
     llvm::Value *Elt = llvm::ConstantInt::get(llvm::Type::Int32Ty, InIdx);
     return RValue::get(Builder.CreateExtractElement(Vec, Elt, "tmp"));
   }
-  
-  // If the source and destination have the same number of elements, use a
-  // vector shuffle instead of insert/extracts.
+
+  // Always use shuffle vector to try to retain the original program structure
   unsigned NumResultElts = ExprVT->getNumElements();
-  unsigned NumSourceElts =
-    cast<llvm::VectorType>(Vec->getType())->getNumElements();
   
-  if (NumResultElts == NumSourceElts) {
-    llvm::SmallVector<llvm::Constant*, 4> Mask;
-    for (unsigned i = 0; i != NumResultElts; ++i) {
-      unsigned InIdx = getAccessedFieldNo(i, Elts);
-      Mask.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, InIdx));
-    }
-    
-    llvm::Value *MaskV = llvm::ConstantVector::get(&Mask[0], Mask.size());
-    Vec = Builder.CreateShuffleVector(Vec,
-                                      llvm::UndefValue::get(Vec->getType()),
-                                      MaskV, "tmp");
-    return RValue::get(Vec);
-  }
-  
-  // Start out with an undef of the result type.
-  llvm::Value *Result = llvm::UndefValue::get(ConvertType(ExprType));
-  
-  // Extract/Insert each element of the result.
+  llvm::SmallVector<llvm::Constant*, 4> Mask;
   for (unsigned i = 0; i != NumResultElts; ++i) {
     unsigned InIdx = getAccessedFieldNo(i, Elts);
-    llvm::Value *Elt = llvm::ConstantInt::get(llvm::Type::Int32Ty, InIdx);
-    Elt = Builder.CreateExtractElement(Vec, Elt, "tmp");
-    
-    llvm::Value *OutIdx = llvm::ConstantInt::get(llvm::Type::Int32Ty, i);
-    Result = Builder.CreateInsertElement(Result, Elt, OutIdx, "tmp");
+    Mask.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, InIdx));
   }
   
-  return RValue::get(Result);
+  llvm::Value *MaskV = llvm::ConstantVector::get(&Mask[0], Mask.size());
+  Vec = Builder.CreateShuffleVector(Vec,
+                                    llvm::UndefValue::get(Vec->getType()),
+                                    MaskV, "tmp");
+  return RValue::get(Vec);
 }
 
 
@@ -548,15 +528,54 @@
   
   if (const VectorType *VTy = Ty->getAsVectorType()) {
     unsigned NumSrcElts = VTy->getNumElements();
-
-    // Extract/Insert each element.
-    for (unsigned i = 0; i != NumSrcElts; ++i) {
-      llvm::Value *Elt = llvm::ConstantInt::get(llvm::Type::Int32Ty, i);
-      Elt = Builder.CreateExtractElement(SrcVal, Elt, "tmp");
-      
-      unsigned Idx = getAccessedFieldNo(i, Elts);
-      llvm::Value *OutIdx = llvm::ConstantInt::get(llvm::Type::Int32Ty, Idx);
-      Vec = Builder.CreateInsertElement(Vec, Elt, OutIdx, "tmp");
+    unsigned NumDstElts =
+       cast<llvm::VectorType>(Vec->getType())->getNumElements();
+    if (NumDstElts == NumSrcElts) {
+      // Use shuffle vector is the src and destination are the same number
+      // of elements
+      llvm::SmallVector<llvm::Constant*, 4> Mask;
+      for (unsigned i = 0; i != NumSrcElts; ++i) {
+        unsigned InIdx = getAccessedFieldNo(i, Elts);
+        Mask.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, InIdx));
+      }
+    
+      llvm::Value *MaskV = llvm::ConstantVector::get(&Mask[0], Mask.size());
+      Vec = Builder.CreateShuffleVector(SrcVal,
+                                        llvm::UndefValue::get(Vec->getType()),
+                                        MaskV, "tmp");
+    }
+    else if (NumDstElts > NumSrcElts) {
+      // Extended the source vector to the same length and then shuffle it
+      // into the destination.
+      // FIXME: since we're shuffling with undef, can we just use the indices
+      //        into that?  This could be simpler.
+      llvm::SmallVector<llvm::Constant*, 4> ExtMask;
+      unsigned i;
+      for (i = 0; i != NumSrcElts; ++i)
+        ExtMask.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, i));
+      for (; i != NumDstElts; ++i)
+        ExtMask.push_back(llvm::UndefValue::get(llvm::Type::Int32Ty));
+      llvm::Value *ExtMaskV = llvm::ConstantVector::get(&ExtMask[0],
+                                                        ExtMask.size());
+      llvm::Value *ExtSrcVal = Builder.CreateShuffleVector(SrcVal,
+                                        llvm::UndefValue::get(SrcVal->getType()),
+                                        ExtMaskV, "tmp");
+      // build identity
+      llvm::SmallVector<llvm::Constant*, 4> Mask;
+      for (unsigned i = 0; i != NumDstElts; ++i) {
+        Mask.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, i));
+      }
+      // modify when what gets shuffled in
+      for (unsigned i = 0; i != NumSrcElts; ++i) {
+        unsigned Idx = getAccessedFieldNo(i, Elts);
+        Mask[Idx] =llvm::ConstantInt::get(llvm::Type::Int32Ty, i+NumDstElts);
+      }
+      llvm::Value *MaskV = llvm::ConstantVector::get(&Mask[0], Mask.size());
+      Vec = Builder.CreateShuffleVector(Vec, ExtSrcVal, MaskV, "tmp");
+    }
+    else {
+      // We should never shorten the vector
+      assert(0 && "unexpected shorten vector length");
     }
   } else {
     // If the Src is a scalar (not a vector) it must be updating one element.
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index d6cc16c..e6eb9c0b 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -409,10 +409,26 @@
   }
   
   // A scalar can be splatted to an extended vector of the same element type
-  if (DstType->isExtVectorType() && !isa<VectorType>(SrcType) &&
-      cast<llvm::VectorType>(DstTy)->getElementType() == Src->getType())
-    return CGF.EmitVector(&Src, DstType->getAsVectorType()->getNumElements(), 
-                          true);
+  if (DstType->isExtVectorType() && !isa<VectorType>(SrcType)) {
+    // Cast the scalar to element type
+    QualType EltTy = DstType->getAsExtVectorType()->getElementType();
+    llvm::Value *Elt = EmitScalarConversion(Src, SrcType, EltTy);
+
+    // Insert the element in element zero of an undef vector
+    llvm::Value *UnV = llvm::UndefValue::get(DstTy);
+    llvm::Value *Idx = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0);
+    UnV = Builder.CreateInsertElement(UnV, Elt, Idx, "tmp");
+
+    // Splat the element across to all elements
+    llvm::SmallVector<llvm::Constant*, 16> Args;
+    unsigned NumElements = cast<llvm::VectorType>(DstTy)->getNumElements();
+    for (unsigned i = 0; i < NumElements; i++)
+      Args.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, 0));
+    
+    llvm::Constant *Mask = llvm::ConstantVector::get(&Args[0], NumElements);
+    llvm::Value *Yay = Builder.CreateShuffleVector(UnV, UnV, Mask, "splat");
+    return Yay;
+  }
 
   // Allow bitcast from vector to integer/fp of the same size.
   if (isa<llvm::VectorType>(Src->getType()) ||