@@ -781,78 +781,83 @@ static bool hoistPreviousBeforeFORUsers(VPFirstOrderRecurrencePHIRecipe *FOR,
781781 return false ;
782782
783783 // Collect recipes that need hoisting.
784- SmallVector<VPRecipeBase *> WorkList ;
784+ SmallVector<VPRecipeBase *> HoistCandidates ;
785785 SmallPtrSet<VPRecipeBase *, 8 > Seen;
786- VPBasicBlock *HoistBlock = FOR->getParent ();
787- auto HoistPoint = HoistBlock->getFirstNonPhi ();
788- auto TryToPushHoistCandidate = [&](VPRecipeBase *HoistCandidate) {
789- // If we reach FOR, it means the original Previous depends on some other
790- // recurrence that in turn depends on FOR. If that is the case, we would
791- // also need to hoist recipes involving the other FOR, which may break
792- // dependencies.
793- if (HoistCandidate == FOR)
794- return false ;
795-
796- // Hoist candidate outside any region, no need to hoist.
797- if (!HoistCandidate->getParent ()->getParent ())
798- return true ;
799-
800- // Hoist candidate is a header phi or already visited, no need to hoist.
801- if (isa<VPHeaderPHIRecipe>(HoistCandidate) ||
802- !Seen.insert (HoistCandidate).second )
803- return true ;
786+ VPRecipeBase *HoistPoint = nullptr ;
787+ // Find the closest hoist point by looking at all users of FOR and selecting
788+ // the recipe dominating all other users.
789+ for (VPUser *U : FOR->users ()) {
790+ auto *R = dyn_cast<VPRecipeBase>(U);
791+ if (!R)
792+ continue ;
793+ if (!HoistPoint || VPDT.properlyDominates (R, HoistPoint))
794+ HoistPoint = R;
795+ }
804796
805- // If we reached a recipe that dominates all users of FOR, we don't need to
797+ auto NeedsHoisting = [HoistPoint, &VPDT,
798+ &Seen](VPValue *HoistCandidateV) -> VPRecipeBase * {
799+ VPRecipeBase *HoistCandidate = HoistCandidateV->getDefiningRecipe ();
800+ if (!HoistCandidate)
801+ return nullptr ;
802+ assert ((!HoistCandidate->getParent ()->getParent () ||
803+ HoistCandidate->getParent ()->getParent () ==
804+ HoistCandidate->getParent ()->getEnclosingLoopRegion ()) &&
805+ " CFG in VPlan should still be flattened, without replicate regions" );
806+ // Hoist candidate has already beend visited, no need to hoist.
807+ if (!Seen.insert (HoistCandidate).second )
808+ return nullptr ;
809+
810+ // Candidate is outside loop region or a header phi, dominates FOR users w/o
811+ // hoisting.
812+ if (!HoistCandidate->getParent ()->getEnclosingLoopRegion () ||
813+ isa<VPHeaderPHIRecipe>(HoistCandidate))
814+ return nullptr ;
815+
816+ // If we reached a recipe that dominates HoistPoint, we don't need to
806817 // hoist the recipe.
807- if (all_of (FOR->users (), [&VPDT, HoistCandidate](VPUser *U) {
808- return VPDT.properlyDominates (HoistCandidate, cast<VPRecipeBase>(U));
809- })) {
810- if (VPDT.properlyDominates (&*HoistPoint, HoistCandidate)) {
811- // This HoistCandidate domiantes all users of FOR and is closer to them
812- // than the previous HoistPoint.
813- HoistPoint = std::next (HoistCandidate->getIterator ());
814- HoistBlock = HoistCandidate->getParent ();
815- }
816- return true ;
817- }
818-
819- // Don't move candiates with sideeffects, as we do not yet analyze recipes
820- // between candidate and hoist destination yet.
821- if (HoistCandidate->mayHaveSideEffects ())
822- return false ;
823-
824- WorkList.push_back (HoistCandidate);
825- return true ;
818+ if (VPDT.properlyDominates (HoistCandidate, HoistPoint))
819+ return nullptr ;
820+ return HoistCandidate;
821+ };
822+ auto CanHoist = [&](VPRecipeBase *HoistCandidate) {
823+ // Avoid hoisting candidates with side-effects, as we do not yet analyze
824+ // associated dependencies.
825+ return !HoistCandidate->mayHaveSideEffects ();
826826 };
827827
828828 // Recursively try to hoist Previous and its operands before all users of FOR.
829- // Update HoistPoint to the closest recipe that dominates all users of FOR.
830- if (!TryToPushHoistCandidate (Previous))
831- return false ;
829+ if (NeedsHoisting (Previous->getVPSingleValue ()))
830+ HoistCandidates.push_back (Previous);
832831
833- for (unsigned I = 0 ; I != WorkList .size (); ++I) {
834- VPRecipeBase *Current = WorkList [I];
832+ for (unsigned I = 0 ; I != HoistCandidates .size (); ++I) {
833+ VPRecipeBase *Current = HoistCandidates [I];
835834 assert (Current->getNumDefinedValues () == 1 &&
836835 " only recipes with a single defined value expected" );
836+ if (!CanHoist (Current))
837+ return false ;
837838
838- for (VPValue *Op : Current->operands ())
839- if (auto *R = Op->getDefiningRecipe ())
840- if (!TryToPushHoistCandidate (R))
841- return false ;
839+ for (VPValue *Op : Current->operands ()) {
840+ // If we reach FOR, it means the original Previous depends on some other
841+ // recurrence that in turn depends on FOR. If that is the case, we would
842+ // also need to hoist recipes involving the other FOR, which may break
843+ // dependencies.
844+ if (Op == FOR)
845+ return false ;
846+
847+ if (auto *R = NeedsHoisting (Op))
848+ HoistCandidates.push_back (R);
849+ }
842850 }
843851
844852 // Keep recipes to hoist ordered by dominance so earlier instructions are
845853 // processed first.
846- sort (WorkList , [&VPDT](const VPRecipeBase *A, const VPRecipeBase *B) {
854+ sort (HoistCandidates , [&VPDT](const VPRecipeBase *A, const VPRecipeBase *B) {
847855 return VPDT.properlyDominates (A, B);
848856 });
849857
850- for (VPRecipeBase *HoistCandidate : WorkList) {
851- if (HoistPoint == HoistCandidate->getIterator ()) {
852- HoistPoint = std::next (HoistCandidate->getIterator ());
853- continue ;
854- }
855- HoistCandidate->moveBefore (*HoistBlock, HoistPoint);
858+ for (VPRecipeBase *HoistCandidate : HoistCandidates) {
859+ HoistCandidate->moveBefore (*HoistPoint->getParent (),
860+ HoistPoint->getIterator ());
856861 }
857862
858863 return true ;
@@ -881,9 +886,9 @@ bool VPlanTransforms::adjustFixedOrderRecurrences(VPlan &Plan,
881886 Previous = PrevPhi->getBackedgeValue ()->getDefiningRecipe ();
882887 }
883888
884- if (!sinkRecurrenceUsersAfterPrevious (FOR, Previous, VPDT))
885- if ( !hoistPreviousBeforeFORUsers (FOR, Previous, VPDT))
886- return false ;
889+ if (!sinkRecurrenceUsersAfterPrevious (FOR, Previous, VPDT) &&
890+ !hoistPreviousBeforeFORUsers (FOR, Previous, VPDT))
891+ return false ;
887892
888893 // Introduce a recipe to combine the incoming and previous values of a
889894 // fixed-order recurrence.
0 commit comments