@@ -2470,64 +2470,74 @@ void VPlanTransforms::convertToConcreteRecipes(VPlan &Plan,
24702470 R->eraseFromParent ();
24712471}
24722472
2473- void VPlanTransforms::handleUncountableEarlyExit (
2474- VPlan &Plan, Loop *OrigLoop, BasicBlock *UncountableExitingBlock,
2475- VPRecipeBuilder &RecipeBuilder, VFRange &Range) {
2473+ void VPlanTransforms::handleUncountableEarlyExit (VPlan &Plan, VFRange &Range) {
2474+ auto *MiddleVPBB = Plan.getMiddleBlock ();
2475+ // First find the uncountable early exiting block by looking at the
2476+ // predecessors of the exit blocks.
2477+ VPBasicBlock *EarlyExitingVPBB = nullptr ;
2478+ VPIRBasicBlock *EarlyExitVPBB = nullptr ;
2479+ for (auto *EB : Plan.getExitBlocks ()) {
2480+ for (VPBlockBase *Pred : EB->getPredecessors ()) {
2481+ if (Pred != MiddleVPBB) {
2482+ EarlyExitingVPBB = cast<VPBasicBlock>(Pred);
2483+ EarlyExitVPBB = EB;
2484+ break ;
2485+ }
2486+ }
2487+ }
2488+
24762489 VPRegionBlock *LoopRegion = Plan.getVectorLoopRegion ();
24772490 auto *LatchVPBB = cast<VPBasicBlock>(LoopRegion->getExiting ());
24782491 VPBuilder Builder (LatchVPBB->getTerminator ());
2479- auto *MiddleVPBB = Plan.getMiddleBlock ();
2480- VPValue *IsEarlyExitTaken = nullptr ;
2481-
2482- // Process the uncountable exiting block. Update IsEarlyExitTaken, which
2483- // tracks if the uncountable early exit has been taken. Also split the middle
2484- // block and have it conditionally branch to the early exit block if
2485- // EarlyExitTaken.
2486- auto *EarlyExitingBranch =
2487- cast<BranchInst>(UncountableExitingBlock->getTerminator ());
2488- BasicBlock *TrueSucc = EarlyExitingBranch->getSuccessor (0 );
2489- BasicBlock *FalseSucc = EarlyExitingBranch->getSuccessor (1 );
2490- BasicBlock *EarlyExitIRBB =
2491- !OrigLoop->contains (TrueSucc) ? TrueSucc : FalseSucc;
2492- VPIRBasicBlock *VPEarlyExitBlock = Plan.getExitBlock (EarlyExitIRBB);
2493-
2494- VPValue *EarlyExitNotTakenCond = RecipeBuilder.getBlockInMask (
2495- OrigLoop->contains (TrueSucc) ? TrueSucc : FalseSucc);
2496- auto *EarlyExitTakenCond = Builder.createNot (EarlyExitNotTakenCond);
2497- IsEarlyExitTaken =
2498- Builder.createNaryOp (VPInstruction::AnyOf, {EarlyExitTakenCond});
2492+ VPBlockBase *TrueSucc = EarlyExitingVPBB->getSuccessors ()[0 ];
2493+ VPValue *EarlyExitCond = EarlyExitingVPBB->getTerminator ()->getOperand (0 );
2494+ auto *EarlyExitTakenCond = TrueSucc == EarlyExitVPBB
2495+ ? EarlyExitCond
2496+ : Builder.createNot (EarlyExitCond);
2497+
2498+ if (!EarlyExitVPBB->getSinglePredecessor () &&
2499+ EarlyExitVPBB->getPredecessors ()[0 ] != MiddleVPBB) {
2500+ for (VPRecipeBase &R : EarlyExitVPBB->phis ()) {
2501+ // Early exit operand should always be last, i.e., 0 if EarlyExitVPBB has
2502+ // a single predecessor and 1 if it has two.
2503+ // If EarlyExitVPBB has two predecessors, they are already ordered such
2504+ // that early exit is second (and latch exit is first), by construction.
2505+ // But its underlying IRBB (EarlyExitIRBB) may have its predecessors
2506+ // ordered the other way around, and it is the order of the latter which
2507+ // corresponds to the order of operands of EarlyExitVPBB's phi recipes.
2508+ // Therefore, if early exit (UncountableExitingBlock) is the first
2509+ // predecessor of EarlyExitIRBB, we swap the operands of phi recipes,
2510+ // thereby bringing them to match EarlyExitVPBB's predecessor order,
2511+ // with early exit being last (second). Otherwise they already match.
2512+ cast<VPIRPhi>(&R)->swapOperands ();
2513+ }
2514+ }
24992515
2516+ EarlyExitingVPBB->getTerminator ()->eraseFromParent ();
2517+ VPBlockUtils::disconnectBlocks (EarlyExitingVPBB, EarlyExitVPBB);
2518+
2519+ // Split the middle block and have it conditionally branch to the early exit
2520+ // block if EarlyExitTaken.
2521+ VPValue *IsEarlyExitTaken =
2522+ Builder.createNaryOp (VPInstruction::AnyOf, {EarlyExitTakenCond});
25002523 VPBasicBlock *NewMiddle = Plan.createVPBasicBlock (" middle.split" );
25012524 VPBasicBlock *VectorEarlyExitVPBB =
25022525 Plan.createVPBasicBlock (" vector.early.exit" );
25032526 VPBlockUtils::insertOnEdge (LoopRegion, MiddleVPBB, NewMiddle);
25042527 VPBlockUtils::connectBlocks (NewMiddle, VectorEarlyExitVPBB);
25052528 NewMiddle->swapSuccessors ();
25062529
2507- VPBlockUtils::connectBlocks (VectorEarlyExitVPBB, VPEarlyExitBlock );
2530+ VPBlockUtils::connectBlocks (VectorEarlyExitVPBB, EarlyExitVPBB );
25082531
25092532 // Update the exit phis in the early exit block.
25102533 VPBuilder MiddleBuilder (NewMiddle);
25112534 VPBuilder EarlyExitB (VectorEarlyExitVPBB);
2512- for (VPRecipeBase &R : VPEarlyExitBlock ->phis ()) {
2535+ for (VPRecipeBase &R : EarlyExitVPBB ->phis ()) {
25132536 auto *ExitIRI = cast<VPIRPhi>(&R);
2514- // Early exit operand should always be last, i.e., 0 if VPEarlyExitBlock has
2537+ // Early exit operand should always be last, i.e., 0 if EarlyExitVPBB has
25152538 // a single predecessor and 1 if it has two.
25162539 unsigned EarlyExitIdx = ExitIRI->getNumOperands () - 1 ;
2517- if (!VPEarlyExitBlock->getSinglePredecessor ()) {
2518- // If VPEarlyExitBlock has two predecessors, they are already ordered such
2519- // that early exit is second (and latch exit is first), by construction.
2520- // But its underlying IRBB (EarlyExitIRBB) may have its predecessors
2521- // ordered the other way around, and it is the order of the latter which
2522- // corresponds to the order of operands of VPEarlyExitBlock's phi recipes.
2523- // Therefore, if early exit (UncountableExitingBlock) is the first
2524- // predecessor of EarlyExitIRBB, we swap the operands of phi recipes,
2525- // thereby bringing them to match VPEarlyExitBlock's predecessor order,
2526- // with early exit being last (second). Otherwise they already match.
2527- if (*pred_begin (VPEarlyExitBlock->getIRBasicBlock ()) ==
2528- UncountableExitingBlock)
2529- ExitIRI->swapOperands ();
2530-
2540+ if (!EarlyExitVPBB->getSinglePredecessor ()) {
25312541 // The first of two operands corresponds to the latch exit, via MiddleVPBB
25322542 // predecessor. Extract its last lane.
25332543 ExitIRI->extractLastLaneOfFirstOperand (MiddleBuilder);
0 commit comments