Transform things like (splat(splat)) -> splat
authorChris Lattner <sabre@nondot.org>
Fri, 26 May 2006 00:29:06 +0000 (00:29 +0000)
committerChris Lattner <sabre@nondot.org>
Fri, 26 May 2006 00:29:06 +0000 (00:29 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@28490 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Transforms/Scalar/InstructionCombining.cpp

index 6196ccf17e58b29923c79a2d8ff20ec874a52c12..1264e55497dade2076b87203fe9976b91bfbb60e 100644 (file)
@@ -7398,18 +7398,26 @@ Instruction *InstCombiner::visitShuffleVectorInst(ShuffleVectorInst &SVI) {
     // Remap any references to RHS to use LHS.
     std::vector<Constant*> Elts;
     for (unsigned i = 0, e = Mask.size(); i != e; ++i) {
-      if (Mask[i] > 2*e)
+      if (Mask[i] >= 2*e)
         Elts.push_back(UndefValue::get(Type::UIntTy));
-      else
-        Elts.push_back(ConstantUInt::get(Type::UIntTy, Mask[i] & (e-1)));
+      else {
+        if ((Mask[i] >= e && isa<UndefValue>(RHS)) ||
+            (Mask[i] <  e && isa<UndefValue>(LHS)))
+          Mask[i] = 2*e;     // Turn into undef.
+        else
+          Mask[i] &= (e-1);  // Force to LHS.
+        Elts.push_back(ConstantUInt::get(Type::UIntTy, Mask[i]));
+      }
     }
     SVI.setOperand(0, SVI.getOperand(1));
     SVI.setOperand(1, UndefValue::get(RHS->getType()));
     SVI.setOperand(2, ConstantPacked::get(Elts));
+    LHS = SVI.getOperand(0);
+    RHS = SVI.getOperand(1);
     MadeChange = true;
   }
   
-  // Analyze the shuffle, are the LHS or RHS and identity shuffle?
+  // Analyze the shuffle, are the LHS or RHS and identity shuffles?
   bool isLHSID = true, isRHSID = true;
     
   for (unsigned i = 0, e = Mask.size(); i != e; ++i) {
@@ -7425,6 +7433,44 @@ Instruction *InstCombiner::visitShuffleVectorInst(ShuffleVectorInst &SVI) {
   if (isLHSID) return ReplaceInstUsesWith(SVI, LHS);
   if (isRHSID) return ReplaceInstUsesWith(SVI, RHS);
   
+  // If the LHS is a shufflevector itself, see if we can combine it with this
+  // one without producing an unusual shuffle.  Here we are really conservative:
+  // we are absolutely afraid of producing a shuffle mask not in the input
+  // program, because the code gen may not be smart enough to turn a merged
+  // shuffle into two specific shuffles: it may produce worse code.  As such,
+  // we only merge two shuffles if the result is one of the two input shuffle
+  // masks.  In this case, merging the shuffles just removes one instruction,
+  // which we know is safe.  This is good for things like turning:
+  // (splat(splat)) -> splat.
+  if (ShuffleVectorInst *LHSSVI = dyn_cast<ShuffleVectorInst>(LHS)) {
+    if (isa<UndefValue>(RHS)) {
+      std::vector<unsigned> LHSMask = getShuffleMask(LHSSVI);
+
+      std::vector<unsigned> NewMask;
+      for (unsigned i = 0, e = Mask.size(); i != e; ++i)
+        if (Mask[i] >= 2*e)
+          NewMask.push_back(2*e);
+        else
+          NewMask.push_back(LHSMask[Mask[i]]);
+      
+      // If the result mask is equal to the src shuffle or this shuffle mask, do
+      // the replacement.
+      if (NewMask == LHSMask || NewMask == Mask) {
+        std::vector<Constant*> Elts;
+        for (unsigned i = 0, e = NewMask.size(); i != e; ++i) {
+          if (NewMask[i] >= e*2) {
+            Elts.push_back(UndefValue::get(Type::UIntTy));
+          } else {
+            Elts.push_back(ConstantUInt::get(Type::UIntTy, NewMask[i]));
+          }
+        }
+        return new ShuffleVectorInst(LHSSVI->getOperand(0),
+                                     LHSSVI->getOperand(1),
+                                     ConstantPacked::get(Elts));
+      }
+    }
+  }
+  
   return MadeChange ? &SVI : 0;
 }