Significantly improve handling of vectors that are live across basic blocks,
[oota-llvm.git] / lib / CodeGen / SelectionDAG / DAGCombiner.cpp
index b5ac211c221e799f0839d6707503c82fa3ad6e4f..a559d3e469e2b7ba4cd36ad93d4a7157706df9ef 100644 (file)
@@ -113,7 +113,7 @@ namespace {
   private:    
     
     /// SimplifyDemandedBits - Check the specified integer node value to see if
-    /// it can be simplified or if things is uses can be simplified by bit
+    /// it can be simplified or if things it uses can be simplified by bit
     /// propagation.  If so, return true.
     bool SimplifyDemandedBits(SDOperand Op) {
       TargetLowering::TargetLoweringOpt TLO(DAG);
@@ -195,6 +195,7 @@ namespace {
     SDOperand visitFMUL(SDNode *N);
     SDOperand visitFDIV(SDNode *N);
     SDOperand visitFREM(SDNode *N);
+    SDOperand visitFCOPYSIGN(SDNode *N);
     SDOperand visitSINT_TO_FP(SDNode *N);
     SDOperand visitUINT_TO_FP(SDNode *N);
     SDOperand visitFP_TO_SINT(SDNode *N);
@@ -205,11 +206,13 @@ namespace {
     SDOperand visitFNEG(SDNode *N);
     SDOperand visitFABS(SDNode *N);
     SDOperand visitBRCOND(SDNode *N);
-    SDOperand visitBRCONDTWOWAY(SDNode *N);
     SDOperand visitBR_CC(SDNode *N);
-    SDOperand visitBRTWOWAY_CC(SDNode *N);
     SDOperand visitLOAD(SDNode *N);
     SDOperand visitSTORE(SDNode *N);
+    SDOperand visitINSERT_VECTOR_ELT(SDNode *N);
+    SDOperand visitVINSERT_VECTOR_ELT(SDNode *N);
+    SDOperand visitVBUILD_VECTOR(SDNode *N);
+    SDOperand visitVECTOR_SHUFFLE(SDNode *N);
 
     SDOperand ReassociateOps(unsigned Opc, SDOperand LHS, SDOperand RHS);
     
@@ -627,6 +630,7 @@ SDOperand DAGCombiner::visit(SDNode *N) {
   case ISD::FMUL:               return visitFMUL(N);
   case ISD::FDIV:               return visitFDIV(N);
   case ISD::FREM:               return visitFREM(N);
+  case ISD::FCOPYSIGN:          return visitFCOPYSIGN(N);
   case ISD::SINT_TO_FP:         return visitSINT_TO_FP(N);
   case ISD::UINT_TO_FP:         return visitUINT_TO_FP(N);
   case ISD::FP_TO_SINT:         return visitFP_TO_SINT(N);
@@ -637,11 +641,13 @@ SDOperand DAGCombiner::visit(SDNode *N) {
   case ISD::FNEG:               return visitFNEG(N);
   case ISD::FABS:               return visitFABS(N);
   case ISD::BRCOND:             return visitBRCOND(N);
-  case ISD::BRCONDTWOWAY:       return visitBRCONDTWOWAY(N);
   case ISD::BR_CC:              return visitBR_CC(N);
-  case ISD::BRTWOWAY_CC:        return visitBRTWOWAY_CC(N);
   case ISD::LOAD:               return visitLOAD(N);
   case ISD::STORE:              return visitSTORE(N);
+  case ISD::INSERT_VECTOR_ELT:  return visitINSERT_VECTOR_ELT(N);
+  case ISD::VINSERT_VECTOR_ELT: return visitVINSERT_VECTOR_ELT(N);
+  case ISD::VBUILD_VECTOR:      return visitVBUILD_VECTOR(N);
+  case ISD::VECTOR_SHUFFLE:     return visitVECTOR_SHUFFLE(N);
   }
   return SDOperand();
 }
@@ -663,6 +669,7 @@ SDOperand DAGCombiner::visitTokenFactor(SDNode *N) {
   for (unsigned i = 0, e = N->getNumOperands(); i != e; ++i) {
     SDOperand Op = N->getOperand(i);
     if (Op.getOpcode() == ISD::TokenFactor && Op.hasOneUse()) {
+      AddToWorkList(Op.Val);  // Remove dead node.
       Changed = true;
       for (unsigned j = 0, e = Op.getNumOperands(); j != e; ++j)
         Ops.push_back(Op.getOperand(j));
@@ -712,9 +719,27 @@ SDOperand DAGCombiner::visitADD(SDNode *N) {
   // fold (A+(B-A)) -> B
   if (N1.getOpcode() == ISD::SUB && N0 == N1.getOperand(1))
     return N1.getOperand(0);
-  // 
+
   if (!MVT::isVector(VT) && SimplifyDemandedBits(SDOperand(N, 0)))
     return SDOperand();
+  
+  // fold (a+b) -> (a|b) iff a and b share no bits.
+  if (MVT::isInteger(VT) && !MVT::isVector(VT)) {
+    uint64_t LHSZero, LHSOne;
+    uint64_t RHSZero, RHSOne;
+    uint64_t Mask = MVT::getIntVTBitMask(VT);
+    TLI.ComputeMaskedBits(N0, Mask, LHSZero, LHSOne);
+    if (LHSZero) {
+      TLI.ComputeMaskedBits(N1, Mask, RHSZero, RHSOne);
+      
+      // If all possibly-set bits on the LHS are clear on the RHS, return an OR.
+      // If all possibly-set bits on the RHS are clear on the LHS, return an OR.
+      if ((RHSZero & (~LHSZero & Mask)) == (~LHSZero & Mask) ||
+          (LHSZero & (~RHSZero & Mask)) == (~RHSZero & Mask))
+        return DAG.getNode(ISD::OR, VT, N0, N1);
+    }
+  }
+  
   return SDOperand();
 }
 
@@ -802,7 +827,13 @@ SDOperand DAGCombiner::visitMUL(SDNode *N) {
       return DAG.getNode(ISD::SHL, VT, Mul, Sh.getOperand(1));
     }
   }
-      
+  // fold (mul (add x, c1), c2) -> (add (mul x, c2), c1*c2)
+  if (N1C && N0.getOpcode() == ISD::ADD && N0.Val->hasOneUse() && 
+      isa<ConstantSDNode>(N0.getOperand(1))) {
+    return DAG.getNode(ISD::ADD, VT, 
+                       DAG.getNode(ISD::MUL, VT, N0.getOperand(0), N1),
+                       DAG.getNode(ISD::MUL, VT, N0.getOperand(1), N1));
+  }
   
   // reassociate mul
   SDOperand RMUL = ReassociateOps(ISD::MUL, N0, N1);
@@ -1018,14 +1049,19 @@ SDOperand DAGCombiner::visitAND(SDNode *N) {
         return N1;
   // fold (and (any_ext V), c) -> (zero_ext V) if 'and' only clears top bits.
   if (N1C && N0.getOpcode() == ISD::ANY_EXTEND) {
-    unsigned InBits = MVT::getSizeInBits(N0.getOperand(0).getValueType());
+    unsigned InMask = MVT::getIntVTBitMask(N0.getOperand(0).getValueType());
     if (TLI.MaskedValueIsZero(N0.getOperand(0),
-                              ~N1C->getValue() & ((1ULL << InBits)-1))) {
+                              ~N1C->getValue() & InMask)) {
+      SDOperand Zext = DAG.getNode(ISD::ZERO_EXTEND, N0.getValueType(),
+                                   N0.getOperand(0));
+      
+      // Replace uses of the AND with uses of the Zero extend node.
+      CombineTo(N, Zext);
+      
       // We actually want to replace all uses of the any_extend with the
       // zero_extend, to avoid duplicating things.  This will later cause this
       // AND to be folded.
-      CombineTo(N0.Val, DAG.getNode(ISD::ZERO_EXTEND, N0.getValueType(),
-                                    N0.getOperand(0)));
+      CombineTo(N0.Val, Zext);
       return SDOperand();
     }
   }
@@ -1088,7 +1124,8 @@ SDOperand DAGCombiner::visitAND(SDNode *N) {
   }
   // fold (and (sign_extend_inreg x, i16 to i32), 1) -> (and x, 1)
   // fold (and (sra)) -> (and (srl)) when possible.
-  if (SimplifyDemandedBits(SDOperand(N, 0)))
+  if (!MVT::isVector(VT) &&
+      SimplifyDemandedBits(SDOperand(N, 0)))
     return SDOperand();
   // fold (zext_inreg (extload x)) -> (zextload x)
   if (N0.getOpcode() == ISD::EXTLOAD) {
@@ -1363,8 +1400,16 @@ SDOperand DAGCombiner::visitXOR(SDNode *N) {
                          DAG.getConstant(N1C->getValue()^N01C->getValue(), VT));
   }
   // fold (xor x, x) -> 0
-  if (N0 == N1)
-    return DAG.getConstant(0, VT);
+  if (N0 == N1) {
+    if (!MVT::isVector(VT)) {
+      return DAG.getConstant(0, VT);
+    } else if (!AfterLegalize || TLI.isOperationLegal(ISD::BUILD_VECTOR, VT)) {
+      // Produce a vector of zeros.
+      SDOperand El = DAG.getConstant(0, MVT::getVectorBaseType(VT));
+      std::vector<SDOperand> Ops(MVT::getVectorNumElements(VT), El);
+      return DAG.getNode(ISD::BUILD_VECTOR, VT, Ops);
+    }
+  }
   // fold (xor (zext x), (zext y)) -> (zext (xor x, y))
   if (N0.getOpcode() == ISD::ZERO_EXTEND && 
       N1.getOpcode() == ISD::ZERO_EXTEND &&
@@ -1441,6 +1486,13 @@ SDOperand DAGCombiner::visitSHL(SDNode *N) {
   if (N1C && N0.getOpcode() == ISD::SRA && N1 == N0.getOperand(1))
     return DAG.getNode(ISD::AND, VT, N0.getOperand(0),
                        DAG.getConstant(~0ULL << N1C->getValue(), VT));
+  // fold (shl (add x, c1), c2) -> (add (shl x, c2), c1<<c2)
+  if (N1C && N0.getOpcode() == ISD::ADD && N0.Val->hasOneUse() && 
+      isa<ConstantSDNode>(N0.getOperand(1))) {
+    return DAG.getNode(ISD::ADD, VT, 
+                       DAG.getNode(ISD::SHL, VT, N0.getOperand(0), N1),
+                       DAG.getNode(ISD::SHL, VT, N0.getOperand(1), N1));
+  }
   return SDOperand();
 }
 
@@ -1981,6 +2033,54 @@ SDOperand DAGCombiner::visitFREM(SDNode *N) {
   return SDOperand();
 }
 
+SDOperand DAGCombiner::visitFCOPYSIGN(SDNode *N) {
+  SDOperand N0 = N->getOperand(0);
+  SDOperand N1 = N->getOperand(1);
+  ConstantFPSDNode *N0CFP = dyn_cast<ConstantFPSDNode>(N0);
+  ConstantFPSDNode *N1CFP = dyn_cast<ConstantFPSDNode>(N1);
+  MVT::ValueType VT = N->getValueType(0);
+
+  if (N0CFP && N1CFP)  // Constant fold
+    return DAG.getNode(ISD::FCOPYSIGN, VT, N0, N1);
+  
+  if (N1CFP) {
+    // copysign(x, c1) -> fabs(x)       iff ispos(c1)
+    // copysign(x, c1) -> fneg(fabs(x)) iff isneg(c1)
+    union {
+      double d;
+      int64_t i;
+    } u;
+    u.d = N1CFP->getValue();
+    if (u.i >= 0)
+      return DAG.getNode(ISD::FABS, VT, N0);
+    else
+      return DAG.getNode(ISD::FNEG, VT, DAG.getNode(ISD::FABS, VT, N0));
+  }
+  
+  // copysign(fabs(x), y) -> copysign(x, y)
+  // copysign(fneg(x), y) -> copysign(x, y)
+  // copysign(copysign(x,z), y) -> copysign(x, y)
+  if (N0.getOpcode() == ISD::FABS || N0.getOpcode() == ISD::FNEG ||
+      N0.getOpcode() == ISD::FCOPYSIGN)
+    return DAG.getNode(ISD::FCOPYSIGN, VT, N0.getOperand(0), N1);
+
+  // copysign(x, abs(y)) -> abs(x)
+  if (N1.getOpcode() == ISD::FABS)
+    return DAG.getNode(ISD::FABS, VT, N0);
+  
+  // copysign(x, copysign(y,z)) -> copysign(x, z)
+  if (N1.getOpcode() == ISD::FCOPYSIGN)
+    return DAG.getNode(ISD::FCOPYSIGN, VT, N0, N1.getOperand(1));
+  
+  // copysign(x, fp_extend(y)) -> copysign(x, y)
+  // copysign(x, fp_round(y)) -> copysign(x, y)
+  if (N1.getOpcode() == ISD::FP_EXTEND || N1.getOpcode() == ISD::FP_ROUND)
+    return DAG.getNode(ISD::FCOPYSIGN, VT, N0, N1.getOperand(0));
+  
+  return SDOperand();
+}
+
+
 
 SDOperand DAGCombiner::visitSINT_TO_FP(SDNode *N) {
   SDOperand N0 = N->getOperand(0);
@@ -2034,6 +2134,18 @@ SDOperand DAGCombiner::visitFP_ROUND(SDNode *N) {
   // fold (fp_round c1fp) -> c1fp
   if (N0CFP)
     return DAG.getNode(ISD::FP_ROUND, VT, N0);
+  
+  // fold (fp_round (fp_extend x)) -> x
+  if (N0.getOpcode() == ISD::FP_EXTEND && VT == N0.getOperand(0).getValueType())
+    return N0.getOperand(0);
+  
+  // fold (fp_round (copysign X, Y)) -> (copysign (fp_round X), Y)
+  if (N0.getOpcode() == ISD::FCOPYSIGN && N0.Val->hasOneUse()) {
+    SDOperand Tmp = DAG.getNode(ISD::FP_ROUND, VT, N0.getOperand(0));
+    AddToWorkList(Tmp.Val);
+    return DAG.getNode(ISD::FCOPYSIGN, VT, Tmp, N0.getOperand(1));
+  }
+  
   return SDOperand();
 }
 
@@ -2071,11 +2183,11 @@ SDOperand DAGCombiner::visitFNEG(SDNode *N) {
   if (N0CFP)
     return DAG.getNode(ISD::FNEG, VT, N0);
   // fold (fneg (sub x, y)) -> (sub y, x)
-  if (N->getOperand(0).getOpcode() == ISD::SUB)
-    return DAG.getNode(ISD::SUB, VT, N->getOperand(1), N->getOperand(0));
+  if (N0.getOpcode() == ISD::SUB)
+    return DAG.getNode(ISD::SUB, VT, N0.getOperand(1), N0.getOperand(0));
   // fold (fneg (fneg x)) -> x
-  if (N->getOperand(0).getOpcode() == ISD::FNEG)
-    return N->getOperand(0).getOperand(0);
+  if (N0.getOpcode() == ISD::FNEG)
+    return N0.getOperand(0);
   return SDOperand();
 }
 
@@ -2088,11 +2200,13 @@ SDOperand DAGCombiner::visitFABS(SDNode *N) {
   if (N0CFP)
     return DAG.getNode(ISD::FABS, VT, N0);
   // fold (fabs (fabs x)) -> (fabs x)
-  if (N->getOperand(0).getOpcode() == ISD::FABS)
+  if (N0.getOpcode() == ISD::FABS)
     return N->getOperand(0);
   // fold (fabs (fneg x)) -> (fabs x)
-  if (N->getOperand(0).getOpcode() == ISD::FNEG)
-    return DAG.getNode(ISD::FABS, VT, N->getOperand(0).getOperand(0));
+  // fold (fabs (fcopysign x, y)) -> (fabs x)
+  if (N0.getOpcode() == ISD::FNEG || N0.getOpcode() == ISD::FCOPYSIGN)
+    return DAG.getNode(ISD::FABS, VT, N0.getOperand(0));
+  
   return SDOperand();
 }
 
@@ -2118,35 +2232,6 @@ SDOperand DAGCombiner::visitBRCOND(SDNode *N) {
   return SDOperand();
 }
 
-SDOperand DAGCombiner::visitBRCONDTWOWAY(SDNode *N) {
-  SDOperand Chain = N->getOperand(0);
-  SDOperand N1 = N->getOperand(1);
-  SDOperand N2 = N->getOperand(2);
-  SDOperand N3 = N->getOperand(3);
-  ConstantSDNode *N1C = dyn_cast<ConstantSDNode>(N1);
-  
-  // unconditional branch to true mbb
-  if (N1C && N1C->getValue() == 1)
-    return DAG.getNode(ISD::BR, MVT::Other, Chain, N2);
-  // unconditional branch to false mbb
-  if (N1C && N1C->isNullValue())
-    return DAG.getNode(ISD::BR, MVT::Other, Chain, N3);
-  // fold a brcondtwoway with a setcc condition into a BRTWOWAY_CC node if 
-  // BRTWOWAY_CC is legal on the target.
-  if (N1.getOpcode() == ISD::SETCC && 
-      TLI.isOperationLegal(ISD::BRTWOWAY_CC, MVT::Other)) {
-    std::vector<SDOperand> Ops;
-    Ops.push_back(Chain);
-    Ops.push_back(N1.getOperand(2));
-    Ops.push_back(N1.getOperand(0));
-    Ops.push_back(N1.getOperand(1));
-    Ops.push_back(N2);
-    Ops.push_back(N3);
-    return DAG.getNode(ISD::BRTWOWAY_CC, MVT::Other, Ops);
-  }
-  return SDOperand();
-}
-
 // Operand List for BR_CC: Chain, CondCC, CondLHS, CondRHS, DestBB.
 //
 SDOperand DAGCombiner::visitBR_CC(SDNode *N) {
@@ -2172,41 +2257,6 @@ SDOperand DAGCombiner::visitBR_CC(SDNode *N) {
   return SDOperand();
 }
 
-SDOperand DAGCombiner::visitBRTWOWAY_CC(SDNode *N) {
-  SDOperand Chain = N->getOperand(0);
-  SDOperand CCN = N->getOperand(1);
-  SDOperand LHS = N->getOperand(2);
-  SDOperand RHS = N->getOperand(3);
-  SDOperand N4 = N->getOperand(4);
-  SDOperand N5 = N->getOperand(5);
-  
-  SDOperand SCC = SimplifySetCC(TLI.getSetCCResultTy(), LHS, RHS,
-                                cast<CondCodeSDNode>(CCN)->get(), false);
-  ConstantSDNode *SCCC = dyn_cast_or_null<ConstantSDNode>(SCC.Val);
-  
-  // fold select_cc lhs, rhs, x, x, cc -> x
-  if (N4 == N5)
-    return DAG.getNode(ISD::BR, MVT::Other, Chain, N4);
-  // fold select_cc true, x, y -> x
-  if (SCCC && SCCC->getValue())
-    return DAG.getNode(ISD::BR, MVT::Other, Chain, N4);
-  // fold select_cc false, x, y -> y
-  if (SCCC && SCCC->isNullValue())
-    return DAG.getNode(ISD::BR, MVT::Other, Chain, N5);
-  // fold to a simpler setcc
-  if (SCC.Val && SCC.getOpcode() == ISD::SETCC) {
-    std::vector<SDOperand> Ops;
-    Ops.push_back(Chain);
-    Ops.push_back(SCC.getOperand(2));
-    Ops.push_back(SCC.getOperand(0));
-    Ops.push_back(SCC.getOperand(1));
-    Ops.push_back(N4);
-    Ops.push_back(N5);
-    return DAG.getNode(ISD::BRTWOWAY_CC, MVT::Other, Ops);
-  }
-  return SDOperand();
-}
-
 SDOperand DAGCombiner::visitLOAD(SDNode *N) {
   SDOperand Chain    = N->getOperand(0);
   SDOperand Ptr      = N->getOperand(1);
@@ -2257,6 +2307,166 @@ SDOperand DAGCombiner::visitSTORE(SDNode *N) {
   return SDOperand();
 }
 
+SDOperand DAGCombiner::visitINSERT_VECTOR_ELT(SDNode *N) {
+  SDOperand InVec = N->getOperand(0);
+  SDOperand InVal = N->getOperand(1);
+  SDOperand EltNo = N->getOperand(2);
+  
+  // If the invec is a BUILD_VECTOR and if EltNo is a constant, build a new
+  // vector with the inserted element.
+  if (InVec.getOpcode() == ISD::BUILD_VECTOR && isa<ConstantSDNode>(EltNo)) {
+    unsigned Elt = cast<ConstantSDNode>(EltNo)->getValue();
+    std::vector<SDOperand> Ops(InVec.Val->op_begin(), InVec.Val->op_end());
+    if (Elt < Ops.size())
+      Ops[Elt] = InVal;
+    return DAG.getNode(ISD::BUILD_VECTOR, InVec.getValueType(), Ops);
+  }
+  
+  return SDOperand();
+}
+
+SDOperand DAGCombiner::visitVINSERT_VECTOR_ELT(SDNode *N) {
+  SDOperand InVec = N->getOperand(0);
+  SDOperand InVal = N->getOperand(1);
+  SDOperand EltNo = N->getOperand(2);
+  SDOperand NumElts = N->getOperand(3);
+  SDOperand EltType = N->getOperand(4);
+  
+  // If the invec is a VBUILD_VECTOR and if EltNo is a constant, build a new
+  // vector with the inserted element.
+  if (InVec.getOpcode() == ISD::VBUILD_VECTOR && isa<ConstantSDNode>(EltNo)) {
+    unsigned Elt = cast<ConstantSDNode>(EltNo)->getValue();
+    std::vector<SDOperand> Ops(InVec.Val->op_begin(), InVec.Val->op_end());
+    if (Elt < Ops.size()-2)
+      Ops[Elt] = InVal;
+    return DAG.getNode(ISD::VBUILD_VECTOR, InVec.getValueType(), Ops);
+  }
+  
+  return SDOperand();
+}
+
+SDOperand DAGCombiner::visitVBUILD_VECTOR(SDNode *N) {
+  unsigned NumInScalars = N->getNumOperands()-2;
+  SDOperand NumElts = N->getOperand(NumInScalars);
+  SDOperand EltType = N->getOperand(NumInScalars+1);
+
+  // Check to see if this is a VBUILD_VECTOR of a bunch of VEXTRACT_VECTOR_ELT
+  // operations.  If so, and if the EXTRACT_ELT vector inputs come from at most
+  // two distinct vectors, turn this into a shuffle node.
+  SDOperand VecIn1, VecIn2;
+  for (unsigned i = 0; i != NumInScalars; ++i) {
+    // Ignore undef inputs.
+    if (N->getOperand(i).getOpcode() == ISD::UNDEF) continue;
+    
+    // If this input is something other than a VEXTRACT_VECTOR_ELT with a
+    // constant index, bail out.
+    if (N->getOperand(i).getOpcode() != ISD::VEXTRACT_VECTOR_ELT ||
+        !isa<ConstantSDNode>(N->getOperand(i).getOperand(1))) {
+      VecIn1 = VecIn2 = SDOperand(0, 0);
+      break;
+    }
+    
+    // If the input vector type disagrees with the result of the vbuild_vector,
+    // we can't make a shuffle.
+    SDOperand ExtractedFromVec = N->getOperand(i).getOperand(0);
+    if (*(ExtractedFromVec.Val->op_end()-2) != NumElts ||
+        *(ExtractedFromVec.Val->op_end()-1) != EltType) {
+      VecIn1 = VecIn2 = SDOperand(0, 0);
+      break;
+    }
+    
+    // Otherwise, remember this.  We allow up to two distinct input vectors.
+    if (ExtractedFromVec == VecIn1 || ExtractedFromVec == VecIn2)
+      continue;
+    
+    if (VecIn1.Val == 0) {
+      VecIn1 = ExtractedFromVec;
+    } else if (VecIn2.Val == 0) {
+      VecIn2 = ExtractedFromVec;
+    } else {
+      // Too many inputs.
+      VecIn1 = VecIn2 = SDOperand(0, 0);
+      break;
+    }
+  }
+  
+  // If everything is good, we can make a shuffle operation.
+  if (VecIn1.Val) {
+    std::vector<SDOperand> BuildVecIndices;
+    for (unsigned i = 0; i != NumInScalars; ++i) {
+      if (N->getOperand(i).getOpcode() == ISD::UNDEF) {
+        BuildVecIndices.push_back(DAG.getNode(ISD::UNDEF, MVT::i32));
+        continue;
+      }
+      
+      SDOperand Extract = N->getOperand(i);
+      
+      // If extracting from the first vector, just use the index directly.
+      if (Extract.getOperand(0) == VecIn1) {
+        BuildVecIndices.push_back(Extract.getOperand(1));
+        continue;
+      }
+
+      // Otherwise, use InIdx + VecSize
+      unsigned Idx = cast<ConstantSDNode>(Extract.getOperand(1))->getValue();
+      BuildVecIndices.push_back(DAG.getConstant(Idx+NumInScalars, MVT::i32));
+    }
+    
+    // Add count and size info.
+    BuildVecIndices.push_back(NumElts);
+    BuildVecIndices.push_back(DAG.getValueType(MVT::i32));
+    
+    // Return the new VVECTOR_SHUFFLE node.
+    std::vector<SDOperand> Ops;
+    Ops.push_back(VecIn1);
+    if (VecIn2.Val) {
+      Ops.push_back(VecIn2);
+    } else {
+       // Use an undef vbuild_vector as input for the second operand.
+      std::vector<SDOperand> UnOps(NumInScalars,
+                                   DAG.getNode(ISD::UNDEF, 
+                                           cast<VTSDNode>(EltType)->getVT()));
+      UnOps.push_back(NumElts);
+      UnOps.push_back(EltType);
+      Ops.push_back(DAG.getNode(ISD::VBUILD_VECTOR, MVT::Vector, UnOps));
+    }
+    Ops.push_back(DAG.getNode(ISD::VBUILD_VECTOR,MVT::Vector, BuildVecIndices));
+    Ops.push_back(NumElts);
+    Ops.push_back(EltType);
+    return DAG.getNode(ISD::VVECTOR_SHUFFLE, MVT::Vector, Ops);
+  }
+  
+  return SDOperand();
+}
+
+SDOperand DAGCombiner::visitVECTOR_SHUFFLE(SDNode *N) {
+  // If the LHS and the RHS are the same node, turn the RHS into an undef.
+  if (N->getOperand(0) == N->getOperand(1)) {
+    // Check the SHUFFLE mask, mapping any inputs from the 2nd operand into the
+    // first operand.
+    std::vector<SDOperand> MappedOps;
+    SDOperand ShufMask = N->getOperand(2);
+    unsigned NumElts = ShufMask.getNumOperands();
+    for (unsigned i = 0, e = ShufMask.getNumOperands(); i != e; ++i) {
+      if (cast<ConstantSDNode>(ShufMask.getOperand(i))->getValue() >= NumElts) {
+        unsigned NewIdx = 
+           cast<ConstantSDNode>(ShufMask.getOperand(i))->getValue() - NumElts;
+        MappedOps.push_back(DAG.getConstant(NewIdx, MVT::i32));
+      } else {
+        MappedOps.push_back(ShufMask.getOperand(i));
+      }
+    }
+    ShufMask = DAG.getNode(ISD::BUILD_VECTOR, ShufMask.getValueType(),
+                           MappedOps);
+    return DAG.getNode(ISD::VECTOR_SHUFFLE, N->getValueType(0),
+                       N->getOperand(0), 
+                       DAG.getNode(ISD::UNDEF, N->getValueType(0)),
+                       ShufMask);
+  }
+  return SDOperand();
+}
+
 SDOperand DAGCombiner::SimplifySelect(SDOperand N0, SDOperand N1, SDOperand N2){
   assert(N0.getOpcode() ==ISD::SETCC && "First argument must be a SetCC node!");