@@ -1590,3 +1590,122 @@ bool InductionDescriptor::isInductionPHI(
15901590 D = InductionDescriptor (StartValue, IK_PtrInduction, Step);
15911591 return true ;
15921592}
1593+
1594+ bool MonotonicDescriptor::setSCEV (const SCEV *NewExpr) {
1595+ auto *AddRec = dyn_cast<SCEVAddRecExpr>(NewExpr);
1596+ if (!AddRec || !AddRec->isAffine ())
1597+ return false ;
1598+ Expr = AddRec;
1599+ return true ;
1600+ }
1601+
1602+ // Recognize monotonic phi variable by matching the following pattern:
1603+ // loop_header:
1604+ // %monotonic_phi = [%start, %preheader], [%chain_phi0, %latch]
1605+ //
1606+ // step_bb:
1607+ // %step = add/gep %monotonic_phi, %step_val
1608+ //
1609+ // bbN:
1610+ // %chain_phiN = [%monotonic_phi, ], [%step, ]
1611+ //
1612+ // ...
1613+ //
1614+ // bb1:
1615+ // %chain_phi1 = [%monotonic_phi, ], [%chain_phi2, ]
1616+ //
1617+ // latch:
1618+ // %chain_phi0 = [%monotonic_phi, %pred], [%chain_phi1, %pred]
1619+ //
1620+ // For this pattern, monotonic phi is described by {%start, +, %step} recurrence
1621+ // and predicate is CFG edge %step_bb -> %bbN.
1622+ bool MonotonicDescriptor::isMonotonicPHI (PHINode *PN, const Loop *L,
1623+ MonotonicDescriptor &Desc,
1624+ ScalarEvolution &SE) {
1625+ if (!PN->getType ()->isIntOrPtrTy () || PN->getParent () != L->getHeader ())
1626+ return false ;
1627+ auto *BackEdgeInst =
1628+ dyn_cast<PHINode>(PN->getIncomingValueForBlock (L->getLoopLatch ()));
1629+ if (!BackEdgeInst)
1630+ return false ;
1631+ SmallVector<PHINode *, 4 > Worklist{BackEdgeInst};
1632+ std::optional<std::pair<Edge, Value *>> Inc;
1633+ while (!Worklist.empty ()) {
1634+ auto *Phi = Worklist.pop_back_val ();
1635+ Desc.Chain .insert (Phi);
1636+ for (unsigned I = 0 , E = Phi->getNumOperands (); I != E; ++I) {
1637+ auto *IncomingVal = Phi->getIncomingValue (I);
1638+ if (IncomingVal == PN)
1639+ continue ;
1640+ if (!IncomingVal->hasOneUse ())
1641+ return false ;
1642+ if (auto *IncomingPhi = dyn_cast<PHINode>(IncomingVal)) {
1643+ Worklist.push_back (IncomingPhi);
1644+ continue ;
1645+ }
1646+ if (Inc)
1647+ return false ;
1648+ Inc = std::make_pair (Edge{Phi->getIncomingBlock (I), Phi->getParent ()},
1649+ IncomingVal);
1650+ }
1651+ }
1652+ if (!Inc)
1653+ return false ;
1654+ auto [PredEdge, StepOp] = *Inc;
1655+ auto *StepInst = dyn_cast<Instruction>(StepOp);
1656+ if (!StepInst)
1657+ return false ;
1658+ Desc.StepInst = StepInst;
1659+ Desc.PredEdge = PredEdge;
1660+
1661+ // Construct SCEVAddRec for this value.
1662+ Value *Start = PN->getIncomingValueForBlock (L->getLoopPreheader ());
1663+
1664+ Value *Step = nullptr ;
1665+ bool StepMatch =
1666+ PN->getType ()->isPointerTy ()
1667+ ? match (StepInst, m_PtrAdd (m_Specific (PN), m_Value (Step)))
1668+ : match (StepInst, m_Add (m_Specific (PN), m_Value (Step)));
1669+ if (!StepMatch || !L->isLoopInvariant (Step))
1670+ return false ;
1671+
1672+ SCEV::NoWrapFlags WrapFlags = SCEV::FlagAnyWrap;
1673+ if (auto *GEP = dyn_cast<GEPOperator>(StepInst)) {
1674+ if (GEP->hasNoUnsignedWrap ())
1675+ WrapFlags = ScalarEvolution::setFlags (WrapFlags, SCEV::FlagNUW);
1676+ if (GEP->hasNoUnsignedSignedWrap ())
1677+ WrapFlags = ScalarEvolution::setFlags (WrapFlags, SCEV::FlagNSW);
1678+ } else if (auto *OBO = dyn_cast<OverflowingBinaryOperator>(StepInst)) {
1679+ if (OBO->hasNoUnsignedWrap ())
1680+ WrapFlags = ScalarEvolution::setFlags (WrapFlags, SCEV::FlagNUW);
1681+ if (OBO->hasNoSignedWrap ())
1682+ WrapFlags = ScalarEvolution::setFlags (WrapFlags, SCEV::FlagNSW);
1683+ }
1684+
1685+ return Desc.setSCEV (
1686+ SE.getAddRecExpr (SE.getSCEV (Start), SE.getSCEV (Step), L, WrapFlags));
1687+ }
1688+
1689+ bool MonotonicDescriptor::isMonotonicVal (Value *Val, const Loop *L,
1690+ MonotonicDescriptor &Desc,
1691+ ScalarEvolution &SE) {
1692+ if (!Val->getType ()->isIntOrPtrTy () || L->isLoopInvariant (Val))
1693+ return false ;
1694+ auto *CurInst = cast<Instruction>(Val);
1695+
1696+ auto NonInvariantVal = [&](Value *V, bool AllowRepeats) {
1697+ return L->isLoopInvariant (V) ? nullptr : cast<Instruction>(V);
1698+ };
1699+
1700+ while (!isa<PHINode>(CurInst)) {
1701+ CurInst = find_singleton<Instruction>(CurInst->operands (), NonInvariantVal);
1702+ if (!CurInst)
1703+ return false ;
1704+ };
1705+
1706+ if (!isMonotonicPHI (cast<PHINode>(CurInst), L, Desc, SE))
1707+ return false ;
1708+
1709+ ValueToSCEVMapTy Map{{CurInst, Desc.getExpr ()}};
1710+ return Desc.setSCEV (SCEVParameterRewriter::rewrite (SE.getSCEV (Val), SE, Map));
1711+ }
0 commit comments