@@ -1014,18 +1014,27 @@ bool VPlanTransforms::handleMultiUseReductions(VPlan &Plan) {
10141014 if (!MinMaxPhiR || !MinMaxPhiR->hasLoopUsesOutsideReductionChain ())
10151015 continue ;
10161016
1017+ // MinMaxPhiR has users outside the reduction cycle in the loop. Check if
1018+ // the only other user is a FindLastIV reduction. MinMaxPhiR must have
1019+ // exactly 3 users: 1) the min/max operation, the compare of a FindLastIV
1020+ // reduction and ComputeReductionResult. The comparisom must compare
1021+ // MinMaxPhiR against the min/max operand used for the min/max reduction
1022+ // and only be used by the select of the FindLastIV reduction.
10171023 RecurKind RdxKind = MinMaxPhiR->getRecurrenceKind ();
10181024 assert (
10191025 RecurrenceDescriptor::isIntMinMaxRecurrenceKind (RdxKind) &&
10201026 " only min/max recurrences support users outside the reduction chain" );
10211027
1022- // One user of MinMaxPhiR is MinMaxOp, the other user must be a compare
1023- // that's part of a FindLastIV chain.
10241028 auto *MinMaxOp =
10251029 dyn_cast<VPRecipeWithIRFlags>(MinMaxPhiR->getBackedgeValue ());
1026- if (!MinMaxOp || MinMaxOp-> getNumUsers () != 2 )
1030+ if (!MinMaxOp)
10271031 return false ;
10281032
1033+ // MinMaxOp must have 2 users: 1) MinMaxPhiR and 2) ComputeReductionResult
1034+ // (asserted below).
1035+ assert (MinMaxOp->getNumUsers () == 2 &&
1036+ " MinMaxOp must have exactly 2 users" );
1037+
10291038 assert ((isa<VPWidenIntrinsicRecipe>(MinMaxOp) ||
10301039 (isa<VPReplicateRecipe>(MinMaxOp) &&
10311040 isa<IntrinsicInst>(
@@ -1035,8 +1044,8 @@ bool VPlanTransforms::handleMultiUseReductions(VPlan &Plan) {
10351044 VPValue *MinMaxOpB = MinMaxOp->getOperand (1 );
10361045 if (MinMaxOpA != MinMaxPhiR)
10371046 std::swap (MinMaxOpA, MinMaxOpB);
1038- if (MinMaxOpA != MinMaxPhiR)
1039- return false ;
1047+ assert (MinMaxOpA == MinMaxPhiR &&
1048+ " one of MinMaxOp's operands must be the phi " ) ;
10401049
10411050 VPValue *CmpOpA;
10421051 VPValue *CmpOpB;
@@ -1047,16 +1056,31 @@ bool VPlanTransforms::handleMultiUseReductions(VPlan &Plan) {
10471056 (CmpOpA != MinMaxOpB && CmpOpB != MinMaxOpB))
10481057 return false ;
10491058
1059+ // MinMaxPhiR must have exactly 3 users:
1060+ // * MinMaxOp,
1061+ // * Cmp (that's part of a FindLastIV chain),
1062+ // * ComputeReductionResult.
1063+ if (MinMaxPhiR->getNumUsers () != 3 )
1064+ return false ;
1065+
1066+ VPInstruction *MinMaxResult =
1067+ findUserOf<VPInstruction::ComputeReductionResult>(MinMaxPhiR);
1068+ assert (is_contained (MinMaxPhiR->users (), MinMaxOp) &&
1069+ " one user must be MinMaxOp" );
1070+ assert (is_contained (MinMaxPhiR->users (), Cmp) && " one user must be Cmp" );
1071+ assert (is_contained (MinMaxPhiR->users (), MinMaxResult) &&
1072+ " one user must be MinMaxResult" );
1073+ assert (is_contained (MinMaxOp->users (), MinMaxPhiR) &&
1074+ " one user must be MinMaxPhiR" );
1075+ assert (is_contained (MinMaxOp->users (), MinMaxResult) &&
1076+ " one user must be MinMaxResult" );
1077+
10501078 // TODO: Strict predicates need to find the first IV value for which the
10511079 // predicate holds, not the last.
10521080 if (Pred == CmpInst::ICMP_EQ || Pred == CmpInst::ICMP_NE ||
10531081 ICmpInst::isLT (Pred) || ICmpInst::isGT (Pred))
10541082 return false ;
10551083
1056- // Normalize the predicate so MinMaxPhiR is on the right side.
1057- if (CmpOpA == MinMaxPhiR)
1058- Pred = CmpInst::getSwappedPredicate (Pred);
1059-
10601084 // Cmp must be used by the select of a FindLastIV chain.
10611085 VPValue *Sel = dyn_cast<VPSingleDefRecipe>(Cmp->getSingleUser ());
10621086 VPValue *IVOp, *FindIV;
@@ -1079,23 +1103,39 @@ bool VPlanTransforms::handleMultiUseReductions(VPlan &Plan) {
10791103 // The reduction using MinMaxPhiR needs adjusting to compute the correct
10801104 // result:
10811105 // 1. We need to find the last IV for which the condition based on the
1082- // min/max recurrence is true,
1106+ // min/max recurrence is true,
10831107 // 2. Compare the partial min/max reduction result to its final value and,
10841108 // 3. Select the lanes of the partial FindLastIV reductions which
1085- // correspond to the lanes matching the min/max reduction result.
1109+ // correspond to the lanes matching the min/max reduction result.
1110+ //
1111+ // For example, this transforms
1112+ // vp<%min.result> = compute-reduction-result ir<%min.val>,
1113+ // ir<%min.val.next>
1114+ // vp<%find.iv.result = compute-find-iv-result ir<%min.idx>, ir<0>,
1115+ // SENTINEL, vp<%min.idx.next>
1116+ //
1117+ // into:
1118+ //
1119+ // vp<min.result> = compute-reduction-result ir<%min.val>, ir<%min.val.next>
1120+ // vp<%final.min.cmp> = icmp eq ir<%min.val.next>, vp<min.result>
1121+ // vp<%final.iv> = select vp<%final.min.cmp>, ir<%min.idx.next>, SENTINEL
1122+ // vp<%find.iv.result> = compute-find-iv-result ir<%min.idx>, ir<0>,
1123+ // SENTINEL, vp<%final.iv>
10861124 VPInstruction *FindIVResult =
10871125 findUserOf<VPInstruction::ComputeFindIVResult>(FindIVPhiR);
1088- VPInstruction * MinMaxResult =
1089- findUserOf<VPInstruction::ComputeReductionResult>(MinMaxPhiR );
1126+ assert (FindIVResult-> getParent () == MinMaxResult-> getParent () &&
1127+ " both results must be computed in the same block " );
10901128 MinMaxResult->moveBefore (*FindIVResult->getParent (),
10911129 FindIVResult->getIterator ());
10921130
10931131 VPBuilder B (FindIVResult);
1094- auto *FinalMinMaxCmp = B.createICmp (
1095- CmpInst::ICMP_EQ, MinMaxResult->getOperand (1 ), MinMaxResult);
1132+ VPValue *MinMaxExiting = MinMaxResult->getOperand (1 );
1133+ auto *FinalMinMaxCmp =
1134+ B.createICmp (CmpInst::ICMP_EQ, MinMaxExiting, MinMaxResult);
1135+ VPValue *Sentinel = FindIVResult->getOperand (2 );
1136+ VPValue *LastIVExiting = FindIVResult->getOperand (3 );
10961137 auto *FinalIVSelect =
1097- B.createSelect (FinalMinMaxCmp, FindIVResult->getOperand (3 ),
1098- FindIVResult->getOperand (2 ));
1138+ B.createSelect (FinalMinMaxCmp, LastIVExiting, Sentinel);
10991139 FindIVResult->setOperand (3 , FinalIVSelect);
11001140 }
11011141 return true ;
0 commit comments