@@ -51,6 +51,8 @@ bool RecurrenceDescriptor::isIntegerRecurrenceKind(RecurKind Kind) {
5151 case RecurKind::UMin:
5252 case RecurKind::IAnyOf:
5353 case RecurKind::FAnyOf:
54+ case RecurKind::IFindLastIV:
55+ case RecurKind::FFindLastIV:
5456 return true ;
5557 }
5658 return false ;
@@ -372,7 +374,7 @@ bool RecurrenceDescriptor::AddReductionVar(
372374 // type-promoted).
373375 if (Cur != Start) {
374376 ReduxDesc =
375- isRecurrenceInstr (TheLoop, Phi, Cur, Kind, ReduxDesc, FuncFMF);
377+ isRecurrenceInstr (TheLoop, Phi, Cur, Kind, ReduxDesc, FuncFMF, SE );
376378 ExactFPMathInst = ExactFPMathInst == nullptr
377379 ? ReduxDesc.getExactFPMathInst ()
378380 : ExactFPMathInst;
@@ -658,6 +660,95 @@ RecurrenceDescriptor::isAnyOfPattern(Loop *Loop, PHINode *OrigPhi,
658660 : RecurKind::FAnyOf);
659661}
660662
663+ // We are looking for loops that do something like this:
664+ // int r = 0;
665+ // for (int i = 0; i < n; i++) {
666+ // if (src[i] > 3)
667+ // r = i;
668+ // }
669+ // The reduction value (r) is derived from either the values of an increasing
670+ // induction variable (i) sequence, or from the start value (0).
671+ // The LLVM IR generated for such loops would be as follows:
672+ // for.body:
673+ // %r = phi i32 [ %spec.select, %for.body ], [ 0, %entry ]
674+ // %i = phi i32 [ %inc, %for.body ], [ 0, %entry ]
675+ // ...
676+ // %cmp = icmp sgt i32 %5, 3
677+ // %spec.select = select i1 %cmp, i32 %i, i32 %r
678+ // %inc = add nsw i32 %i, 1
679+ // ...
680+ // Since 'i' is an increasing induction variable, the reduction value after the
681+ // loop will be the maximum value of 'i' that the condition (src[i] > 3) is
682+ // satisfied, or the start value (0 in the example above). When the start value
683+ // of the increasing induction variable 'i' is greater than the minimum value of
684+ // the data type, we can use the minimum value of the data type as a sentinel
685+ // value to replace the start value. This allows us to perform a single
686+ // reduction max operation to obtain the final reduction result.
687+ // TODO: It is possible to solve the case where the start value is the minimum
688+ // value of the data type or a non-constant value by using mask and multiple
689+ // reduction operations.
690+ RecurrenceDescriptor::InstDesc
691+ RecurrenceDescriptor::isFindLastIVPattern (Loop *TheLoop, PHINode *OrigPhi,
692+ Instruction *I, ScalarEvolution &SE) {
693+ // TODO: Support the vectorization of FindLastIV when the reduction phi is
694+ // used by more than one select instruction. This vectorization is only
695+ // performed when the SCEV of each increasing induction variable used by the
696+ // select instructions is identical.
697+ if (!OrigPhi->hasOneUse ())
698+ return InstDesc (false , I);
699+
700+ // TODO: Match selects with multi-use cmp conditions.
701+ Value *NonRdxPhi = nullptr ;
702+ if (!match (I, m_CombineOr (m_Select (m_OneUse (m_Cmp ()), m_Value (NonRdxPhi),
703+ m_Specific (OrigPhi)),
704+ m_Select (m_OneUse (m_Cmp ()), m_Specific (OrigPhi),
705+ m_Value (NonRdxPhi)))))
706+ return InstDesc (false , I);
707+
708+ auto IsIncreasingLoopInduction = [&](Value *V) {
709+ Type *Ty = V->getType ();
710+ if (!SE.isSCEVable (Ty))
711+ return false ;
712+
713+ auto *AR = dyn_cast<SCEVAddRecExpr>(SE.getSCEV (V));
714+ if (!AR || AR->getLoop () != TheLoop)
715+ return false ;
716+
717+ const SCEV *Step = AR->getStepRecurrence (SE);
718+ if (!SE.isKnownPositive (Step))
719+ return false ;
720+
721+ const ConstantRange IVRange = SE.getSignedRange (AR);
722+ unsigned NumBits = Ty->getIntegerBitWidth ();
723+ // Keep the minimum value of the recurrence type as the sentinel value.
724+ // The maximum acceptable range for the increasing induction variable,
725+ // called the valid range, will be defined as
726+ // [<sentinel value> + 1, <sentinel value>)
727+ // where <sentinel value> is SignedMin(<recurrence type>)
728+ // TODO: This range restriction can be lifted by adding an additional
729+ // virtual OR reduction.
730+ const APInt Sentinel = APInt::getSignedMinValue (NumBits);
731+ const ConstantRange ValidRange =
732+ ConstantRange::getNonEmpty (Sentinel + 1 , Sentinel);
733+ LLVM_DEBUG (dbgs () << " LV: FindLastIV valid range is " << ValidRange
734+ << " , and the signed range of " << *AR << " is "
735+ << IVRange << " \n " );
736+ // Ensure the induction variable does not wrap around by verifying that its
737+ // range is fully contained within the valid range.
738+ return ValidRange.contains (IVRange);
739+ };
740+
741+ // We are looking for selects of the form:
742+ // select(cmp(), phi, increasing_loop_induction) or
743+ // select(cmp(), increasing_loop_induction, phi)
744+ // TODO: Support for monotonically decreasing induction variable
745+ if (!IsIncreasingLoopInduction (NonRdxPhi))
746+ return InstDesc (false , I);
747+
748+ return InstDesc (I, isa<ICmpInst>(I->getOperand (0 )) ? RecurKind::IFindLastIV
749+ : RecurKind::FFindLastIV);
750+ }
751+
661752RecurrenceDescriptor::InstDesc
662753RecurrenceDescriptor::isMinMaxPattern (Instruction *I, RecurKind Kind,
663754 const InstDesc &Prev) {
@@ -756,10 +847,9 @@ RecurrenceDescriptor::isConditionalRdxPattern(RecurKind Kind, Instruction *I) {
756847 return InstDesc (true , SI);
757848}
758849
759- RecurrenceDescriptor::InstDesc
760- RecurrenceDescriptor::isRecurrenceInstr (Loop *L, PHINode *OrigPhi,
761- Instruction *I, RecurKind Kind,
762- InstDesc &Prev, FastMathFlags FuncFMF) {
850+ RecurrenceDescriptor::InstDesc RecurrenceDescriptor::isRecurrenceInstr (
851+ Loop *L, PHINode *OrigPhi, Instruction *I, RecurKind Kind, InstDesc &Prev,
852+ FastMathFlags FuncFMF, ScalarEvolution *SE) {
763853 assert (Prev.getRecKind () == RecurKind::None || Prev.getRecKind () == Kind);
764854 switch (I->getOpcode ()) {
765855 default :
@@ -789,6 +879,8 @@ RecurrenceDescriptor::isRecurrenceInstr(Loop *L, PHINode *OrigPhi,
789879 if (Kind == RecurKind::FAdd || Kind == RecurKind::FMul ||
790880 Kind == RecurKind::Add || Kind == RecurKind::Mul)
791881 return isConditionalRdxPattern (Kind, I);
882+ if (isFindLastIVRecurrenceKind (Kind) && SE)
883+ return isFindLastIVPattern (L, OrigPhi, I, *SE);
792884 [[fallthrough]];
793885 case Instruction::FCmp:
794886 case Instruction::ICmp:
@@ -893,6 +985,15 @@ bool RecurrenceDescriptor::isReductionPHI(PHINode *Phi, Loop *TheLoop,
893985 << *Phi << " \n " );
894986 return true ;
895987 }
988+ if (AddReductionVar (Phi, RecurKind::IFindLastIV, TheLoop, FMF, RedDes, DB, AC,
989+ DT, SE)) {
990+ LLVM_DEBUG (dbgs () << " Found a "
991+ << (RedDes.getRecurrenceKind () == RecurKind::FFindLastIV
992+ ? " F"
993+ : " I" )
994+ << " FindLastIV reduction PHI." << *Phi << " \n " );
995+ return true ;
996+ }
896997 if (AddReductionVar (Phi, RecurKind::FMul, TheLoop, FMF, RedDes, DB, AC, DT,
897998 SE)) {
898999 LLVM_DEBUG (dbgs () << " Found an FMult reduction PHI." << *Phi << " \n " );
@@ -1048,12 +1149,14 @@ unsigned RecurrenceDescriptor::getOpcode(RecurKind Kind) {
10481149 case RecurKind::UMax:
10491150 case RecurKind::UMin:
10501151 case RecurKind::IAnyOf:
1152+ case RecurKind::IFindLastIV:
10511153 return Instruction::ICmp;
10521154 case RecurKind::FMax:
10531155 case RecurKind::FMin:
10541156 case RecurKind::FMaximum:
10551157 case RecurKind::FMinimum:
10561158 case RecurKind::FAnyOf:
1159+ case RecurKind::FFindLastIV:
10571160 return Instruction::FCmp;
10581161 default :
10591162 llvm_unreachable (" Unknown recurrence operation" );
0 commit comments