@@ -8953,14 +8953,73 @@ static void addScalarResumePhis(VPRecipeBuilder &Builder, VPlan &Plan) {
8953
8953
}
8954
8954
}
8955
8955
8956
+ /// Return true if \p VPV is an optimizable IV or IV use. That is, if \p VPV is
8957
+ /// either an untruncated wide induction, or if it increments a wide induction
8958
+ /// by its step.
8959
+ static bool isOptimizableIVOrUse(VPValue *VPV) {
8960
+ VPRecipeBase *Def = VPV->getDefiningRecipe();
8961
+ if (!Def)
8962
+ return false;
8963
+ auto *WideIV = dyn_cast<VPWidenInductionRecipe>(Def);
8964
+ if (WideIV) {
8965
+ // VPV itself is a wide induction, separately compute the end value for exit
8966
+ // users if it is not a truncated IV.
8967
+ return isa<VPWidenPointerInductionRecipe>(WideIV) ||
8968
+ !cast<VPWidenIntOrFpInductionRecipe>(WideIV)->getTruncInst();
8969
+ }
8970
+
8971
+ // Check if VPV is an optimizable induction increment.
8972
+ if (Def->getNumOperands() != 2)
8973
+ return false;
8974
+ WideIV = dyn_cast<VPWidenInductionRecipe>(Def->getOperand(0));
8975
+ if (!WideIV)
8976
+ WideIV = dyn_cast<VPWidenInductionRecipe>(Def->getOperand(1));
8977
+ if (!WideIV)
8978
+ return false;
8979
+
8980
+ using namespace VPlanPatternMatch;
8981
+ auto &ID = WideIV->getInductionDescriptor();
8982
+
8983
+ // Check if VPV increments the induction by the induction step.
8984
+ VPValue *IVStep = WideIV->getStepValue();
8985
+ switch (ID.getInductionOpcode()) {
8986
+ case Instruction::Add:
8987
+ return match(VPV, m_c_Binary<Instruction::Add>(m_Specific(WideIV),
8988
+ m_Specific(IVStep)));
8989
+ case Instruction::FAdd:
8990
+ return match(VPV, m_c_Binary<Instruction::FAdd>(m_Specific(WideIV),
8991
+ m_Specific(IVStep)));
8992
+ case Instruction::FSub:
8993
+ return match(VPV, m_Binary<Instruction::FSub>(m_Specific(WideIV),
8994
+ m_Specific(IVStep)));
8995
+ case Instruction::Sub: {
8996
+ // IVStep will be the negated step of the subtraction. Check if Step == -1 *
8997
+ // IVStep.
8998
+ VPValue *Step;
8999
+ if (!match(VPV, m_Binary<Instruction::Sub>(m_VPValue(), m_VPValue(Step))) ||
9000
+ !Step->isLiveIn() || !IVStep->isLiveIn())
9001
+ return false;
9002
+ auto *StepCI = dyn_cast<ConstantInt>(Step->getLiveInIRValue());
9003
+ auto *IVStepCI = dyn_cast<ConstantInt>(IVStep->getLiveInIRValue());
9004
+ return StepCI && IVStepCI &&
9005
+ StepCI->getValue() == (-1 * IVStepCI->getValue());
9006
+ }
9007
+ default:
9008
+ return ID.getKind() == InductionDescriptor::IK_PtrInduction &&
9009
+ match(VPV, m_GetElementPtr(m_Specific(WideIV),
9010
+ m_Specific(WideIV->getStepValue())));
9011
+ }
9012
+ llvm_unreachable("should have been covered by switch above");
9013
+ }
9014
+
8956
9015
// Collect VPIRInstructions for phis in the exit blocks that are modeled
8957
9016
// in VPlan and add the exiting VPValue as operand. Some exiting values are not
8958
9017
// modeled explicitly yet and won't be included. Those are un-truncated
8959
9018
// VPWidenIntOrFpInductionRecipe, VPWidenPointerInductionRecipe and induction
8960
9019
// increments.
8961
- static SetVector<VPIRInstruction *> collectUsersInExitBlocks(
8962
- Loop *OrigLoop, VPRecipeBuilder &Builder, VPlan &Plan ,
8963
- const MapVector<PHINode *, InductionDescriptor> &Inductions ) {
9020
+ static SetVector<VPIRInstruction *>
9021
+ collectUsersInExitBlocks( Loop *OrigLoop, VPRecipeBuilder &Builder,
9022
+ VPlan &Plan ) {
8964
9023
auto *MiddleVPBB = Plan.getMiddleBlock();
8965
9024
SetVector<VPIRInstruction *> ExitUsersToFix;
8966
9025
for (VPIRBasicBlock *ExitVPBB : Plan.getExitBlocks()) {
@@ -8985,18 +9044,9 @@ static SetVector<VPIRInstruction *> collectUsersInExitBlocks(
8985
9044
// Exit values for inductions are computed and updated outside of VPlan
8986
9045
// and independent of induction recipes.
8987
9046
// TODO: Compute induction exit values in VPlan.
8988
- if ((isa<VPWidenIntOrFpInductionRecipe>(V) &&
8989
- !cast<VPWidenIntOrFpInductionRecipe>(V)->getTruncInst()) ||
8990
- isa<VPWidenPointerInductionRecipe>(V) ||
8991
- (isa<Instruction>(IncomingValue) &&
8992
- OrigLoop->contains(cast<Instruction>(IncomingValue)) &&
8993
- any_of(IncomingValue->users(), [&Inductions](User *U) {
8994
- auto *P = dyn_cast<PHINode>(U);
8995
- return P && Inductions.contains(P);
8996
- }))) {
8997
- if (ExitVPBB->getSinglePredecessor() == MiddleVPBB)
8998
- continue;
8999
- }
9047
+ if (isOptimizableIVOrUse(V) &&
9048
+ ExitVPBB->getSinglePredecessor() == MiddleVPBB)
9049
+ continue;
9000
9050
ExitUsersToFix.insert(ExitIRI);
9001
9051
ExitIRI->addOperand(V);
9002
9052
}
@@ -9331,8 +9381,8 @@ LoopVectorizationPlanner::tryToBuildVPlanWithVPRecipes(VFRange &Range) {
9331
9381
*Plan, *PSE.getSE(), OrigLoop, UncountableExitingBlock, RecipeBuilder);
9332
9382
}
9333
9383
addScalarResumePhis(RecipeBuilder, *Plan);
9334
- SetVector<VPIRInstruction *> ExitUsersToFix = collectUsersInExitBlocks(
9335
- OrigLoop, RecipeBuilder, *Plan, Legal->getInductionVars() );
9384
+ SetVector<VPIRInstruction *> ExitUsersToFix =
9385
+ collectUsersInExitBlocks( OrigLoop, RecipeBuilder, *Plan);
9336
9386
addExitUsersForFirstOrderRecurrences(*Plan, ExitUsersToFix);
9337
9387
if (!addUsersInExitBlocks(*Plan, ExitUsersToFix)) {
9338
9388
reportVectorizationFailure(
0 commit comments