@@ -2775,6 +2775,23 @@ BasicBlock *InnerLoopVectorizer::createVectorizedLoopSkeleton(
27752775 return LoopVectorPreHeader;
27762776}
27772777
2778+ static bool isValueIncomingFromBlock (BasicBlock *ExitingBB, Value *V,
2779+ Instruction *UI) {
2780+ PHINode *PHI = dyn_cast<PHINode>(UI);
2781+ assert (PHI && " Expected LCSSA form" );
2782+
2783+ // If this loop has an uncountable early exit then there could be
2784+ // different users of OrigPhi with either:
2785+ // 1. Multiple users, because each exiting block (countable or
2786+ // uncountable) jumps to the same exit block, or ..
2787+ // 2. A single user with an incoming value from a countable or
2788+ // uncountable exiting block.
2789+ // In both cases there is no guarantee this came from a countable exiting
2790+ // block, i.e. the latch.
2791+ int Index = PHI->getBasicBlockIndex (ExitingBB);
2792+ return Index != -1 && PHI->getIncomingValue (Index) == V;
2793+ }
2794+
27782795// Fix up external users of the induction variable. At this point, we are
27792796// in LCSSA form, with all external PHIs that use the IV having one input value,
27802797// coming from the remainder loop. We need those PHIs to also have a correct
@@ -2797,12 +2814,13 @@ void InnerLoopVectorizer::fixupIVUsers(PHINode *OrigPhi,
27972814
27982815 // An external user of the last iteration's value should see the value that
27992816 // the remainder loop uses to initialize its own IV.
2800- Value *PostInc = OrigPhi->getIncomingValueForBlock (OrigLoop->getLoopLatch ());
2817+ BasicBlock *OrigLoopLatch = OrigLoop->getLoopLatch ();
2818+ Value *PostInc = OrigPhi->getIncomingValueForBlock (OrigLoopLatch);
28012819 for (User *U : PostInc->users ()) {
28022820 Instruction *UI = cast<Instruction>(U);
28032821 if (!OrigLoop->contains (UI)) {
2804- assert (isa<PHINode>(UI) && " Expected LCSSA form " );
2805- MissingVals[UI ] = EndValue;
2822+ if ( isValueIncomingFromBlock (OrigLoopLatch, PostInc, UI))
2823+ MissingVals[cast<PHINode>(UI) ] = EndValue;
28062824 }
28072825 }
28082826
@@ -2812,7 +2830,8 @@ void InnerLoopVectorizer::fixupIVUsers(PHINode *OrigPhi,
28122830 for (User *U : OrigPhi->users ()) {
28132831 auto *UI = cast<Instruction>(U);
28142832 if (!OrigLoop->contains (UI)) {
2815- assert (isa<PHINode>(UI) && " Expected LCSSA form" );
2833+ if (!isValueIncomingFromBlock (OrigLoopLatch, OrigPhi, UI))
2834+ continue ;
28162835 IRBuilder<> B (MiddleBlock->getTerminator ());
28172836
28182837 // Fast-math-flags propagate from the original induction instruction.
@@ -2842,18 +2861,6 @@ void InnerLoopVectorizer::fixupIVUsers(PHINode *OrigPhi,
28422861 }
28432862 }
28442863
2845- assert ((MissingVals.empty () ||
2846- all_of (MissingVals,
2847- [MiddleBlock, this ](const std::pair<Value *, Value *> &P) {
2848- return all_of (
2849- predecessors (cast<Instruction>(P.first )->getParent ()),
2850- [MiddleBlock, this ](BasicBlock *Pred) {
2851- return Pred == MiddleBlock ||
2852- Pred == OrigLoop->getLoopLatch ();
2853- });
2854- })) &&
2855- " Expected escaping values from latch/middle.block only" );
2856-
28572864 for (auto &I : MissingVals) {
28582865 PHINode *PHI = cast<PHINode>(I.first );
28592866 // One corner case we have to handle is two IVs "chasing" each-other,
@@ -7774,6 +7781,9 @@ DenseMap<const SCEV *, Value *> LoopVectorizationPlanner::executePlan(
77747781 State.LVer ->prepareNoAliasMetadata ();
77757782 }
77767783
7784+ // Set the uncountable early exit block in the VPTransformState.
7785+ State.CFG .UncountableEarlyExitBB = ILV.Legal ->getUncountableEarlyExitBlock ();
7786+
77777787 ILV.printDebugTracesAtStart ();
77787788
77797789 // ===------------------------------------------------===//
@@ -8958,6 +8968,9 @@ static void addScalarResumePhis(VPRecipeBuilder &Builder, VPlan &Plan) {
89588968 // start value provides the value if the loop is bypassed.
89598969 bool IsFOR = isa<VPFirstOrderRecurrencePHIRecipe>(VectorPhiR);
89608970 auto *ResumeFromVectorLoop = VectorPhiR->getBackedgeValue ();
8971+ assert (!Plan.getEarlyExit () &&
8972+ " Cannot handle reductions or first-order recurrences with "
8973+ " uncountable early exits" );
89618974 if (IsFOR)
89628975 ResumeFromVectorLoop = MiddleBuilder.createNaryOp (
89638976 VPInstruction::ExtractFromEnd, {ResumeFromVectorLoop, OneVPV}, {},
@@ -9075,14 +9088,20 @@ collectUsersInExitBlocks(Loop *OrigLoop, VPRecipeBuilder &Builder,
90759088// Add exit values to \p Plan. Extracts are added for each entry in \p
90769089// ExitUsersToFix if needed and their operands are updated. Returns true if all
90779090// exit users can be handled, otherwise return false.
9078- static bool
9091+ static void
90799092addUsersInExitBlocks (VPlan &Plan,
90809093 const SetVector<VPIRInstruction *> &ExitUsersToFix) {
90819094 if (ExitUsersToFix.empty ())
9082- return true ;
9095+ return ;
90839096
90849097 auto *MiddleVPBB = Plan.getMiddleBlock ();
9085- VPBuilder B (MiddleVPBB, MiddleVPBB->getFirstNonPhi ());
9098+ VPBuilder MiddleB (MiddleVPBB, MiddleVPBB->getFirstNonPhi ());
9099+ VPBuilder EarlyExitB;
9100+ VPBasicBlock *VectorEarlyExitVPBB = Plan.getEarlyExit ();
9101+ VPValue *EarlyExitMask = nullptr ;
9102+ if (VectorEarlyExitVPBB)
9103+ EarlyExitB.setInsertPoint (VectorEarlyExitVPBB,
9104+ VectorEarlyExitVPBB->getFirstNonPhi ());
90869105
90879106 // Introduce extract for exiting values and update the VPIRInstructions
90889107 // modeling the corresponding LCSSA phis.
@@ -9093,19 +9112,38 @@ addUsersInExitBlocks(VPlan &Plan,
90939112 if (Op->isLiveIn ())
90949113 continue ;
90959114
9096- // Currently only live-ins can be used by exit values from blocks not
9097- // exiting via the vector latch through to the middle block.
9098- if (ExitIRI->getParent ()->getSinglePredecessor () != MiddleVPBB)
9099- return false ;
9100-
91019115 LLVMContext &Ctx = ExitIRI->getInstruction ().getContext ();
9102- VPValue *Ext = B.createNaryOp (VPInstruction::ExtractFromEnd,
9103- {Op, Plan.getOrAddLiveIn (ConstantInt::get (
9104- IntegerType::get (Ctx, 32 ), 1 ))});
9116+ VPValue *Ext;
9117+ VPBasicBlock *PredVPBB =
9118+ cast<VPBasicBlock>(ExitIRI->getParent ()->getPredecessors ()[Idx]);
9119+ if (PredVPBB != MiddleVPBB) {
9120+ assert (ExitIRI->getParent ()->getNumPredecessors () <= 2 );
9121+
9122+ // Cache the early exit mask
9123+ if (!EarlyExitMask) {
9124+ VPBasicBlock *MiddleSplitVPBB =
9125+ cast<VPBasicBlock>(VectorEarlyExitVPBB->getSinglePredecessor ());
9126+ VPInstruction *PredTerm =
9127+ cast<VPInstruction>(MiddleSplitVPBB->getTerminator ());
9128+ assert (PredTerm->getOpcode () == VPInstruction::BranchOnCond &&
9129+ " Unexpected middle split block terminator" );
9130+ VPInstruction *ScalarCond =
9131+ cast<VPInstruction>(PredTerm->getOperand (0 ));
9132+ assert (
9133+ ScalarCond->getOpcode () == VPInstruction::AnyOf &&
9134+ " Unexpected condition for middle split block terminator branch" );
9135+ EarlyExitMask = ScalarCond->getOperand (0 );
9136+ }
9137+ Ext = EarlyExitB.createNaryOp (VPInstruction::ExtractFirstActive,
9138+ {Op, EarlyExitMask});
9139+ } else {
9140+ Ext = MiddleB.createNaryOp (VPInstruction::ExtractFromEnd,
9141+ {Op, Plan.getOrAddLiveIn (ConstantInt::get (
9142+ IntegerType::get (Ctx, 32 ), 1 ))});
9143+ }
91059144 ExitIRI->setOperand (Idx, Ext);
91069145 }
91079146 }
9108- return true ;
91099147}
91109148
91119149// / Handle users in the exit block for first order reductions in the original
@@ -9401,12 +9439,7 @@ LoopVectorizationPlanner::tryToBuildVPlanWithVPRecipes(VFRange &Range) {
94019439 SetVector<VPIRInstruction *> ExitUsersToFix =
94029440 collectUsersInExitBlocks (OrigLoop, RecipeBuilder, *Plan);
94039441 addExitUsersForFirstOrderRecurrences (*Plan, ExitUsersToFix);
9404- if (!addUsersInExitBlocks (*Plan, ExitUsersToFix)) {
9405- reportVectorizationFailure (
9406- " Some exit values in loop with uncountable exit not supported yet" ,
9407- " UncountableEarlyExitLoopsUnsupportedExitValue" , ORE, OrigLoop);
9408- return nullptr ;
9409- }
9442+ addUsersInExitBlocks (*Plan, ExitUsersToFix);
94109443
94119444 // ---------------------------------------------------------------------------
94129445 // Transform initial VPlan: Apply previously taken decisions, in order, to
0 commit comments