[llvm] [VPlan] Make simplifyRecipe more like InstCombine (PR #212968)
Luke Lau via llvm-commits
llvm-commits at lists.llvm.org
Mon Aug 3 01:22:16 PDT 2026
https://github.com/lukel97 updated https://github.com/llvm/llvm-project/pull/212968
>From 0d78fb5d33d5447fa0a7d4c69ae1ca3464322237 Mon Sep 17 00:00:00 2001
From: Luke Lau <luke at igalia.com>
Date: Thu, 30 Jul 2026 17:13:43 +0800
Subject: [PATCH 1/2] [VPlan] Make simplifyRecipe more like InstCombine
Most combines in simplifyRecipe RAUW a value, but not all of them erase the old recipe.
Unify them and bring it in line with InstCombine by having it return a VPValue, which simplifyRecipes can then call RAUW with, and automatically erase the old recipe.
Similarly to InstCombine, combines that modify a recipe should return the same recipe.
---
.../Transforms/Vectorize/VPlanTransforms.cpp | 262 ++++++++----------
.../LoopVectorize/VPlan/constant-fold.ll | 11 -
.../epilog-vectorization-reductions.ll | 2 -
3 files changed, 113 insertions(+), 162 deletions(-)
diff --git a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
index 9990fd142df02..6280514152ee5 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
@@ -1119,8 +1119,9 @@ static void removeRedundantExpandSCEVRecipes(VPlan &Plan) {
}
/// Try to simplify logical and bitwise recipes in \p Def.
-static bool simplifyLogicalRecipe(VPSingleDefRecipe *Def, VPBuilder &Builder,
- bool CanCreateNewRecipe) {
+static VPValue *simplifyLogicalRecipe(VPSingleDefRecipe *Def,
+ VPBuilder &Builder,
+ bool CanCreateNewRecipe) {
VPlan *Plan = Def->getParent()->getPlan();
// Simplify (X && Y) | (X && !Y) -> X.
@@ -1130,53 +1131,36 @@ static bool simplifyLogicalRecipe(VPSingleDefRecipe *Def, VPBuilder &Builder,
VPValue *X, *Y, *Z;
if (match(Def,
m_c_BinaryOr(m_LogicalAnd(m_VPValue(X), m_VPValue(Y)),
- m_LogicalAnd(m_Deferred(X), m_Not(m_Deferred(Y)))))) {
- Def->replaceAllUsesWith(X);
- Def->eraseFromParent();
- return true;
- }
+ m_LogicalAnd(m_Deferred(X), m_Not(m_Deferred(Y))))))
+ return X;
// x | AllOnes -> AllOnes
- if (match(Def, m_c_BinaryOr(m_VPValue(X), m_AllOnes()))) {
- Def->replaceAllUsesWith(Plan->getAllOnesValue(Def->getScalarType()));
- return true;
- }
+ if (match(Def, m_c_BinaryOr(m_VPValue(X), m_AllOnes())))
+ return Plan->getAllOnesValue(Def->getScalarType());
// x | 0 -> x
- if (match(Def, m_c_BinaryOr(m_VPValue(X), m_ZeroInt()))) {
- Def->replaceAllUsesWith(X);
- return true;
- }
+ if (match(Def, m_c_BinaryOr(m_VPValue(X), m_ZeroInt())))
+ return X;
// x | !x -> AllOnes
- if (match(Def, m_c_BinaryOr(m_VPValue(X), m_Not(m_Deferred(X))))) {
- Def->replaceAllUsesWith(Plan->getAllOnesValue(Def->getScalarType()));
- return true;
- }
+ if (match(Def, m_c_BinaryOr(m_VPValue(X), m_Not(m_Deferred(X)))))
+ return Plan->getAllOnesValue(Def->getScalarType());
// x & 0 -> 0
- if (match(Def, m_c_BinaryAnd(m_VPValue(X), m_ZeroInt()))) {
- Def->replaceAllUsesWith(Plan->getZero(Def->getScalarType()));
- return true;
- }
+ if (match(Def, m_c_BinaryAnd(m_VPValue(X), m_ZeroInt())))
+ return Plan->getZero(Def->getScalarType());
// x & AllOnes -> x
- if (match(Def, m_c_BinaryAnd(m_VPValue(X), m_AllOnes()))) {
- Def->replaceAllUsesWith(X);
- return true;
- }
+ if (match(Def, m_c_BinaryAnd(m_VPValue(X), m_AllOnes())))
+ return X;
// x && false -> false
- if (match(Def, m_c_LogicalAnd(m_VPValue(X), m_False()))) {
- Def->replaceAllUsesWith(Plan->getFalse());
- return true;
- }
+ if (match(Def, m_c_LogicalAnd(m_VPValue(X), m_False())))
+ return Plan->getFalse();
// x && true -> x
- if (match(Def, m_c_LogicalAnd(m_VPValue(X), m_True()))) {
- Def->replaceAllUsesWith(X);
- return true;
- }
+ if (match(Def, m_c_LogicalAnd(m_VPValue(X), m_True())))
+ return X;
// (x && y) | (x && z) -> x && (y | z)
if (CanCreateNewRecipe &&
@@ -1185,51 +1169,38 @@ static bool simplifyLogicalRecipe(VPSingleDefRecipe *Def, VPBuilder &Builder,
// Simplify only if one of the operands has one use to avoid creating an
// extra recipe.
(!Def->getOperand(0)->hasMoreThanOneUniqueUser() ||
- !Def->getOperand(1)->hasMoreThanOneUniqueUser())) {
- Def->replaceAllUsesWith(
- Builder.createLogicalAnd(X, Builder.createOr(Y, Z)));
- return true;
- }
+ !Def->getOperand(1)->hasMoreThanOneUniqueUser()))
+ return Builder.createLogicalAnd(X, Builder.createOr(Y, Z));
// x && (x && y) -> x && y
if (match(Def, m_LogicalAnd(m_VPValue(X),
- m_LogicalAnd(m_Deferred(X), m_VPValue())))) {
- Def->replaceAllUsesWith(Def->getOperand(1));
- return true;
- }
+ m_LogicalAnd(m_Deferred(X), m_VPValue()))))
+ return Def->getOperand(1);
// x && (y && x) -> x && y
if (match(Def, m_LogicalAnd(m_VPValue(X),
- m_LogicalAnd(m_VPValue(Y), m_Deferred(X))))) {
- Def->replaceAllUsesWith(Builder.createLogicalAnd(X, Y));
- return true;
- }
+ m_LogicalAnd(m_VPValue(Y), m_Deferred(X)))))
+ return Builder.createLogicalAnd(X, Y);
// x && !x -> 0
- if (match(Def, m_LogicalAnd(m_VPValue(X), m_Not(m_Deferred(X))))) {
- Def->replaceAllUsesWith(Plan->getFalse());
- return true;
- }
+ if (match(Def, m_LogicalAnd(m_VPValue(X), m_Not(m_Deferred(X)))))
+ return Plan->getFalse();
- if (match(Def, m_Select(m_VPValue(), m_VPValue(X), m_Deferred(X)))) {
- Def->replaceAllUsesWith(X);
- return true;
- }
+ if (match(Def, m_Select(m_VPValue(), m_VPValue(X), m_Deferred(X))))
+ return X;
// select c, false, true -> not c
VPValue *C;
if (CanCreateNewRecipe &&
- match(Def, m_Select(m_VPValue(C), m_False(), m_True()))) {
- Def->replaceAllUsesWith(Builder.createNot(C));
- return true;
- }
+ match(Def, m_Select(m_VPValue(C), m_False(), m_True())))
+ return Builder.createNot(C);
// select !c, x, y -> select c, y, x
if (match(Def, m_Select(m_Not(m_VPValue(C)), m_VPValue(X), m_VPValue(Y)))) {
Def->setOperand(0, C);
Def->setOperand(1, Y);
Def->setOperand(2, X);
- return true;
+ return Def;
}
// select x, (i1 y | z), y -> y | (x && z)
@@ -1237,11 +1208,8 @@ static bool simplifyLogicalRecipe(VPSingleDefRecipe *Def, VPBuilder &Builder,
match(Def, m_Select(m_VPValue(X),
m_OneUse(m_c_BinaryOr(m_VPValue(Y), m_VPValue(Z))),
m_Deferred(Y))) &&
- Y->getScalarType()->isIntegerTy(1)) {
- Def->replaceAllUsesWith(
- Builder.createOr(Y, Builder.createLogicalAnd(X, Z)));
- return true;
- }
+ Y->getScalarType()->isIntegerTy(1))
+ return Builder.createOr(Y, Builder.createLogicalAnd(X, Z));
// select %M0, (select %M1, %X, %Y), %Y -> select (%M0 && %M1), %X, %Y
VPValue *Mask0, *Mask1;
@@ -1250,31 +1218,30 @@ static bool simplifyLogicalRecipe(VPSingleDefRecipe *Def, VPBuilder &Builder,
m_SelectLike(m_VPValue(Mask0),
m_OneUse(m_SelectLike(m_VPValue(Mask1), m_VPValue(X),
m_VPValue(Y))),
- m_Deferred(Y)))) {
- auto *Select = Builder.createSelect(Builder.createLogicalAnd(Mask0, Mask1),
- X, Y, Def->getDebugLoc());
- Def->replaceAllUsesWith(Select);
- return true;
- }
+ m_Deferred(Y))))
+ return Builder.createSelect(Builder.createLogicalAnd(Mask0, Mask1), X, Y,
+ Def->getDebugLoc());
- return false;
+ return nullptr;
}
-/// Try to simplify VPSingleDefRecipe \p Def.
-static void simplifyRecipe(VPSingleDefRecipe *Def) {
+/// Try to simplify VPSingleDefRecipe \p Def. Returns a new recipe if it should
+/// be replaced, or the existing recipe if it was modified. Returns nullptr if
+/// nothing was simplified.
+static VPValue *simplifyRecipe(VPSingleDefRecipe *Def) {
VPlan *Plan = Def->getParent()->getPlan();
// Simplification of live-in IR values for SingleDef recipes using
// InstSimplifyFolder.
const DataLayout &DL = Plan->getDataLayout();
if (VPValue *V = vputils::tryToFoldLiveIns(*Def, Def->operands(), DL))
- return Def->replaceAllUsesWith(V);
+ return V;
// Fold PredPHI LiveIn -> LiveIn.
if (auto *PredPHI = dyn_cast<VPPredInstPHIRecipe>(Def)) {
VPValue *Op = PredPHI->getOperand(0);
if (isa<VPIRValue>(Op))
- PredPHI->replaceAllUsesWith(Op);
+ return Op;
}
// Drop the mask of a predicated store masked by the header mask (which is
@@ -1290,9 +1257,7 @@ static void simplifyRecipe(VPSingleDefRecipe *Def) {
RepR->isSingleScalar(), /*Mask=*/nullptr, *RepR, *RepR,
RepR->getDebugLoc());
Unmasked->insertBefore(RepR);
- RepR->replaceAllUsesWith(Unmasked);
- RepR->eraseFromParent();
- return;
+ return Unmasked;
}
VPBuilder Builder(Def);
@@ -1317,7 +1282,7 @@ static void simplifyRecipe(VPSingleDefRecipe *Def) {
} else {
// Don't replace a non-widened cast recipe with a widened cast.
if (!isa<VPWidenCastRecipe>(Def))
- return;
+ return nullptr;
if (ATy->getScalarSizeInBits() < TruncTy->getScalarSizeInBits()) {
unsigned ExtOpcode = match(Def->getOperand(0), m_SExt(m_VPValue()))
@@ -1337,25 +1302,25 @@ static void simplifyRecipe(VPSingleDefRecipe *Def) {
}
}
- if (simplifyLogicalRecipe(Def, Builder, CanCreateNewRecipe))
- return;
+ if (VPValue *V = simplifyLogicalRecipe(Def, Builder, CanCreateNewRecipe))
+ return V;
VPValue *X, *Y, *C;
if (match(Def, m_c_Add(m_VPValue(A), m_ZeroInt())))
- return Def->replaceAllUsesWith(A);
+ return A;
if (match(Def, m_c_Mul(m_VPValue(A), m_One())))
- return Def->replaceAllUsesWith(A);
+ return A;
if (match(Def, m_c_Mul(m_VPValue(A), m_ZeroInt())))
- return Def->replaceAllUsesWith(Plan->getZero(Def->getScalarType()));
+ return Plan->getZero(Def->getScalarType());
if (CanCreateNewRecipe && match(Def, m_c_Mul(m_VPValue(A), m_AllOnes()))) {
// Preserve nsw from the Mul on the new Sub.
VPIRFlags::WrapFlagsTy NW = {
false, cast<VPRecipeWithIRFlags>(Def)->hasNoSignedWrap()};
- return Def->replaceAllUsesWith(Builder.createSub(
- Plan->getZero(A->getScalarType()), A, Def->getDebugLoc(), "", NW));
+ return Builder.createSub(Plan->getZero(A->getScalarType()), A,
+ Def->getDebugLoc(), "", NW);
}
if (CanCreateNewRecipe &&
@@ -1367,8 +1332,7 @@ static void simplifyRecipe(VPSingleDefRecipe *Def) {
cast<VPRecipeWithIRFlags>(Def)->hasNoSignedWrap() &&
cast<VPRecipeWithIRFlags>(Def->getOperand(Def->getOperand(0) == X))
->hasNoSignedWrap()};
- return Def->replaceAllUsesWith(
- Builder.createSub(X, Y, Def->getDebugLoc(), "", NW));
+ return Builder.createSub(X, Y, Def->getDebugLoc(), "", NW);
}
const APInt *APC;
@@ -1379,22 +1343,22 @@ static void simplifyRecipe(VPSingleDefRecipe *Def) {
VPIRFlags::WrapFlagsTy NW(MulR->hasNoUnsignedWrap(),
MulR->hasNoSignedWrap() &&
ShiftAmt != APC->getBitWidth() - 1);
- return Def->replaceAllUsesWith(Builder.createNaryOp(
+ return Builder.createNaryOp(
Instruction::Shl,
{A, Plan->getConstantInt(APC->getBitWidth(), ShiftAmt)}, NW,
- Def->getDebugLoc()));
+ Def->getDebugLoc());
}
if (CanCreateNewRecipe && match(Def, m_UDiv(m_VPValue(A), m_APInt(APC))) &&
APC->isPowerOf2())
- return Def->replaceAllUsesWith(Builder.createNaryOp(
+ return Builder.createNaryOp(
Instruction::LShr,
{A, Plan->getConstantInt(APC->getBitWidth(), APC->exactLogBase2())},
- *cast<VPRecipeWithIRFlags>(Def), Def->getDebugLoc()));
+ *cast<VPRecipeWithIRFlags>(Def), Def->getDebugLoc());
if (match(Def, m_Not(m_VPValue(A)))) {
if (match(A, m_Not(m_VPValue(A))))
- return Def->replaceAllUsesWith(A);
+ return A;
// Try to fold Not into compares by adjusting the predicate in-place.
CmpPredicate Pred;
@@ -1423,6 +1387,7 @@ static void simplifyRecipe(VPSingleDefRecipe *Def) {
Cmp->setDebugLoc(Def->getDebugLoc());
}
}
+ return Def;
}
// Fold any-of (fcmp uno %A, %A), (fcmp uno %B, %B), ... ->
@@ -1450,7 +1415,7 @@ static void simplifyRecipe(VPSingleDefRecipe *Def) {
if (NewOps.size() < Def->getNumOperands()) {
VPValue *NewAnyOf = Builder.createNaryOp(VPInstruction::AnyOf, NewOps);
- return Def->replaceAllUsesWith(NewAnyOf);
+ return NewAnyOf;
}
}
@@ -1458,27 +1423,24 @@ static void simplifyRecipe(VPSingleDefRecipe *Def) {
// This is useful for fmax/fmin without fast-math flags, where we need to
// check if any operand is NaN.
if (CanCreateNewRecipe &&
- match(Def, m_BinaryOr(m_SpecificCmp(CmpInst::FCMP_UNO, m_VPValue(X),
- m_Deferred(X)),
- m_SpecificCmp(CmpInst::FCMP_UNO, m_VPValue(Y),
- m_Deferred(Y))))) {
- VPValue *NewCmp = Builder.createFCmp(CmpInst::FCMP_UNO, X, Y);
- return Def->replaceAllUsesWith(NewCmp);
- }
+ match(Def,
+ m_BinaryOr(
+ m_SpecificCmp(CmpInst::FCMP_UNO, m_VPValue(X), m_Deferred(X)),
+ m_SpecificCmp(CmpInst::FCMP_UNO, m_VPValue(Y), m_Deferred(Y)))))
+ return Builder.createFCmp(CmpInst::FCMP_UNO, X, Y);
// Remove redundant DerviedIVs, that is 0 + A * 1 -> A and 0 + 0 * x -> 0.
if ((match(Def, m_DerivedIV(m_ZeroInt(), m_VPValue(A), m_One())) ||
match(Def, m_DerivedIV(m_ZeroInt(), m_ZeroInt(), m_VPValue()))) &&
Def->getOperand(1)->getScalarType() == Def->getScalarType())
- return Def->replaceAllUsesWith(Def->getOperand(1));
+ return Def->getOperand(1);
if (match(Def, m_VPInstruction<VPInstruction::WideIVStep>(m_VPValue(X),
m_One()))) {
Type *WideStepTy = Def->getScalarType();
if (X->getScalarType() != WideStepTy)
X = Builder.createWidenCast(Instruction::Trunc, X, WideStepTy);
- Def->replaceAllUsesWith(X);
- return;
+ return X;
}
// For i1 vp.merges produced by AnyOf reductions:
@@ -1489,53 +1451,45 @@ static void simplifyRecipe(VPSingleDefRecipe *Def) {
Def->getScalarType()->isIntegerTy(1)) {
Def->setOperand(1, Def->getOperand(0));
Def->setOperand(0, Y);
- return;
+ return Def;
}
// Simplify MaskedCond with no block mask to its single operand.
if (match(Def, m_VPInstruction<VPInstruction::MaskedCond>()) &&
!cast<VPInstruction>(Def)->isMasked())
- return Def->replaceAllUsesWith(Def->getOperand(0));
+ return Def->getOperand(0);
// Look through ExtractLastLane.
if (match(Def, m_ExtractLastLane(m_VPValue(A)))) {
if (match(A, m_BuildVector())) {
auto *BuildVector = cast<VPInstruction>(A);
- Def->replaceAllUsesWith(
- BuildVector->getOperand(BuildVector->getNumOperands() - 1));
- return;
+ return BuildVector->getOperand(BuildVector->getNumOperands() - 1);
}
if (match(A, m_Broadcast(m_VPValue(X))))
- return Def->replaceAllUsesWith(X);
+ return X;
if (isa<VPInstruction, VPReplicateRecipe>(A) && vputils::isSingleScalar(A))
- return Def->replaceAllUsesWith(A);
+ return A;
if (Plan->hasScalarVFOnly())
- return Def->replaceAllUsesWith(A);
+ return A;
}
// Look through ExtractPenultimateElement (BuildVector ....).
if (match(Def, m_ExtractPenultimateElement(m_BuildVector()))) {
auto *BuildVector = cast<VPInstruction>(Def->getOperand(0));
- Def->replaceAllUsesWith(
- BuildVector->getOperand(BuildVector->getNumOperands() - 2));
- return;
+ return BuildVector->getOperand(BuildVector->getNumOperands() - 2);
}
uint64_t Idx;
if (match(Def, m_ExtractElement(m_BuildVector(), m_ConstantInt(Idx)))) {
auto *BuildVector = cast<VPInstruction>(Def->getOperand(0));
- Def->replaceAllUsesWith(BuildVector->getOperand(Idx));
- return;
+ return BuildVector->getOperand(Idx);
}
- if (match(Def, m_BuildVector()) && all_equal(Def->operands())) {
- Def->replaceAllUsesWith(
- Builder.createNaryOp(VPInstruction::Broadcast, Def->getOperand(0)));
- return;
- }
+ if (match(Def, m_BuildVector()) && all_equal(Def->operands()))
+ return Builder.createNaryOp(VPInstruction::Broadcast, Def->getOperand(0));
// Replace uses of a BuildVector by users that only use its first lane with
// its first operand directly.
@@ -1543,6 +1497,7 @@ static void simplifyRecipe(VPSingleDefRecipe *Def) {
Def->replaceUsesWithIf(Def->getOperand(0), [Def](VPUser &U, unsigned) {
return U.usesFirstLaneOnly(Def);
});
+ return Def;
}
// Look through broadcast of single-scalar when used as select conditions; in
@@ -1552,34 +1507,35 @@ static void simplifyRecipe(VPSingleDefRecipe *Def) {
assert(vputils::isSingleScalar(C) &&
"broadcast operand must be single-scalar");
Def->setOperand(0, C);
- return;
+ return Def;
}
- if (match(Def, m_Broadcast(m_VPValue(X))))
- return Def->replaceUsesWithIf(
+ if (match(Def, m_Broadcast(m_VPValue(X)))) {
+ Def->replaceUsesWithIf(
X, [Def](const VPUser &U, unsigned) { return U.usesScalars(Def); });
+ return Def;
+ }
if (isa<VPPhi, VPWidenPHIRecipe, VPHeaderPHIRecipe>(Def)) {
if (Def->getNumOperands() == 1) {
- Def->replaceAllUsesWith(Def->getOperand(0));
- return;
+ return Def->getOperand(0);
}
if (auto *Phi = dyn_cast<VPFirstOrderRecurrencePHIRecipe>(Def)) {
if (all_equal(Phi->incoming_values()))
- Phi->replaceAllUsesWith(Phi->getOperand(0));
+ return Phi->getOperand(0);
}
- return;
+ return nullptr;
}
VPIRValue *IRV;
if (Def->getNumOperands() == 1 &&
match(Def, m_ComputeReductionResult(m_VPIRValue(IRV))))
- return Def->replaceAllUsesWith(IRV);
+ return IRV;
// Some simplifications can only be applied after unrolling. Perform them
// below.
if (!Plan->isUnrolled())
- return;
+ return nullptr;
// After unrolling, extract-lane may be used to extract values from multiple
// scalar sources. Only simplify when extracting from a single scalar source.
@@ -1587,19 +1543,18 @@ static void simplifyRecipe(VPSingleDefRecipe *Def) {
if (match(Def, m_ExtractLane(m_VPValue(LaneToExtract), m_VPValue(A)))) {
// Simplify extract-lane(%lane_num, %scalar_val) -> %scalar_val.
if (vputils::isSingleScalar(A))
- return Def->replaceAllUsesWith(A);
+ return A;
// Replace extract-lane(0, canonical-WIDEN-INDUCTION) with the region's
// scalar canonical IV.
VPWidenIntOrFpInductionRecipe *WidenIV;
if (match(LaneToExtract, m_ZeroInt()) &&
match(A, m_CanonicalWidenIV(WidenIV)))
- return Def->replaceAllUsesWith(WidenIV->getRegion()->getCanonicalIV());
+ return WidenIV->getRegion()->getCanonicalIV();
// Simplify extract-lane with single source to extract-element.
- Def->replaceAllUsesWith(Builder.createNaryOp(
- Instruction::ExtractElement, {A, LaneToExtract}, Def->getDebugLoc()));
- return;
+ return Builder.createNaryOp(Instruction::ExtractElement, {A, LaneToExtract},
+ Def->getDebugLoc());
}
// Look for cycles where Def is of the form:
@@ -1623,7 +1578,7 @@ static void simplifyRecipe(VPSingleDefRecipe *Def) {
if (Inc)
Inc->replaceAllUsesWith(Phi);
Phi->setOperand(0, Y);
- return;
+ return Def;
}
}
}
@@ -1632,16 +1587,14 @@ static void simplifyRecipe(VPSingleDefRecipe *Def) {
// just the pointer operand.
if (auto *VPR = dyn_cast<VPVectorPointerRecipe>(Def))
if (!VPR->getVFxPart() || match(VPR->getVFxPart(), m_ZeroInt()))
- return VPR->replaceAllUsesWith(VPR->getOperand(0));
+ return VPR->getOperand(0);
// VPScalarIVSteps after unrolling can be replaced by their start value, if
// the start index is zero and only the first lane 0 is demanded.
- if (auto *Steps = dyn_cast<VPScalarIVStepsRecipe>(Def)) {
- if (!Steps->getStartIndex() && vputils::onlyFirstLaneUsed(Steps)) {
- Steps->replaceAllUsesWith(Steps->getOperand(0));
- return;
- }
- }
+ if (auto *Steps = dyn_cast<VPScalarIVStepsRecipe>(Def))
+ if (!Steps->getStartIndex() && vputils::onlyFirstLaneUsed(Steps))
+ return Steps->getOperand(0);
+
// Simplify redundant ReductionStartVector recipes after unrolling.
VPValue *StartV;
if (match(Def, m_VPInstruction<VPInstruction::ReductionStartVector>(
@@ -1650,11 +1603,13 @@ static void simplifyRecipe(VPSingleDefRecipe *Def) {
auto *PhiR = dyn_cast<VPReductionPHIRecipe>(&U);
return PhiR && PhiR->isInLoop();
});
- return;
+ return Def;
}
if (Plan->getConcreteUF() == 1 && match(Def, m_ExtractLastPart(m_VPValue(A))))
- return Def->replaceAllUsesWith(A);
+ return A;
+
+ return nullptr;
}
void VPlanTransforms::simplifyRecipes(VPlan &Plan) {
@@ -1663,7 +1618,16 @@ void VPlanTransforms::simplifyRecipes(VPlan &Plan) {
for (VPBasicBlock *VPBB : VPBlockUtils::blocksOnly<VPBasicBlock>(RPOT)) {
for (VPRecipeBase &R : make_early_inc_range(*VPBB))
if (auto *Def = dyn_cast<VPSingleDefRecipe>(&R))
- simplifyRecipe(Def);
+ if (VPValue *New = simplifyRecipe(Def)) {
+ if (New != Def) {
+ // Replace the recipe with a new one.
+ Def->replaceAllUsesWith(New);
+ Def->eraseFromParent();
+ } else if (vputils::isDeadRecipe(R)) {
+ // Recipe was modified - it may be dead now.
+ Def->eraseFromParent();
+ }
+ }
}
}
diff --git a/llvm/test/Transforms/LoopVectorize/VPlan/constant-fold.ll b/llvm/test/Transforms/LoopVectorize/VPlan/constant-fold.ll
index 92bb9704c4fd2..f648b52602637 100644
--- a/llvm/test/Transforms/LoopVectorize/VPlan/constant-fold.ll
+++ b/llvm/test/Transforms/LoopVectorize/VPlan/constant-fold.ll
@@ -24,14 +24,11 @@ define void @f1() {
; CHECK-EMPTY:
; CHECK-NEXT: bb2:
; CHECK-NEXT: EMIT-SCALAR ir<%c.1.0> = phi [ ir<0>, vector.ph ], [ ir<%_tmp9>, bb2 ]
-; CHECK-NEXT: EMIT-SCALAR ir<%_tmp1> = zext ir<0> to i64
-; CHECK-NEXT: EMIT ir<%_tmp2> = getelementptr ir<@a>, ir<0>, ir<0>
; CHECK-NEXT: EMIT-SCALAR ir<%_tmp6> = sext ir<%c.1.0> to i64
; CHECK-NEXT: EMIT ir<%_tmp7> = getelementptr ir<@b>, ir<0>, ir<%_tmp6>
; CHECK-NEXT: EMIT store ir<@a>, ir<%_tmp7>
; CHECK-NEXT: EMIT ir<%_tmp9> = add nsw ir<%c.1.0>, ir<1>
; CHECK-NEXT: EMIT ir<%_tmp11> = icmp sge ir<%_tmp9>, ir<2>
-; CHECK-NEXT: EMIT vp<{{.+}}> = not ir<%_tmp11>
; CHECK-NEXT: EMIT branch-on-cond ir<%_tmp11>
; CHECK-NEXT: Successor(s): middle.block, bb2
;
@@ -74,8 +71,6 @@ define void @redundant_or_1(ptr %dst, i1 %c.0, i1 %c.1) {
; CHECK-EMPTY:
; CHECK-NEXT: then.1:
; CHECK-NEXT: EMIT ir<%cmp> = icmp eq ir<%iv>, ir<2>
-; CHECK-NEXT: EMIT ir<%or> = or ir<%cmp>, ir<true>
-; CHECK-NEXT: EMIT ir<%cond> = select ir<true>, ir<%c.1>, ir<false>
; CHECK-NEXT: EMIT branch-on-cond ir<%c.1>
; CHECK-NEXT: Successor(s): then.2, loop.latch
;
@@ -125,8 +120,6 @@ define void @redundant_or_2(ptr %dst, i1 %c.0, i1 %c.1) {
; CHECK-EMPTY:
; CHECK-NEXT: then.1:
; CHECK-NEXT: EMIT ir<%cmp> = icmp eq ir<%iv>, ir<2>
-; CHECK-NEXT: EMIT ir<%or> = or ir<true>, ir<%cmp>
-; CHECK-NEXT: EMIT ir<%cond> = select ir<true>, ir<%c.1>, ir<false>
; CHECK-NEXT: EMIT branch-on-cond ir<%c.1>
; CHECK-NEXT: Successor(s): then.2, loop.latch
;
@@ -176,7 +169,6 @@ define void @redundant_and_1(ptr %dst, i1 %c.0, i1 %c.1) {
; CHECK-EMPTY:
; CHECK-NEXT: then.1:
; CHECK-NEXT: EMIT ir<%cmp> = icmp eq ir<%iv>, ir<2>
-; CHECK-NEXT: EMIT ir<%or> = or ir<%cmp>, ir<false>
; CHECK-NEXT: EMIT ir<%cond> = select ir<%cmp>, ir<%c.1>, ir<false>
; CHECK-NEXT: EMIT branch-on-cond ir<%cond>
; CHECK-NEXT: Successor(s): then.2, loop.latch
@@ -228,8 +220,6 @@ define void @redundant_and_2(ptr %dst, i1 %c.0, i1 %c.1) {
; CHECK-EMPTY:
; CHECK-NEXT: then.1:
; CHECK-NEXT: EMIT ir<%cmp> = icmp eq ir<%iv>, ir<2>
-; CHECK-NEXT: EMIT ir<%or> = and ir<false>, ir<%cmp>
-; CHECK-NEXT: EMIT ir<%cond> = select ir<false>, ir<%c.1>, ir<false>
; CHECK-NEXT: EMIT branch-on-cond ir<false>
; CHECK-NEXT: Successor(s): then.2, loop.latch
;
@@ -280,7 +270,6 @@ define void @fold_replicating_umax_equal_live_ins(ptr noalias %dst, ptr %cond, i
; CHECK-NEXT: Successor(s): then, latch
; CHECK-EMPTY:
; CHECK-NEXT: then:
-; CHECK-NEXT: EMIT ir<%m> = call ir<%x>, ir<%x>, ir<@llvm.umax.i32>
; CHECK-NEXT: EMIT ir<%gep> = getelementptr ir<%dst>, ir<%iv>
; CHECK-NEXT: EMIT store ir<%x>, ir<%gep>
; CHECK-NEXT: Successor(s): latch
diff --git a/llvm/test/Transforms/LoopVectorize/epilog-vectorization-reductions.ll b/llvm/test/Transforms/LoopVectorize/epilog-vectorization-reductions.ll
index 20e18d018892a..846c78db79100 100644
--- a/llvm/test/Transforms/LoopVectorize/epilog-vectorization-reductions.ll
+++ b/llvm/test/Transforms/LoopVectorize/epilog-vectorization-reductions.ll
@@ -1115,7 +1115,6 @@ define i32 @test_foldable_reduction(i64 %N) {
; CHECK-NEXT: br i1 [[TMP1]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP32:![0-9]+]]
; CHECK: [[MIDDLE_BLOCK]]:
; CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.vector.reduce.or.v8i32(<8 x i32> [[VEC_PHI]])
-; CHECK-NEXT: [[TMP3:%.*]] = call i1 @llvm.vector.reduce.or.v8i1(<8 x i1> splat (i1 true))
; CHECK-NEXT: [[CMP_N:%.*]] = icmp eq i64 [[TMP0]], [[N_VEC]]
; CHECK-NEXT: br i1 [[CMP_N]], label %[[EXIT:.*]], label %[[VEC_EPILOG_ITER_CHECK:.*]]
; CHECK: [[VEC_EPILOG_ITER_CHECK]]:
@@ -1136,7 +1135,6 @@ define i32 @test_foldable_reduction(i64 %N) {
; CHECK-NEXT: br i1 [[TMP6]], label %[[VEC_EPILOG_MIDDLE_BLOCK:.*]], label %[[VEC_EPILOG_VECTOR_BODY]], !llvm.loop [[LOOP33:![0-9]+]]
; CHECK: [[VEC_EPILOG_MIDDLE_BLOCK]]:
; CHECK-NEXT: [[TMP7:%.*]] = call i32 @llvm.vector.reduce.or.v4i32(<4 x i32> [[VEC_PHI6]])
-; CHECK-NEXT: [[TMP8:%.*]] = call i1 @llvm.vector.reduce.or.v4i1(<4 x i1> splat (i1 true))
; CHECK-NEXT: [[CMP_N9:%.*]] = icmp eq i64 [[TMP0]], [[N_VEC4]]
; CHECK-NEXT: br i1 [[CMP_N9]], label %[[EXIT]], label %[[VEC_EPILOG_SCALAR_PH]]
; CHECK: [[VEC_EPILOG_SCALAR_PH]]:
>From 2a3f74fa60131097570b925ee451e7960278b614 Mon Sep 17 00:00:00 2001
From: Luke Lau <luke at igalia.com>
Date: Thu, 30 Jul 2026 22:18:50 +0800
Subject: [PATCH 2/2] Update trunc combine, fix m_Not return position
---
llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
index 0101d43adda81..21bbe02c0ca07 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
@@ -1274,7 +1274,7 @@ static VPValue *simplifyRecipe(VPSingleDefRecipe *Def) {
Type *TruncTy = Def->getScalarType();
Type *ATy = A->getScalarType();
if (TruncTy == ATy) {
- Def->replaceAllUsesWith(A);
+ return A;
} else {
// Don't replace a non-widened cast recipe with a widened cast.
if (!isa<VPWidenCastRecipe>(Def))
@@ -1290,10 +1290,10 @@ static VPValue *simplifyRecipe(VPSingleDefRecipe *Def) {
// UnderlyingExt has distinct return type, used to retain legacy cost.
Ext->setUnderlyingValue(UnderlyingExt);
}
- Def->replaceAllUsesWith(Ext);
+ return Ext;
} else if (ATy->getScalarSizeInBits() > TruncTy->getScalarSizeInBits()) {
auto *Trunc = Builder.createWidenCast(Instruction::Trunc, A, TruncTy);
- Def->replaceAllUsesWith(Trunc);
+ return Trunc;
}
}
}
@@ -1381,9 +1381,9 @@ static VPValue *simplifyRecipe(VPSingleDefRecipe *Def) {
// to preserve the location.
if (!Cmp->getDebugLoc() && Def->getDebugLoc())
Cmp->setDebugLoc(Def->getDebugLoc());
+ return Def;
}
}
- return Def;
}
// Fold any-of (fcmp uno %A, %A), (fcmp uno %B, %B), ... ->
More information about the llvm-commits
mailing list