[llvm] [SLP]Add umax/umin/smax/smin as main opcodes for copyables (PR #209326)

Alexey Bataev via llvm-commits llvm-commits at lists.llvm.org
Sun Jul 19 11:58:53 PDT 2026


https://github.com/alexey-bataev updated https://github.com/llvm/llvm-project/pull/209326

>From a6ca941ac9b4690425544c3f36724601461bafce Mon Sep 17 00:00:00 2001
From: Alexey Bataev <a.bataev at outlook.com>
Date: Mon, 13 Jul 2026 15:39:24 -0700
Subject: [PATCH] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20initia?=
 =?UTF-8?q?l=20version?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Created using spr 1.3.7
---
 .../Transforms/Vectorize/SLPVectorizer.cpp    | 134 +++++++++++++-----
 .../SLPVectorizer/X86/debug-info-salvage.ll   |  43 +++---
 .../X86/minmax-main-opcode-copyables-cost.ll  |  16 +--
 .../X86/minmax-main-opcode-copyables.ll       |  65 ++++-----
 .../X86/split-node-num-operands.ll            |  77 +++++-----
 .../SLPVectorizer/splat-buildvector.ll        |   5 +-
 6 files changed, 194 insertions(+), 146 deletions(-)

diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index 7e22ba3bd149c..83ab156906b81 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -1269,6 +1269,19 @@ class InstructionsState {
   /// Some of the instructions in the list have alternate opcodes.
   bool isAltShuffle() const { return getMainOp() != getAltOp(); }
 
+  /// Checks if \p I is the same operation as \p Op: same opcode, and, for
+  /// calls, the same intrinsic ID. All calls share the Call opcode regardless
+  /// of callee, so e.g. llvm.umax and llvm.smax are not the same operation
+  /// even though `getOpcode()` cannot tell them apart.
+  static bool isSameOperation(const Instruction *I, const Instruction *Op) {
+    if (I->getOpcode() != Op->getOpcode())
+      return false;
+    if (const auto *IOp = dyn_cast<IntrinsicInst>(Op))
+      if (const auto *II = dyn_cast<IntrinsicInst>(I))
+        return II->getIntrinsicID() == IOp->getIntrinsicID();
+    return true;
+  }
+
   /// Checks if the instruction matches either the main or alternate opcode.
   /// \returns
   /// - MainOp if \param I matches MainOp's opcode directly or can be converted
@@ -1278,16 +1291,18 @@ class InstructionsState {
   /// - nullptr if \param I cannot be matched or converted to either opcode
   Instruction *getMatchingMainOpOrAltOp(Instruction *I) const {
     assert(MainOp && "MainOp cannot be nullptr.");
-    if (I->getOpcode() == MainOp->getOpcode())
+    if (isSameOperation(I, MainOp))
       return MainOp;
     if (MainOp->getOpcode() == Instruction::Select &&
         I->getOpcode() == Instruction::ZExt && !isAltShuffle())
       return MainOp;
     // Prefer AltOp instead of interchangeable instruction of MainOp.
     assert(AltOp && "AltOp cannot be nullptr.");
-    if (I->getOpcode() == AltOp->getOpcode())
+    if (isSameOperation(I, AltOp))
       return AltOp;
-    if (!I->isBinaryOp())
+    // BinOpSameOpcodeHelper only models interchangeable BinaryOperators, so a
+    // non-BinaryOperator MainOp (e.g. a call) cannot match here.
+    if (!I->isBinaryOp() || !isa<BinaryOperator>(MainOp))
       return nullptr;
     BinOpSameOpcodeHelper Converter(MainOp);
     if (!Converter.add(I) || !Converter.add(MainOp))
@@ -1364,9 +1379,11 @@ class InstructionsState {
         (!isVectorLikeInstWithConstOps(I) ||
          !isVectorLikeInstWithConstOps(MainOp)))
       return true;
-    if (I->getOpcode() == MainOp->getOpcode())
+    if (isSameOperation(I, MainOp))
       return false;
-    if (!I->isBinaryOp())
+    // BinOpSameOpcodeHelper only models interchangeable BinaryOperators, so a
+    // non-BinaryOperator MainOp (e.g. a call) is unconditionally copyable.
+    if (!I->isBinaryOp() || !isa<BinaryOperator>(MainOp))
       return true;
     BinOpSameOpcodeHelper Converter(MainOp);
     return !Converter.add(I) || !Converter.add(MainOp) ||
@@ -1460,6 +1477,10 @@ convertTo(Instruction *I, const InstructionsState &S) {
     BinOpSameOpcodeHelper Converter(I);
     return std::make_pair(SelectedOp, Converter.getOperand(SelectedOp));
   }
+  // CallInst::operands() also includes the called function itself as a
+  // trailing operand, which is not a real argument; use args() instead.
+  if (auto *CI = dyn_cast<CallInst>(I))
+    return std::make_pair(SelectedOp, SmallVector<Value *>(CI->args()));
   return std::make_pair(SelectedOp, SmallVector<Value *>(I->operands()));
 }
 
@@ -3287,7 +3308,6 @@ class slpvectorizer::BoUpSLP {
       // IntrinsicInst::isCommutative returns true if swapping the first "two"
       // arguments to the intrinsic produces the same result.
       Instruction *MainOp = S.getMainOp();
-      unsigned NumOperands = MainOp->getNumOperands();
       ArgSize = ::getNumberOfPotentiallyCommutativeOps(MainOp);
       OpsVec.resize(ArgSize);
       unsigned NumLanes = VL.size();
@@ -3306,7 +3326,7 @@ class slpvectorizer::BoUpSLP {
         // the inverse operations by checking commutativity.
         auto *I = dyn_cast<Instruction>(VL[Lane]);
         if (!I && isa<PoisonValue>(VL[Lane])) {
-          for (unsigned OpIdx : seq<unsigned>(NumOperands))
+          for (unsigned OpIdx : seq<unsigned>(ArgSize))
             OpsVec[OpIdx][Lane] = {Operands[OpIdx][Lane], true, false};
           continue;
         }
@@ -11311,6 +11331,10 @@ BoUpSLP::TreeEntry::EntryState BoUpSLP::getScalarsVectorizationState(
       if (isVectorIntrinsicWithScalarOpAtArg(ID, J, TTI))
         ScalarArgs[J] = CI->getArgOperand(J);
     for (Value *V : VL) {
+      // A copyable element stands in for the call via a substituted
+      // idempotent operand, so it is exempt from the checks below.
+      if (S.isCopyableElement(V))
+        continue;
       CallInst *CI2 = dyn_cast<CallInst>(V);
       if (!CI2 || CI2->getCalledFunction() != F ||
           getVectorIntrinsicIDForCall(CI2, TLI) != ID ||
@@ -11905,6 +11929,22 @@ class InstructionsCompatibilityAnalysis {
            Opcode == Instruction::FDiv;
   }
 
+  /// Checks if \p I can be used as the main instruction for copyable elements
+  /// analysis, i.e. it is either a supported binary operator or a call to one
+  /// of the integer min/max intrinsics. Only the integer intrinsics qualify,
+  /// since they have a well-defined idempotent value; the FP variants do not
+  /// (NaN handling means no single value is idempotent for all inputs).
+  bool isSupportedMainOp(Instruction *I) const {
+    if (isSupportedOpcode(I->getOpcode()))
+      return true;
+    auto *CI = dyn_cast<CallInst>(I);
+    if (!CI)
+      return false;
+    Intrinsic::ID ID = getVectorIntrinsicIDForCall(CI, &TLI);
+    return ID == Intrinsic::umax || ID == Intrinsic::umin ||
+           ID == Intrinsic::smax || ID == Intrinsic::smin;
+  }
+
   /// Identifies the best candidate value, which represents main opcode
   /// operation.
   /// Currently the best candidate is the Add instruction with the parent
@@ -11915,7 +11955,7 @@ class InstructionsCompatibilityAnalysis {
     auto IsSupportedInstruction = [&](Instruction *I, bool AnyUndef) {
       if (AnyUndef && (I->isIntDivRem() || I->isFPDivRem() || isa<CallInst>(I)))
         return false;
-      return I && isSupportedOpcode(I->getOpcode()) &&
+      return I && isSupportedMainOp(I) &&
              (!doesNotNeedToBeScheduled(I) || !R.isVectorized(I));
     };
     // Exclude operands instructions immediately to improve compile time, it
@@ -12016,9 +12056,13 @@ class InstructionsCompatibilityAnalysis {
 
   /// Returns the idempotent value for the \p MainOp with the detected \p
   /// MainOpcode. For Add, returns 0. For Or, it should choose between false and
-  /// the operand itself, since V or V == V.
+  /// the operand itself, since V or V == V. For the min/max intrinsics, returns
+  /// the corresponding limit value (e.g. 0 for umax, since umax(V, 0) == V).
   Value *selectBestIdempotentValue() const {
-    assert(isSupportedOpcode(MainOpcode) && "Unsupported opcode");
+    assert(isSupportedMainOp(MainOp) && "Unsupported opcode");
+    if (auto *CI = dyn_cast<CallInst>(MainOp))
+      return ConstantExpr::getIntrinsicIdentity(
+          getVectorIntrinsicIDForCall(CI, &TLI), MainOp->getType());
     return ConstantExpr::getBinOpIdentity(MainOpcode, MainOp->getType(),
                                           !MainOp->isCommutative());
   }
@@ -12031,7 +12075,7 @@ class InstructionsCompatibilityAnalysis {
       return {V, V};
     if (!S.isCopyableElement(V))
       return convertTo(cast<Instruction>(V), S).second;
-    assert(isSupportedOpcode(MainOpcode) && "Unsupported opcode");
+    assert(isSupportedMainOp(MainOp) && "Unsupported opcode");
     return {V, selectBestIdempotentValue()};
   }
 
@@ -12463,14 +12507,14 @@ class InstructionsCompatibilityAnalysis {
       // If this pattern is supported by the target then we consider the order.
       if (TTI.isLegalAltInstr(VecTy, Opcode0, Opcode1, OpcodeMask))
         return S;
-    } else if (S && (!VectorizeCopyableElements ||
-                     !isa<BinaryOperator>(S.getMainOp()) ||
-                     all_of(VL, [&](Value *V) {
-                       auto *I = dyn_cast<Instruction>(V);
-                       return !I || I->getOpcode() == S.getOpcode() ||
-                              (S.getOpcode() == Instruction::Add &&
-                               I->getOpcode() == Instruction::Shl);
-                     }))) {
+    } else if (S &&
+               (!VectorizeCopyableElements ||
+                !isSupportedMainOp(S.getMainOp()) || all_of(VL, [&](Value *V) {
+                  auto *I = dyn_cast<Instruction>(V);
+                  return !I || I->getOpcode() == S.getOpcode() ||
+                         (S.getOpcode() == Instruction::Add &&
+                          I->getOpcode() == Instruction::Shl);
+                }))) {
       return S;
     }
     if (!VectorizeCopyableElements)
@@ -12499,6 +12543,10 @@ class InstructionsCompatibilityAnalysis {
           Candidates.emplace_back(V1, (I1 || I2) ? V2 : V1);
         };
     if (VL.size() == 2) {
+      // The operand-pairing heuristic below does not apply to calls; defer
+      // to the full tree cost computation instead of pre-rejecting here.
+      if (MainOpcode == Instruction::Call)
+        return S;
       // Check if the operands allow better vectorization.
       SmallVector<std::pair<Value *, Value *>, 4> Candidates1, Candidates2;
       BuildCandidates(Candidates1, Operands[0][0], Operands[0][1]);
@@ -12540,6 +12588,7 @@ class InstructionsCompatibilityAnalysis {
         VectorCost = TTI.getArithmeticInstrCost(MainOpcode, VecTy, Kind);
         break;
       default:
+        // Instruction::Call returns above before reaching this switch.
         llvm_unreachable("Unexpected instruction.");
       }
       if (VectorCost > ScalarCost)
@@ -12601,6 +12650,10 @@ class InstructionsCompatibilityAnalysis {
     auto CheckOperand = [&](ArrayRef<Value *> Ops) {
       if (allConstant(Ops) || isSplat(Ops))
         return true;
+      // Non-instruction operands of a call (args, constants) are always a
+      // trivial gather, same as the constant/splat cases above.
+      if (MainOpcode == Instruction::Call && none_of(Ops, IsaPred<Instruction>))
+        return true;
       // Check if it is "almost" splat, i.e. has >= 4 elements and only single
       // one is different.
       constexpr unsigned Limit = 4;
@@ -12640,9 +12693,13 @@ class InstructionsCompatibilityAnalysis {
     if (S.areInstructionsWithCopyableElements()) {
       MainOp = S.getMainOp();
       MainOpcode = S.getOpcode();
+      // Use the argument count, not the raw operand count, so a call's
+      // trailing callee operand is not miscounted.
+      const unsigned NumMainOpOperands =
+          ::getNumberOfPotentiallyCommutativeOps(MainOp);
       const bool IsCommutative =
-          isCommutative(MainOp) && MainOp->getNumOperands() == 2;
-      Operands.assign(MainOp->getNumOperands(),
+          isCommutative(MainOp) && NumMainOpOperands == 2;
+      Operands.assign(NumMainOpOperands,
                       BoUpSLP::ValueList(VL.size(), nullptr));
       // Populate operands for every lane.
       for (auto [Idx, V] : enumerate(VL)) {
@@ -18094,6 +18151,11 @@ BoUpSLP::getEntryCost(const TreeEntry *E, ArrayRef<Value *> VectorizedVals,
   }
   case Instruction::Call: {
     auto GetScalarCost = [&](unsigned Idx) {
+      // A copyable lane has no scalar call of its own; its real cost is
+      // accounted for wherever it is otherwise computed.
+      if (isa<PoisonValue>(UniqueValues[Idx]) ||
+          E->isCopyableElement(UniqueValues[Idx]))
+        return InstructionCost(TTI::TCC_Free);
       auto *CI = cast<CallInst>(UniqueValues[Idx]);
       Intrinsic::ID ID = getVectorIntrinsicIDForCall(CI, TLI);
       if (ID != Intrinsic::not_intrinsic) {
@@ -27317,9 +27379,12 @@ bool BoUpSLP::collectValuesToDemote(
     auto CompChecker = [&](unsigned BitWidth, unsigned OrigBitWidth) {
       assert(BitWidth <= OrigBitWidth && "Unexpected bitwidths!");
       return all_of(E.Scalars, [&](Value *V) {
-        auto *I = cast<Instruction>(V);
         if (ID == Intrinsic::umin || ID == Intrinsic::umax) {
           APInt Mask = APInt::getBitsSetFrom(OrigBitWidth, BitWidth);
+          // A copyable V stands for umax/umin(V, identity), which equals V.
+          if (E.isCopyableElement(V))
+            return MaskedValueIsZero(V, Mask, SimplifyQuery(*DL));
+          auto *I = cast<Instruction>(V);
           return MaskedValueIsZero(I->getOperand(0), Mask,
                                    SimplifyQuery(*DL)) &&
                  MaskedValueIsZero(I->getOperand(1), Mask, SimplifyQuery(*DL));
@@ -27328,19 +27393,18 @@ bool BoUpSLP::collectValuesToDemote(
                "Expected min/max intrinsics only.");
         unsigned SignBits = OrigBitWidth - BitWidth;
         APInt Mask = APInt::getBitsSetFrom(OrigBitWidth, BitWidth - 1);
-        unsigned Op0SignBits =
-            ComputeNumSignBits(I->getOperand(0), *DL, AC, nullptr, DT);
-        unsigned Op1SignBits =
-            ComputeNumSignBits(I->getOperand(1), *DL, AC, nullptr, DT);
-        return SignBits <= Op0SignBits &&
-               ((SignBits != Op0SignBits &&
-                 !isKnownNonNegative(I->getOperand(0), SimplifyQuery(*DL))) ||
-                MaskedValueIsZero(I->getOperand(0), Mask,
-                                  SimplifyQuery(*DL))) &&
-               SignBits <= Op1SignBits &&
-               ((SignBits != Op1SignBits &&
-                 !isKnownNonNegative(I->getOperand(1), SimplifyQuery(*DL))) ||
-                MaskedValueIsZero(I->getOperand(1), Mask, SimplifyQuery(*DL)));
+        auto CheckOp = [&](Value *Op) {
+          unsigned OpSignBits = ComputeNumSignBits(Op, *DL, AC, nullptr, DT);
+          return SignBits <= OpSignBits &&
+                 ((SignBits != OpSignBits &&
+                   !isKnownNonNegative(Op, SimplifyQuery(*DL))) ||
+                  MaskedValueIsZero(Op, Mask, SimplifyQuery(*DL)));
+        };
+        // A copyable V stands for smax/smin(V, identity), which equals V.
+        if (E.isCopyableElement(V))
+          return CheckOp(V);
+        auto *I = cast<Instruction>(V);
+        return CheckOp(I->getOperand(0)) && CheckOp(I->getOperand(1));
       });
     };
     auto AbsChecker = [&](unsigned BitWidth, unsigned OrigBitWidth) {
diff --git a/llvm/test/Transforms/SLPVectorizer/X86/debug-info-salvage.ll b/llvm/test/Transforms/SLPVectorizer/X86/debug-info-salvage.ll
index 4a36ddf06fdb3..ae721cb84750f 100644
--- a/llvm/test/Transforms/SLPVectorizer/X86/debug-info-salvage.ll
+++ b/llvm/test/Transforms/SLPVectorizer/X86/debug-info-salvage.ll
@@ -6,33 +6,28 @@ define void @test(i8 %a, i8 %b, ptr %p) {
 ; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]], ptr [[P:%.*]]) #[[ATTR0:[0-9]+]] {
 ; CHECK-NEXT:  [[ENTRY:.*:]]
 ; CHECK-NEXT:    [[ARRAYIDX51_1_I:%.*]] = getelementptr i8, ptr [[P]], i64 4
-; CHECK-NEXT:    [[TMP0:%.*]] = insertelement <2 x i8> poison, i8 [[B]], i64 0
-; CHECK-NEXT:    [[TMP1:%.*]] = insertelement <2 x i8> [[TMP0]], i8 [[A]], i64 1
-; CHECK-NEXT:    [[TMP2:%.*]] = zext <2 x i8> [[TMP1]] to <2 x i16>
+; CHECK-NEXT:    [[RETVAL_SROA_3_0_INSERT_EXT_I_I:%.*]] = zext i8 [[A]] to i32
+; CHECK-NEXT:    [[RETVAL_SROA_2_0_INSERT_EXT_I_I:%.*]] = zext i8 [[B]] to i32
 ; CHECK-NEXT:    br label %[[COND_END_I:.*]]
 ; CHECK:       [[COND_END_I]]:
-; CHECK-NEXT:    [[TMP3:%.*]] = extractelement <2 x i16> [[TMP2]], i64 0
-; CHECK-NEXT:    [[TMP4:%.*]] = zext i16 [[TMP3]] to i32
-; CHECK-NEXT:    [[ADD46_I30:%.*]] = or i32 0, [[TMP4]]
-; CHECK-NEXT:    [[TMP5:%.*]] = or <2 x i16> zeroinitializer, [[TMP2]]
-; CHECK-NEXT:      #dbg_value(!DIArgList(i32 0, i8 [[A]]), [[META3:![0-9]+]], !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_LLVM_convert, 8, DW_ATE_unsigned, DW_OP_LLVM_convert, 32, DW_ATE_unsigned, DW_OP_or, DW_OP_stack_value), [[META7:![0-9]+]])
-; CHECK-NEXT:    [[TMP6:%.*]] = tail call i32 @llvm.umin.i32(i32 [[ADD46_I30]], i32 0)
-; CHECK-NEXT:    [[TMP7:%.*]] = insertelement <2 x i32> <i32 0, i32 poison>, i32 [[TMP6]], i64 1
-; CHECK-NEXT:    [[TMP8:%.*]] = extractelement <2 x i16> [[TMP2]], i64 1
-; CHECK-NEXT:    [[TMP9:%.*]] = zext i16 [[TMP8]] to i32
-; CHECK-NEXT:    [[ADD49_1_I:%.*]] = or i32 0, [[TMP9]]
-; CHECK-NEXT:    [[TMP10:%.*]] = icmp slt <2 x i16> [[TMP5]], zeroinitializer
-; CHECK-NEXT:    [[TMP11:%.*]] = shufflevector <2 x i1> <i1 poison, i1 false>, <2 x i1> [[TMP10]], <2 x i32> <i32 3, i32 1>
-; CHECK-NEXT:    [[TMP12:%.*]] = select <2 x i1> [[TMP11]], <2 x i32> zeroinitializer, <2 x i32> [[TMP7]]
-; CHECK-NEXT:    [[TMP13:%.*]] = shl <2 x i32> [[TMP12]], <i32 16, i32 0>
-; CHECK-NEXT:    [[TMP14:%.*]] = extractelement <2 x i32> [[TMP13]], i64 0
-; CHECK-NEXT:    [[OP_RDX:%.*]] = or i32 0, [[TMP14]]
-; CHECK-NEXT:    [[TMP15:%.*]] = extractelement <2 x i32> [[TMP13]], i64 1
-; CHECK-NEXT:    [[OP_RDX1:%.*]] = or i32 [[OP_RDX]], [[TMP15]]
+; CHECK-NEXT:    [[ADD46_I30:%.*]] = or i32 0, [[RETVAL_SROA_2_0_INSERT_EXT_I_I]]
+; CHECK-NEXT:    [[ADD49_I:%.*]] = or i32 0, [[RETVAL_SROA_3_0_INSERT_EXT_I_I]]
+; CHECK-NEXT:      #dbg_value(i32 [[ADD49_I]], [[META3:![0-9]+]], !DIExpression(), [[META7:![0-9]+]])
+; CHECK-NEXT:    [[TMP0:%.*]] = tail call i32 @llvm.umin.i32(i32 [[ADD46_I30]], i32 0)
+; CHECK-NEXT:    [[CMP_I14_I_I_I:%.*]] = icmp slt i32 [[ADD49_I]], 0
+; CHECK-NEXT:    [[BLOCK_COLOR_SROA_7_0_INSERT_EXT_I:%.*]] = select i1 [[CMP_I14_I_I_I]], i32 0, i32 0
+; CHECK-NEXT:    [[BLOCK_COLOR_SROA_7_0_INSERT_SHIFT_I:%.*]] = shl i32 [[BLOCK_COLOR_SROA_7_0_INSERT_EXT_I]], 16
+; CHECK-NEXT:    [[BLOCK_COLOR_SROA_5_0_INSERT_EXT_I:%.*]] = select i1 false, i32 0, i32 [[TMP0]]
+; CHECK-NEXT:    [[BLOCK_COLOR_SROA_5_0_INSERT_SHIFT_I:%.*]] = shl i32 [[BLOCK_COLOR_SROA_5_0_INSERT_EXT_I]], 0
+; CHECK-NEXT:    [[OP_RDX:%.*]] = or i32 0, [[BLOCK_COLOR_SROA_7_0_INSERT_SHIFT_I]]
+; CHECK-NEXT:    [[OP_RDX1:%.*]] = or i32 [[OP_RDX]], [[BLOCK_COLOR_SROA_5_0_INSERT_SHIFT_I]]
 ; CHECK-NEXT:    store i32 [[OP_RDX1]], ptr null, align 4
-; CHECK-NEXT:    [[TMP16:%.*]] = tail call i32 @llvm.umin.i32(i32 [[ADD49_1_I]], i32 0)
-; CHECK-NEXT:    [[TMP17:%.*]] = shufflevector <2 x i1> <i1 false, i1 poison>, <2 x i1> [[TMP10]], <2 x i32> <i32 0, i32 2>
-; CHECK-NEXT:    [[TMP18:%.*]] = insertelement <2 x i32> <i32 poison, i32 0>, i32 [[TMP16]], i64 0
+; CHECK-NEXT:    [[ADD46_1_I:%.*]] = or i32 0, [[RETVAL_SROA_2_0_INSERT_EXT_I_I]]
+; CHECK-NEXT:    [[ADD49_1_I:%.*]] = or i32 0, [[RETVAL_SROA_3_0_INSERT_EXT_I_I]]
+; CHECK-NEXT:    [[CMP_I11_I_I_1_I:%.*]] = icmp slt i32 [[ADD46_1_I]], 0
+; CHECK-NEXT:    [[TMP1:%.*]] = insertelement <2 x i32> <i32 poison, i32 -1>, i32 [[ADD49_1_I]], i64 0
+; CHECK-NEXT:    [[TMP18:%.*]] = call <2 x i32> @llvm.umin.v2i32(<2 x i32> zeroinitializer, <2 x i32> [[TMP1]])
+; CHECK-NEXT:    [[TMP17:%.*]] = insertelement <2 x i1> <i1 false, i1 poison>, i1 [[CMP_I11_I_I_1_I]], i64 1
 ; CHECK-NEXT:    [[TMP19:%.*]] = select <2 x i1> [[TMP17]], <2 x i32> zeroinitializer, <2 x i32> [[TMP18]]
 ; CHECK-NEXT:    [[TMP20:%.*]] = shl <2 x i32> [[TMP19]], <i32 16, i32 0>
 ; CHECK-NEXT:    [[TMP21:%.*]] = extractelement <2 x i32> [[TMP20]], i64 0
diff --git a/llvm/test/Transforms/SLPVectorizer/X86/minmax-main-opcode-copyables-cost.ll b/llvm/test/Transforms/SLPVectorizer/X86/minmax-main-opcode-copyables-cost.ll
index 0cc58fa07dbbb..c66e4e48f0a3f 100644
--- a/llvm/test/Transforms/SLPVectorizer/X86/minmax-main-opcode-copyables-cost.ll
+++ b/llvm/test/Transforms/SLPVectorizer/X86/minmax-main-opcode-copyables-cost.ll
@@ -5,16 +5,12 @@ define void @test_umax(ptr %dst, i32 %x0, i32 %x1, i32 %x2, i32 %x3) {
 ; CHECK-LABEL: define void @test_umax(
 ; CHECK-SAME: ptr [[DST:%.*]], i32 [[X0:%.*]], i32 [[X1:%.*]], i32 [[X2:%.*]], i32 [[X3:%.*]]) #[[ATTR0:[0-9]+]] {
 ; CHECK-NEXT:  [[ENTRY:.*:]]
-; CHECK-NEXT:    [[UMAX0:%.*]] = call i32 @llvm.umax.i32(i32 [[X0]], i32 1)
-; CHECK-NEXT:    [[UMAX1:%.*]] = call i32 @llvm.umax.i32(i32 [[X1]], i32 2)
-; CHECK-NEXT:    [[UMAX2:%.*]] = call i32 @llvm.umax.i32(i32 [[X2]], i32 3)
-; CHECK-NEXT:    store i32 [[UMAX0]], ptr [[DST]], align 4
-; CHECK-NEXT:    [[P1:%.*]] = getelementptr i32, ptr [[DST]], i32 1
-; CHECK-NEXT:    store i32 [[UMAX1]], ptr [[P1]], align 4
-; CHECK-NEXT:    [[P2:%.*]] = getelementptr i32, ptr [[DST]], i32 2
-; CHECK-NEXT:    store i32 [[UMAX2]], ptr [[P2]], align 4
-; CHECK-NEXT:    [[P3:%.*]] = getelementptr i32, ptr [[DST]], i32 3
-; CHECK-NEXT:    store i32 [[X3]], ptr [[P3]], align 4
+; CHECK-NEXT:    [[TMP0:%.*]] = insertelement <4 x i32> poison, i32 [[X0]], i64 0
+; CHECK-NEXT:    [[TMP1:%.*]] = insertelement <4 x i32> [[TMP0]], i32 [[X1]], i64 1
+; CHECK-NEXT:    [[TMP2:%.*]] = insertelement <4 x i32> [[TMP1]], i32 [[X2]], i64 2
+; CHECK-NEXT:    [[TMP3:%.*]] = insertelement <4 x i32> [[TMP2]], i32 [[X3]], i64 3
+; CHECK-NEXT:    [[TMP4:%.*]] = call <4 x i32> @llvm.umax.v4i32(<4 x i32> [[TMP3]], <4 x i32> <i32 1, i32 2, i32 3, i32 0>)
+; CHECK-NEXT:    store <4 x i32> [[TMP4]], ptr [[DST]], align 4
 ; CHECK-NEXT:    ret void
 ;
 entry:
diff --git a/llvm/test/Transforms/SLPVectorizer/X86/minmax-main-opcode-copyables.ll b/llvm/test/Transforms/SLPVectorizer/X86/minmax-main-opcode-copyables.ll
index 43c44cd1df776..9c75e114ee9f4 100644
--- a/llvm/test/Transforms/SLPVectorizer/X86/minmax-main-opcode-copyables.ll
+++ b/llvm/test/Transforms/SLPVectorizer/X86/minmax-main-opcode-copyables.ll
@@ -6,14 +6,12 @@ define void @test_umax(ptr %dst, i32 %x0, i32 %x1, i32 %x2, i32 %x3) {
 ; CHECK-LABEL: define void @test_umax(
 ; CHECK-SAME: ptr [[DST:%.*]], i32 [[X0:%.*]], i32 [[X1:%.*]], i32 [[X2:%.*]], i32 [[X3:%.*]]) {
 ; CHECK-NEXT:  [[ENTRY:.*:]]
-; CHECK-NEXT:    [[TMP0:%.*]] = insertelement <2 x i32> poison, i32 [[X0]], i64 0
-; CHECK-NEXT:    [[TMP1:%.*]] = insertelement <2 x i32> [[TMP0]], i32 [[X1]], i64 1
-; CHECK-NEXT:    [[TMP2:%.*]] = call <2 x i32> @llvm.umax.v2i32(<2 x i32> [[TMP1]], <2 x i32> <i32 1, i32 2>)
-; CHECK-NEXT:    store <2 x i32> [[TMP2]], ptr [[DST]], align 4
-; CHECK-NEXT:    [[P2:%.*]] = getelementptr i32, ptr [[DST]], i32 2
-; CHECK-NEXT:    store i32 [[X2]], ptr [[P2]], align 4
-; CHECK-NEXT:    [[P3:%.*]] = getelementptr i32, ptr [[DST]], i32 3
-; CHECK-NEXT:    store i32 [[X3]], ptr [[P3]], align 4
+; CHECK-NEXT:    [[TMP0:%.*]] = insertelement <4 x i32> poison, i32 [[X0]], i64 0
+; CHECK-NEXT:    [[TMP1:%.*]] = insertelement <4 x i32> [[TMP0]], i32 [[X1]], i64 1
+; CHECK-NEXT:    [[TMP2:%.*]] = insertelement <4 x i32> [[TMP1]], i32 [[X2]], i64 2
+; CHECK-NEXT:    [[TMP3:%.*]] = insertelement <4 x i32> [[TMP2]], i32 [[X3]], i64 3
+; CHECK-NEXT:    [[TMP4:%.*]] = call <4 x i32> @llvm.umax.v4i32(<4 x i32> [[TMP3]], <4 x i32> <i32 1, i32 2, i32 0, i32 0>)
+; CHECK-NEXT:    store <4 x i32> [[TMP4]], ptr [[DST]], align 4
 ; CHECK-NEXT:    ret void
 ;
 entry:
@@ -35,14 +33,12 @@ define void @test_umin(ptr %dst, i32 %x0, i32 %x1, i32 %x2, i32 %x3) {
 ; CHECK-LABEL: define void @test_umin(
 ; CHECK-SAME: ptr [[DST:%.*]], i32 [[X0:%.*]], i32 [[X1:%.*]], i32 [[X2:%.*]], i32 [[X3:%.*]]) {
 ; CHECK-NEXT:  [[ENTRY:.*:]]
-; CHECK-NEXT:    [[TMP0:%.*]] = insertelement <2 x i32> poison, i32 [[X0]], i64 0
-; CHECK-NEXT:    [[TMP1:%.*]] = insertelement <2 x i32> [[TMP0]], i32 [[X1]], i64 1
-; CHECK-NEXT:    [[TMP2:%.*]] = call <2 x i32> @llvm.umin.v2i32(<2 x i32> [[TMP1]], <2 x i32> <i32 1, i32 2>)
-; CHECK-NEXT:    store <2 x i32> [[TMP2]], ptr [[DST]], align 4
-; CHECK-NEXT:    [[P2:%.*]] = getelementptr i32, ptr [[DST]], i32 2
-; CHECK-NEXT:    store i32 [[X2]], ptr [[P2]], align 4
-; CHECK-NEXT:    [[P3:%.*]] = getelementptr i32, ptr [[DST]], i32 3
-; CHECK-NEXT:    store i32 [[X3]], ptr [[P3]], align 4
+; CHECK-NEXT:    [[TMP0:%.*]] = insertelement <4 x i32> poison, i32 [[X0]], i64 0
+; CHECK-NEXT:    [[TMP1:%.*]] = insertelement <4 x i32> [[TMP0]], i32 [[X1]], i64 1
+; CHECK-NEXT:    [[TMP2:%.*]] = insertelement <4 x i32> [[TMP1]], i32 [[X2]], i64 2
+; CHECK-NEXT:    [[TMP3:%.*]] = insertelement <4 x i32> [[TMP2]], i32 [[X3]], i64 3
+; CHECK-NEXT:    [[TMP4:%.*]] = call <4 x i32> @llvm.umin.v4i32(<4 x i32> [[TMP3]], <4 x i32> <i32 1, i32 2, i32 -1, i32 -1>)
+; CHECK-NEXT:    store <4 x i32> [[TMP4]], ptr [[DST]], align 4
 ; CHECK-NEXT:    ret void
 ;
 entry:
@@ -64,14 +60,12 @@ define void @test_smax(ptr %dst, i32 %x0, i32 %x1, i32 %x2, i32 %x3) {
 ; CHECK-LABEL: define void @test_smax(
 ; CHECK-SAME: ptr [[DST:%.*]], i32 [[X0:%.*]], i32 [[X1:%.*]], i32 [[X2:%.*]], i32 [[X3:%.*]]) {
 ; CHECK-NEXT:  [[ENTRY:.*:]]
-; CHECK-NEXT:    [[TMP0:%.*]] = insertelement <2 x i32> poison, i32 [[X0]], i64 0
-; CHECK-NEXT:    [[TMP1:%.*]] = insertelement <2 x i32> [[TMP0]], i32 [[X1]], i64 1
-; CHECK-NEXT:    [[TMP2:%.*]] = call <2 x i32> @llvm.smax.v2i32(<2 x i32> [[TMP1]], <2 x i32> <i32 1, i32 2>)
-; CHECK-NEXT:    store <2 x i32> [[TMP2]], ptr [[DST]], align 4
-; CHECK-NEXT:    [[P2:%.*]] = getelementptr i32, ptr [[DST]], i32 2
-; CHECK-NEXT:    store i32 [[X2]], ptr [[P2]], align 4
-; CHECK-NEXT:    [[P3:%.*]] = getelementptr i32, ptr [[DST]], i32 3
-; CHECK-NEXT:    store i32 [[X3]], ptr [[P3]], align 4
+; CHECK-NEXT:    [[TMP0:%.*]] = insertelement <4 x i32> poison, i32 [[X0]], i64 0
+; CHECK-NEXT:    [[TMP1:%.*]] = insertelement <4 x i32> [[TMP0]], i32 [[X1]], i64 1
+; CHECK-NEXT:    [[TMP2:%.*]] = insertelement <4 x i32> [[TMP1]], i32 [[X2]], i64 2
+; CHECK-NEXT:    [[TMP3:%.*]] = insertelement <4 x i32> [[TMP2]], i32 [[X3]], i64 3
+; CHECK-NEXT:    [[TMP4:%.*]] = call <4 x i32> @llvm.smax.v4i32(<4 x i32> [[TMP3]], <4 x i32> <i32 1, i32 2, i32 -2147483648, i32 -2147483648>)
+; CHECK-NEXT:    store <4 x i32> [[TMP4]], ptr [[DST]], align 4
 ; CHECK-NEXT:    ret void
 ;
 entry:
@@ -93,14 +87,12 @@ define void @test_smin(ptr %dst, i32 %x0, i32 %x1, i32 %x2, i32 %x3) {
 ; CHECK-LABEL: define void @test_smin(
 ; CHECK-SAME: ptr [[DST:%.*]], i32 [[X0:%.*]], i32 [[X1:%.*]], i32 [[X2:%.*]], i32 [[X3:%.*]]) {
 ; CHECK-NEXT:  [[ENTRY:.*:]]
-; CHECK-NEXT:    [[TMP0:%.*]] = insertelement <2 x i32> poison, i32 [[X0]], i64 0
-; CHECK-NEXT:    [[TMP1:%.*]] = insertelement <2 x i32> [[TMP0]], i32 [[X1]], i64 1
-; CHECK-NEXT:    [[TMP2:%.*]] = call <2 x i32> @llvm.smin.v2i32(<2 x i32> [[TMP1]], <2 x i32> <i32 1, i32 2>)
-; CHECK-NEXT:    store <2 x i32> [[TMP2]], ptr [[DST]], align 4
-; CHECK-NEXT:    [[P2:%.*]] = getelementptr i32, ptr [[DST]], i32 2
-; CHECK-NEXT:    store i32 [[X2]], ptr [[P2]], align 4
-; CHECK-NEXT:    [[P3:%.*]] = getelementptr i32, ptr [[DST]], i32 3
-; CHECK-NEXT:    store i32 [[X3]], ptr [[P3]], align 4
+; CHECK-NEXT:    [[TMP0:%.*]] = insertelement <4 x i32> poison, i32 [[X0]], i64 0
+; CHECK-NEXT:    [[TMP1:%.*]] = insertelement <4 x i32> [[TMP0]], i32 [[X1]], i64 1
+; CHECK-NEXT:    [[TMP2:%.*]] = insertelement <4 x i32> [[TMP1]], i32 [[X2]], i64 2
+; CHECK-NEXT:    [[TMP3:%.*]] = insertelement <4 x i32> [[TMP2]], i32 [[X3]], i64 3
+; CHECK-NEXT:    [[TMP4:%.*]] = call <4 x i32> @llvm.smin.v4i32(<4 x i32> [[TMP3]], <4 x i32> <i32 1, i32 2, i32 2147483647, i32 2147483647>)
+; CHECK-NEXT:    store <4 x i32> [[TMP4]], ptr [[DST]], align 4
 ; CHECK-NEXT:    ret void
 ;
 entry:
@@ -126,13 +118,12 @@ define void @test_minbitwidth_trunc(ptr %dst, ptr %src) {
 ; CHECK-NEXT:    [[TMP1:%.*]] = load i32, ptr [[SRC]], align 4
 ; CHECK-NEXT:    [[TMP2:%.*]] = load i32, ptr [[SRC]], align 4
 ; CHECK-NEXT:    [[TMP3:%.*]] = load i32, ptr [[SRC]], align 4
-; CHECK-NEXT:    [[TMP4:%.*]] = insertelement <2 x i32> poison, i32 [[TMP0]], i64 0
-; CHECK-NEXT:    [[TMP8:%.*]] = insertelement <2 x i32> [[TMP4]], i32 [[TMP1]], i64 1
-; CHECK-NEXT:    [[TMP10:%.*]] = call <2 x i32> @llvm.smax.v2i32(<2 x i32> [[TMP8]], <2 x i32> <i32 100, i32 200>)
-; CHECK-NEXT:    [[TMP5:%.*]] = shufflevector <2 x i32> [[TMP10]], <2 x i32> poison, <4 x i32> <i32 0, i32 1, i32 poison, i32 poison>
+; CHECK-NEXT:    [[TMP4:%.*]] = insertelement <4 x i32> poison, i32 [[TMP0]], i64 0
+; CHECK-NEXT:    [[TMP5:%.*]] = insertelement <4 x i32> [[TMP4]], i32 [[TMP1]], i64 1
 ; CHECK-NEXT:    [[TMP11:%.*]] = insertelement <4 x i32> [[TMP5]], i32 [[TMP2]], i64 2
 ; CHECK-NEXT:    [[TMP7:%.*]] = insertelement <4 x i32> [[TMP11]], i32 [[TMP3]], i64 3
-; CHECK-NEXT:    [[TMP9:%.*]] = trunc <4 x i32> [[TMP7]] to <4 x i16>
+; CHECK-NEXT:    [[TMP8:%.*]] = call <4 x i32> @llvm.smax.v4i32(<4 x i32> [[TMP7]], <4 x i32> <i32 100, i32 200, i32 -2147483648, i32 -2147483648>)
+; CHECK-NEXT:    [[TMP9:%.*]] = trunc <4 x i32> [[TMP8]] to <4 x i16>
 ; CHECK-NEXT:    store <4 x i16> [[TMP9]], ptr [[DST]], align 2
 ; CHECK-NEXT:    ret void
 ;
diff --git a/llvm/test/Transforms/SLPVectorizer/X86/split-node-num-operands.ll b/llvm/test/Transforms/SLPVectorizer/X86/split-node-num-operands.ll
index 604063fd15230..ae7da95dd918d 100644
--- a/llvm/test/Transforms/SLPVectorizer/X86/split-node-num-operands.ll
+++ b/llvm/test/Transforms/SLPVectorizer/X86/split-node-num-operands.ll
@@ -15,46 +15,49 @@ define i64 @Foo(ptr align 8 dereferenceable(344) %0, i64 %1) {
 ; CHECK-NEXT:    [[TMP11:%.*]] = insertelement <2 x i64> [[TMP10]], i64 [[TMP9]], i64 1
 ; CHECK-NEXT:    [[TMP12:%.*]] = insertelement <2 x i64> poison, i64 [[TMP7]], i64 0
 ; CHECK-NEXT:    [[TMP13:%.*]] = insertelement <2 x i64> [[TMP12]], i64 [[TMP8]], i64 1
-; CHECK-NEXT:    [[TMP14:%.*]] = insertelement <2 x i64> poison, i64 0, i64 0
-; CHECK-NEXT:    [[TMP15:%.*]] = insertelement <2 x i64> <i64 0, i64 poison>, i64 [[TMP1]], i64 1
-; CHECK-NEXT:    br label %[[BB16:.*]]
-; CHECK:       [[BB16]]:
-; CHECK-NEXT:    [[TMP17:%.*]] = phi <2 x i64> [ [[TMP11]], [[TMP2:%.*]] ], [ zeroinitializer, %[[TMP25:.*]] ]
-; CHECK-NEXT:    [[TMP18:%.*]] = phi <2 x i64> [ [[TMP13]], [[TMP2]] ], [ [[TMP29:%.*]], %[[TMP25]] ]
-; CHECK-NEXT:    switch i32 0, label %[[BB19:.*]] [
-; CHECK-NEXT:      i32 0, label %[[TMP25]]
+; CHECK-NEXT:    [[TMP14:%.*]] = insertelement <2 x i64> <i64 0, i64 poison>, i64 [[TMP1]], i64 1
+; CHECK-NEXT:    br label %[[DOTCONT174:.*]]
+; CHECK:       [[DOTCONT174]]:
+; CHECK-NEXT:    [[TMP16:%.*]] = phi <2 x i64> [ [[TMP11]], [[TMP2:%.*]] ], [ zeroinitializer, %[[TMP26:.*]] ]
+; CHECK-NEXT:    [[TMP17:%.*]] = phi <2 x i64> [ [[TMP13]], [[TMP2]] ], [ [[TMP30:%.*]], %[[TMP26]] ]
+; CHECK-NEXT:    switch i32 0, label %[[_CONT174:.*]] [
+; CHECK-NEXT:      i32 0, label %[[TMP26]]
 ; CHECK-NEXT:    ]
-; CHECK:       [[BB19]]:
-; CHECK-NEXT:    [[TMP20:%.*]] = shufflevector <2 x i64> [[TMP18]], <2 x i64> poison, <4 x i32> <i32 1, i32 poison, i32 poison, i32 poison>
-; CHECK-NEXT:    [[TMP21:%.*]] = insertelement <4 x i64> [[TMP20]], i64 0, i64 1
-; CHECK-NEXT:    [[TMP22:%.*]] = insertelement <4 x i64> [[TMP21]], i64 0, i64 2
-; CHECK-NEXT:    [[TMP23:%.*]] = shufflevector <4 x i64> [[TMP22]], <4 x i64> poison, <4 x i32> <i32 0, i32 1, i32 2, i32 2>
-; CHECK-NEXT:    [[TMP24:%.*]] = shufflevector <2 x i64> [[TMP14]], <2 x i64> [[TMP18]], <2 x i32> <i32 0, i32 2>
-; CHECK-NEXT:    br label %[[TMP25]]
-; CHECK:       [[TMP25]]:
-; CHECK-NEXT:    [[TMP26:%.*]] = phi <2 x i64> [ [[TMP17]], %[[BB19]] ], [ zeroinitializer, %[[BB16]] ]
-; CHECK-NEXT:    [[TMP27:%.*]] = phi <4 x i64> [ [[TMP23]], %[[BB19]] ], [ zeroinitializer, %[[BB16]] ]
-; CHECK-NEXT:    [[TMP28:%.*]] = phi <2 x i64> [ [[TMP24]], %[[BB19]] ], [ [[TMP15]], %[[BB16]] ]
-; CHECK-NEXT:    [[TMP29]] = shufflevector <2 x i64> [[TMP18]], <2 x i64> <i64 0, i64 poison>, <2 x i32> <i32 2, i32 1>
-; CHECK-NEXT:    br i1 false, label %[[DOTLOOPEXIT206:.*]], label %[[BB16]]
+; CHECK:       [[_CONT174]]:
+; CHECK-NEXT:    [[TMP19:%.*]] = shufflevector <2 x i64> <i64 0, i64 poison>, <2 x i64> [[TMP17]], <2 x i32> <i32 0, i32 2>
+; CHECK-NEXT:    [[TMP20:%.*]] = call <2 x i64> @llvm.umin.v2i64(<2 x i64> <i64 0, i64 -1>, <2 x i64> [[TMP19]])
+; CHECK-NEXT:    [[TMP21:%.*]] = shufflevector <2 x i64> [[TMP17]], <2 x i64> poison, <4 x i32> <i32 1, i32 poison, i32 poison, i32 poison>
+; CHECK-NEXT:    [[TMP22:%.*]] = shufflevector <2 x i64> [[TMP20]], <2 x i64> poison, <4 x i32> <i32 0, i32 1, i32 poison, i32 poison>
+; CHECK-NEXT:    [[TMP23:%.*]] = shufflevector <4 x i64> [[TMP21]], <4 x i64> [[TMP22]], <4 x i32> <i32 0, i32 4, i32 poison, i32 poison>
+; CHECK-NEXT:    [[TMP24:%.*]] = insertelement <4 x i64> [[TMP23]], i64 0, i64 2
+; CHECK-NEXT:    [[TMP25:%.*]] = shufflevector <4 x i64> [[TMP24]], <4 x i64> poison, <4 x i32> <i32 0, i32 1, i32 2, i32 2>
+; CHECK-NEXT:    br label %[[TMP26]]
+; CHECK:       [[TMP26]]:
+; CHECK-NEXT:    [[TMP27:%.*]] = phi <2 x i64> [ [[TMP16]], %[[_CONT174]] ], [ zeroinitializer, %[[DOTCONT174]] ]
+; CHECK-NEXT:    [[TMP28:%.*]] = phi <4 x i64> [ [[TMP25]], %[[_CONT174]] ], [ zeroinitializer, %[[DOTCONT174]] ]
+; CHECK-NEXT:    [[TMP29:%.*]] = phi <2 x i64> [ [[TMP20]], %[[_CONT174]] ], [ [[TMP14]], %[[DOTCONT174]] ]
+; CHECK-NEXT:    [[TMP30]] = shufflevector <2 x i64> [[TMP17]], <2 x i64> <i64 0, i64 poison>, <2 x i32> <i32 2, i32 1>
+; CHECK-NEXT:    br i1 false, label %[[DOTLOOPEXIT206:.*]], label %[[DOTCONT174]]
 ; CHECK:       [[_LOOPEXIT206:.*:]]
-; CHECK-NEXT:    switch i32 0, label %[[BB32:.*]] [
-; CHECK-NEXT:      i32 0, [[DOTCONT174:label %.*]]
-; CHECK-NEXT:      i32 1, label %[[BB30:.*]]
+; CHECK-NEXT:    switch i32 0, label %[[BB33:.*]] [
+; CHECK-NEXT:      i32 0, [[DOTCONT175:label %.*]]
+; CHECK-NEXT:      i32 1, label %[[BB31:.*]]
 ; CHECK-NEXT:    ]
-; CHECK:       [[BB30]]:
-; CHECK-NEXT:    [[TMP31:%.*]] = shufflevector <4 x i64> [[TMP27]], <4 x i64> <i64 0, i64 0, i64 poison, i64 0>, <4 x i32> <i32 4, i32 5, i32 2, i32 7>
-; CHECK-NEXT:    br [[DOTCONT174]]
-; CHECK:       [[BB32]]:
-; CHECK-NEXT:    [[TMP33:%.*]] = insertelement <4 x i64> [[TMP27]], i64 0, i64 1
-; CHECK-NEXT:    [[TMP34:%.*]] = insertelement <4 x i64> [[TMP33]], i64 0, i64 2
-; CHECK-NEXT:    [[TMP35:%.*]] = shufflevector <4 x i64> [[TMP34]], <4 x i64> poison, <4 x i32> <i32 0, i32 1, i32 2, i32 2>
-; CHECK-NEXT:    [[TMP36:%.*]] = insertelement <2 x i64> [[TMP28]], i64 0, i64 0
-; CHECK-NEXT:    br [[DOTCONT174]]
-; CHECK:       [[_CONT174:.*:]]
-; CHECK-NEXT:    [[TMP37:%.*]] = phi <2 x i64> [ [[TMP26]], %[[BB32]] ], [ zeroinitializer, %[[BB30]] ], [ [[TMP26]], %[[DOTLOOPEXIT206]] ]
-; CHECK-NEXT:    [[TMP38:%.*]] = phi <4 x i64> [ [[TMP35]], %[[BB32]] ], [ [[TMP31]], %[[BB30]] ], [ [[TMP27]], %[[DOTLOOPEXIT206]] ]
-; CHECK-NEXT:    [[TMP39:%.*]] = phi <2 x i64> [ [[TMP36]], %[[BB32]] ], [ zeroinitializer, %[[BB30]] ], [ [[TMP28]], %[[DOTLOOPEXIT206]] ]
+; CHECK:       [[BB31]]:
+; CHECK-NEXT:    [[TMP32:%.*]] = shufflevector <4 x i64> [[TMP28]], <4 x i64> <i64 0, i64 0, i64 poison, i64 0>, <4 x i32> <i32 4, i32 5, i32 2, i32 7>
+; CHECK-NEXT:    br [[DOTCONT175]]
+; CHECK:       [[BB33]]:
+; CHECK-NEXT:    [[TMP34:%.*]] = shufflevector <2 x i64> [[TMP29]], <2 x i64> <i64 0, i64 poison>, <2 x i32> <i32 2, i32 1>
+; CHECK-NEXT:    [[TMP35:%.*]] = call <2 x i64> @llvm.umin.v2i64(<2 x i64> <i64 0, i64 -1>, <2 x i64> [[TMP34]])
+; CHECK-NEXT:    [[TMP36:%.*]] = shufflevector <2 x i64> [[TMP35]], <2 x i64> poison, <4 x i32> <i32 0, i32 1, i32 poison, i32 poison>
+; CHECK-NEXT:    [[TMP37:%.*]] = shufflevector <4 x i64> [[TMP28]], <4 x i64> [[TMP36]], <4 x i32> <i32 0, i32 4, i32 2, i32 3>
+; CHECK-NEXT:    [[TMP38:%.*]] = insertelement <4 x i64> [[TMP37]], i64 0, i64 2
+; CHECK-NEXT:    [[TMP39:%.*]] = shufflevector <4 x i64> [[TMP38]], <4 x i64> poison, <4 x i32> <i32 0, i32 1, i32 2, i32 2>
+; CHECK-NEXT:    br [[DOTCONT175]]
+; CHECK:       [[_CONT175:.*:]]
+; CHECK-NEXT:    [[TMP40:%.*]] = phi <2 x i64> [ [[TMP27]], %[[BB33]] ], [ zeroinitializer, %[[BB31]] ], [ [[TMP27]], %[[DOTLOOPEXIT206]] ]
+; CHECK-NEXT:    [[TMP41:%.*]] = phi <4 x i64> [ [[TMP39]], %[[BB33]] ], [ [[TMP32]], %[[BB31]] ], [ [[TMP28]], %[[DOTLOOPEXIT206]] ]
+; CHECK-NEXT:    [[TMP42:%.*]] = phi <2 x i64> [ [[TMP35]], %[[BB33]] ], [ zeroinitializer, %[[BB31]] ], [ [[TMP29]], %[[DOTLOOPEXIT206]] ]
 ; CHECK-NEXT:    ret i64 0
 ;
   %3 = getelementptr i8, ptr %0, i64 104
diff --git a/llvm/test/Transforms/SLPVectorizer/splat-buildvector.ll b/llvm/test/Transforms/SLPVectorizer/splat-buildvector.ll
index a3f8f7bfdc2c9..e51e46b55d034 100644
--- a/llvm/test/Transforms/SLPVectorizer/splat-buildvector.ll
+++ b/llvm/test/Transforms/SLPVectorizer/splat-buildvector.ll
@@ -8,9 +8,8 @@ define i8 @foo(i64 %val_i64_57) {
 ; CHECK-LABEL: define i8 @foo(
 ; CHECK-SAME: i64 [[VAL_I64_57:%.*]]) {
 ; CHECK-NEXT:  entry_1:
-; CHECK-NEXT:    [[VAL_I64_58:%.*]] = call i64 @llvm.smax.i64(i64 0, i64 1)
-; CHECK-NEXT:    [[TMP0:%.*]] = insertelement <4 x i64> <i64 0, i64 poison, i64 poison, i64 0>, i64 [[VAL_I64_57]], i64 1
-; CHECK-NEXT:    [[TMP1:%.*]] = insertelement <4 x i64> [[TMP0]], i64 [[VAL_I64_58]], i64 2
+; CHECK-NEXT:    [[TMP0:%.*]] = insertelement <4 x i64> <i64 -9223372036854775808, i64 poison, i64 1, i64 -9223372036854775808>, i64 [[VAL_I64_57]], i64 1
+; CHECK-NEXT:    [[TMP1:%.*]] = call <4 x i64> @llvm.smax.v4i64(<4 x i64> [[TMP0]], <4 x i64> <i64 0, i64 -9223372036854775808, i64 0, i64 0>)
 ; CHECK-NEXT:    [[TMP2:%.*]] = shufflevector <4 x i64> [[TMP1]], <4 x i64> <i64 poison, i64 poison, i64 poison, i64 undef>, <4 x i32> <i32 2, i32 2, i32 2, i32 7>
 ; CHECK-NEXT:    [[TMP3:%.*]] = icmp ule <4 x i64> [[TMP1]], [[TMP2]]
 ; CHECK-NEXT:    [[TMP4:%.*]] = icmp sle <4 x i64> [[TMP1]], [[TMP2]]



More information about the llvm-commits mailing list