@@ -523,7 +523,7 @@ class InnerLoopVectorizer {
523523 // / and the resume values can come from an additional bypass block, the \p
524524 // / AdditionalBypass pair provides information about the bypass block and the
525525 // / end value on the edge from bypass to this loop.
526- PHINode * createInductionResumeValue (
526+ void createInductionResumeValue (
527527 PHINode *OrigPhi, const InductionDescriptor &ID, Value *Step,
528528 ArrayRef<BasicBlock *> BypassBlocks,
529529 std::pair<BasicBlock *, Value *> AdditionalBypass = {nullptr , nullptr });
@@ -536,6 +536,11 @@ class InnerLoopVectorizer {
536536 // / count of the original loop for both main loop and epilogue vectorization.
537537 void setTripCount (Value *TC) { TripCount = TC; }
538538
539+ std::pair<BasicBlock *, Value *>
540+ getInductionBypassValue (PHINode *OrigPhi) const {
541+ return InductionBypassValues.find (OrigPhi)->second ;
542+ }
543+
539544protected:
540545 friend class LoopVectorizationPlanner ;
541546
@@ -675,6 +680,9 @@ class InnerLoopVectorizer {
675680 // / for cleaning the checks, if vectorization turns out unprofitable.
676681 GeneratedRTChecks &RTChecks;
677682
683+ // / Mapping of induction phis to their bypass values and bypass blocks.
684+ DenseMap<PHINode *, std::pair<BasicBlock *, Value *>> InductionBypassValues;
685+
678686 VPlan &Plan;
679687};
680688
@@ -2588,7 +2596,18 @@ void InnerLoopVectorizer::createVectorLoopSkeleton(StringRef Prefix) {
25882596 nullptr , Twine (Prefix) + " scalar.ph" );
25892597}
25902598
2591- PHINode *InnerLoopVectorizer::createInductionResumeValue (
2599+ static void addOperandToPhiInVPIRBasicBlock (VPIRBasicBlock *VPBB, PHINode *P,
2600+ VPValue *Op) {
2601+ for (VPRecipeBase &R : *VPBB) {
2602+ auto *IRI = cast<VPIRInstruction>(&R);
2603+ if (&IRI->getInstruction () == P) {
2604+ IRI->addOperand (Op);
2605+ break ;
2606+ }
2607+ }
2608+ }
2609+
2610+ void InnerLoopVectorizer::createInductionResumeValue (
25922611 PHINode *OrigPhi, const InductionDescriptor &II, Value *Step,
25932612 ArrayRef<BasicBlock *> BypassBlocks,
25942613 std::pair<BasicBlock *, Value *> AdditionalBypass) {
@@ -2623,27 +2642,28 @@ PHINode *InnerLoopVectorizer::createInductionResumeValue(
26232642 }
26242643 }
26252644
2626- // Create phi nodes to merge from the backedge-taken check block.
2627- PHINode *BCResumeVal =
2628- PHINode::Create (OrigPhi->getType (), 3 , " bc.resume.val" ,
2629- LoopScalarPreHeader->getFirstNonPHIIt ());
2630- // Copy original phi DL over to the new one.
2631- BCResumeVal->setDebugLoc (OrigPhi->getDebugLoc ());
2645+ VPBasicBlock *MiddleVPBB =
2646+ cast<VPBasicBlock>(Plan.getVectorLoopRegion ()->getSingleSuccessor ());
26322647
2633- // The new PHI merges the original incoming value, in case of a bypass,
2634- // or the value at the end of the vectorized loop.
2635- BCResumeVal->addIncoming (EndValue, LoopMiddleBlock);
2648+ VPBasicBlock *ScalarPHVPBB = nullptr ;
2649+ if (MiddleVPBB->getNumSuccessors () == 2 ) {
2650+ // Order is strict: first is the exit block, second is the scalar preheader.
2651+ ScalarPHVPBB = cast<VPBasicBlock>(MiddleVPBB->getSuccessors ()[1 ]);
2652+ } else {
2653+ ScalarPHVPBB = cast<VPBasicBlock>(MiddleVPBB->getSingleSuccessor ());
2654+ }
26362655
2637- // Fix the scalar body counter (PHI node).
2638- // The old induction's phi node in the scalar body needs the truncated
2639- // value.
2640- for (BasicBlock *BB : BypassBlocks)
2641- BCResumeVal-> addIncoming (II. getStartValue ( ), BB );
2656+ VPBuilder ScalarPHBuilder (ScalarPHVPBB);
2657+ auto *ResumePhiRecipe = ScalarPHBuilder. createNaryOp (
2658+ VPInstruction::ResumePhi,
2659+ {Plan. getOrAddLiveIn (EndValue), Plan. getOrAddLiveIn (II. getStartValue ())},
2660+ OrigPhi-> getDebugLoc ( ), " bc.resume.val " );
26422661
2643- if (AdditionalBypass.first )
2644- BCResumeVal->setIncomingValueForBlock (AdditionalBypass.first ,
2645- EndValueFromAdditionalBypass);
2646- return BCResumeVal;
2662+ auto *ScalarLoopHeader =
2663+ cast<VPIRBasicBlock>(ScalarPHVPBB->getSingleSuccessor ());
2664+ addOperandToPhiInVPIRBasicBlock (ScalarLoopHeader, OrigPhi, ResumePhiRecipe);
2665+ InductionBypassValues[OrigPhi] = {AdditionalBypass.first ,
2666+ EndValueFromAdditionalBypass};
26472667}
26482668
26492669// / Return the expanded step for \p ID using \p ExpandedSCEVs to look up SCEV
@@ -2676,10 +2696,8 @@ void InnerLoopVectorizer::createInductionResumeValues(
26762696 for (const auto &InductionEntry : Legal->getInductionVars ()) {
26772697 PHINode *OrigPhi = InductionEntry.first ;
26782698 const InductionDescriptor &II = InductionEntry.second ;
2679- PHINode *BCResumeVal = createInductionResumeValue (
2680- OrigPhi, II, getExpandedStep (II, ExpandedSCEVs), LoopBypassBlocks,
2681- AdditionalBypass);
2682- OrigPhi->setIncomingValueForBlock (LoopScalarPreHeader, BCResumeVal);
2699+ createInductionResumeValue (OrigPhi, II, getExpandedStep (II, ExpandedSCEVs),
2700+ LoopBypassBlocks, AdditionalBypass);
26832701 }
26842702}
26852703
@@ -7803,6 +7821,25 @@ EpilogueVectorizerMainLoop::createEpilogueVectorizedLoopSkeleton(
78037821 // the second pass for the scalar loop. The induction resume values for the
78047822 // inductions in the epilogue loop are created before executing the plan for
78057823 // the epilogue loop.
7824+ for (VPRecipeBase &R :
7825+ Plan.getVectorLoopRegion ()->getEntryBasicBlock ()->phis ()) {
7826+ // Create induction resume values for both widened pointer and
7827+ // integer/fp inductions and update the start value of the induction
7828+ // recipes to use the resume value.
7829+ PHINode *IndPhi = nullptr ;
7830+ const InductionDescriptor *ID;
7831+ if (auto *Ind = dyn_cast<VPWidenPointerInductionRecipe>(&R)) {
7832+ IndPhi = cast<PHINode>(Ind->getUnderlyingValue ());
7833+ ID = &Ind->getInductionDescriptor ();
7834+ } else if (auto *WidenInd = dyn_cast<VPWidenIntOrFpInductionRecipe>(&R)) {
7835+ IndPhi = WidenInd->getPHINode ();
7836+ ID = &WidenInd->getInductionDescriptor ();
7837+ } else
7838+ continue ;
7839+
7840+ createInductionResumeValue (IndPhi, *ID, getExpandedStep (*ID, ExpandedSCEVs),
7841+ LoopBypassBlocks);
7842+ }
78067843
78077844 return {LoopVectorPreHeader, nullptr };
78087845}
@@ -10293,23 +10330,16 @@ bool LoopVectorizePass::processLoop(Loop *L) {
1029310330 RdxDesc.getRecurrenceStartValue ());
1029410331 }
1029510332 } else {
10296- // Create induction resume values for both widened pointer and
10297- // integer/fp inductions and update the start value of the induction
10298- // recipes to use the resume value.
10333+ // Retrive the induction resume values for wide inductions from
10334+ // their original phi nodes in the scalar loop
1029910335 PHINode *IndPhi = nullptr ;
10300- const InductionDescriptor *ID;
1030110336 if (auto *Ind = dyn_cast<VPWidenPointerInductionRecipe>(&R)) {
1030210337 IndPhi = cast<PHINode>(Ind->getUnderlyingValue ());
10303- ID = &Ind->getInductionDescriptor ();
1030410338 } else {
1030510339 auto *WidenInd = cast<VPWidenIntOrFpInductionRecipe>(&R);
1030610340 IndPhi = WidenInd->getPHINode ();
10307- ID = &WidenInd->getInductionDescriptor ();
1030810341 }
10309-
10310- ResumeV = MainILV.createInductionResumeValue (
10311- IndPhi, *ID, getExpandedStep (*ID, ExpandedSCEVs),
10312- {EPI.MainLoopIterationCountCheck });
10342+ ResumeV = IndPhi->getIncomingValueForBlock (L->getLoopPreheader ());
1031310343 }
1031410344 assert (ResumeV && " Must have a resume value" );
1031510345 VPValue *StartVal = BestEpiPlan.getOrAddLiveIn (ResumeV);
@@ -10321,7 +10351,13 @@ bool LoopVectorizePass::processLoop(Loop *L) {
1032110351 LVP.executePlan (EPI.EpilogueVF , EPI.EpilogueUF , BestEpiPlan, EpilogILV,
1032210352 DT, true , &ExpandedSCEVs);
1032310353 ++LoopsEpilogueVectorized;
10354+ BasicBlock *PH = L->getLoopPreheader ();
1032410355
10356+ for (const auto &[IVPhi, _] : LVL.getInductionVars ()) {
10357+ auto *Inc = cast<PHINode>(IVPhi->getIncomingValueForBlock (PH));
10358+ const auto &[BB, V] = EpilogILV.getInductionBypassValue (IVPhi);
10359+ Inc->setIncomingValueForBlock (BB, V);
10360+ }
1032510361 if (!MainILV.areSafetyChecksAdded ())
1032610362 DisableRuntimeUnroll = true ;
1032710363 } else {
0 commit comments