[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
Tue Jul 14 06:46:40 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