@@ -8953,14 +8953,73 @@ static void addScalarResumePhis(VPRecipeBuilder &Builder, VPlan &Plan) {
89538953 }
89548954}
89558955
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+
89569015// Collect VPIRInstructions for phis in the exit blocks that are modeled
89579016// in VPlan and add the exiting VPValue as operand. Some exiting values are not
89589017// modeled explicitly yet and won't be included. Those are un-truncated
89599018// VPWidenIntOrFpInductionRecipe, VPWidenPointerInductionRecipe and induction
89609019// 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 ) {
89649023 auto *MiddleVPBB = Plan.getMiddleBlock ();
89659024 SetVector<VPIRInstruction *> ExitUsersToFix;
89669025 for (VPIRBasicBlock *ExitVPBB : Plan.getExitBlocks ()) {
@@ -8985,18 +9044,9 @@ static SetVector<VPIRInstruction *> collectUsersInExitBlocks(
89859044 // Exit values for inductions are computed and updated outside of VPlan
89869045 // and independent of induction recipes.
89879046 // 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 ;
90009050 ExitUsersToFix.insert (ExitIRI);
90019051 ExitIRI->addOperand (V);
90029052 }
@@ -9331,8 +9381,8 @@ LoopVectorizationPlanner::tryToBuildVPlanWithVPRecipes(VFRange &Range) {
93319381 *Plan, *PSE.getSE (), OrigLoop, UncountableExitingBlock, RecipeBuilder);
93329382 }
93339383 addScalarResumePhis (RecipeBuilder, *Plan);
9334- SetVector<VPIRInstruction *> ExitUsersToFix = collectUsersInExitBlocks (
9335- OrigLoop, RecipeBuilder, *Plan, Legal-> getInductionVars () );
9384+ SetVector<VPIRInstruction *> ExitUsersToFix =
9385+ collectUsersInExitBlocks ( OrigLoop, RecipeBuilder, *Plan);
93369386 addExitUsersForFirstOrderRecurrences (*Plan, ExitUsersToFix);
93379387 if (!addUsersInExitBlocks (*Plan, ExitUsersToFix)) {
93389388 reportVectorizationFailure (
0 commit comments