xref: /aosp_15_r20/external/swiftshader/third_party/subzero/src/IceLoopAnalyzer.cpp (revision 03ce13f70fcc45d86ee91b7ee4cab1936a95046e)
1*03ce13f7SAndroid Build Coastguard Worker //===- subzero/src/IceLoopAnalyzer.cpp - Loop Analysis --------------------===//
2*03ce13f7SAndroid Build Coastguard Worker //
3*03ce13f7SAndroid Build Coastguard Worker //                        The Subzero Code Generator
4*03ce13f7SAndroid Build Coastguard Worker //
5*03ce13f7SAndroid Build Coastguard Worker // This file is distributed under the University of Illinois Open Source
6*03ce13f7SAndroid Build Coastguard Worker // License. See LICENSE.TXT for details.
7*03ce13f7SAndroid Build Coastguard Worker //
8*03ce13f7SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
9*03ce13f7SAndroid Build Coastguard Worker ///
10*03ce13f7SAndroid Build Coastguard Worker /// \file
11*03ce13f7SAndroid Build Coastguard Worker /// \brief Implements the loop analysis on the CFG.
12*03ce13f7SAndroid Build Coastguard Worker ///
13*03ce13f7SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
14*03ce13f7SAndroid Build Coastguard Worker #include "IceLoopAnalyzer.h"
15*03ce13f7SAndroid Build Coastguard Worker 
16*03ce13f7SAndroid Build Coastguard Worker #include "IceCfg.h"
17*03ce13f7SAndroid Build Coastguard Worker #include "IceCfgNode.h"
18*03ce13f7SAndroid Build Coastguard Worker 
19*03ce13f7SAndroid Build Coastguard Worker #include <algorithm>
20*03ce13f7SAndroid Build Coastguard Worker 
21*03ce13f7SAndroid Build Coastguard Worker namespace Ice {
22*03ce13f7SAndroid Build Coastguard Worker class LoopAnalyzer {
23*03ce13f7SAndroid Build Coastguard Worker public:
24*03ce13f7SAndroid Build Coastguard Worker   explicit LoopAnalyzer(Cfg *Func);
25*03ce13f7SAndroid Build Coastguard Worker 
26*03ce13f7SAndroid Build Coastguard Worker   /// Use Tarjan's strongly connected components algorithm to identify outermost
27*03ce13f7SAndroid Build Coastguard Worker   /// to innermost loops. By deleting the head of the loop from the graph, inner
28*03ce13f7SAndroid Build Coastguard Worker   /// loops can be found. This assumes that the head node is not shared between
29*03ce13f7SAndroid Build Coastguard Worker   /// loops but instead all paths to the head come from 'continue' constructs.
30*03ce13f7SAndroid Build Coastguard Worker   ///
31*03ce13f7SAndroid Build Coastguard Worker   /// This only computes the loop nest depth within the function and does not
32*03ce13f7SAndroid Build Coastguard Worker   /// take into account whether the function was called from within a loop.
33*03ce13f7SAndroid Build Coastguard Worker   // TODO(ascull): this currently uses a extension of Tarjan's algorithm with
34*03ce13f7SAndroid Build Coastguard Worker   // is bounded linear. ncbray suggests another algorithm which is linear in
35*03ce13f7SAndroid Build Coastguard Worker   // practice but not bounded linear. I think it also finds dominators.
36*03ce13f7SAndroid Build Coastguard Worker   // http://lenx.100871.net/papers/loop-SAS.pdf
37*03ce13f7SAndroid Build Coastguard Worker 
getLoopBodies()38*03ce13f7SAndroid Build Coastguard Worker   CfgVector<CfgUnorderedSet<SizeT>> getLoopBodies() { return Loops; }
39*03ce13f7SAndroid Build Coastguard Worker 
40*03ce13f7SAndroid Build Coastguard Worker private:
41*03ce13f7SAndroid Build Coastguard Worker   LoopAnalyzer() = delete;
42*03ce13f7SAndroid Build Coastguard Worker   LoopAnalyzer(const LoopAnalyzer &) = delete;
43*03ce13f7SAndroid Build Coastguard Worker   LoopAnalyzer &operator=(const LoopAnalyzer &) = delete;
44*03ce13f7SAndroid Build Coastguard Worker   void computeLoopNestDepth();
45*03ce13f7SAndroid Build Coastguard Worker 
46*03ce13f7SAndroid Build Coastguard Worker   using IndexT = uint32_t;
47*03ce13f7SAndroid Build Coastguard Worker   static constexpr IndexT UndefinedIndex = 0;
48*03ce13f7SAndroid Build Coastguard Worker   static constexpr IndexT FirstDefinedIndex = 1;
49*03ce13f7SAndroid Build Coastguard Worker 
50*03ce13f7SAndroid Build Coastguard Worker   // TODO(ascull): classify the other fields
51*03ce13f7SAndroid Build Coastguard Worker   class LoopNode {
52*03ce13f7SAndroid Build Coastguard Worker     LoopNode() = delete;
53*03ce13f7SAndroid Build Coastguard Worker     LoopNode operator=(const LoopNode &) = delete;
54*03ce13f7SAndroid Build Coastguard Worker 
55*03ce13f7SAndroid Build Coastguard Worker   public:
LoopNode(CfgNode * BB)56*03ce13f7SAndroid Build Coastguard Worker     explicit LoopNode(CfgNode *BB) : BB(BB) { reset(); }
57*03ce13f7SAndroid Build Coastguard Worker     LoopNode(const LoopNode &) = default;
58*03ce13f7SAndroid Build Coastguard Worker 
59*03ce13f7SAndroid Build Coastguard Worker     void reset();
60*03ce13f7SAndroid Build Coastguard Worker 
61*03ce13f7SAndroid Build Coastguard Worker     NodeList::const_iterator successorsEnd() const;
currentSuccessor() const62*03ce13f7SAndroid Build Coastguard Worker     NodeList::const_iterator currentSuccessor() const { return Succ; }
nextSuccessor()63*03ce13f7SAndroid Build Coastguard Worker     void nextSuccessor() { ++Succ; }
64*03ce13f7SAndroid Build Coastguard Worker 
visit(IndexT VisitIndex)65*03ce13f7SAndroid Build Coastguard Worker     void visit(IndexT VisitIndex) { Index = LowLink = VisitIndex; }
isVisited() const66*03ce13f7SAndroid Build Coastguard Worker     bool isVisited() const { return Index != UndefinedIndex; }
getIndex() const67*03ce13f7SAndroid Build Coastguard Worker     IndexT getIndex() const { return Index; }
68*03ce13f7SAndroid Build Coastguard Worker 
tryLink(IndexT NewLink)69*03ce13f7SAndroid Build Coastguard Worker     void tryLink(IndexT NewLink) {
70*03ce13f7SAndroid Build Coastguard Worker       if (NewLink < LowLink)
71*03ce13f7SAndroid Build Coastguard Worker         LowLink = NewLink;
72*03ce13f7SAndroid Build Coastguard Worker     }
getLowLink() const73*03ce13f7SAndroid Build Coastguard Worker     IndexT getLowLink() const { return LowLink; }
74*03ce13f7SAndroid Build Coastguard Worker 
setOnStack(bool NewValue=true)75*03ce13f7SAndroid Build Coastguard Worker     void setOnStack(bool NewValue = true) { OnStack = NewValue; }
isOnStack() const76*03ce13f7SAndroid Build Coastguard Worker     bool isOnStack() const { return OnStack; }
77*03ce13f7SAndroid Build Coastguard Worker 
setDeleted()78*03ce13f7SAndroid Build Coastguard Worker     void setDeleted() { Deleted = true; }
isDeleted() const79*03ce13f7SAndroid Build Coastguard Worker     bool isDeleted() const { return Deleted; }
80*03ce13f7SAndroid Build Coastguard Worker 
81*03ce13f7SAndroid Build Coastguard Worker     void incrementLoopNestDepth();
82*03ce13f7SAndroid Build Coastguard Worker     bool hasSelfEdge() const;
83*03ce13f7SAndroid Build Coastguard Worker 
getNode()84*03ce13f7SAndroid Build Coastguard Worker     CfgNode *getNode() { return BB; }
85*03ce13f7SAndroid Build Coastguard Worker 
86*03ce13f7SAndroid Build Coastguard Worker   private:
87*03ce13f7SAndroid Build Coastguard Worker     CfgNode *BB;
88*03ce13f7SAndroid Build Coastguard Worker     NodeList::const_iterator Succ;
89*03ce13f7SAndroid Build Coastguard Worker     IndexT Index;
90*03ce13f7SAndroid Build Coastguard Worker     IndexT LowLink;
91*03ce13f7SAndroid Build Coastguard Worker     bool OnStack;
92*03ce13f7SAndroid Build Coastguard Worker     bool Deleted = false;
93*03ce13f7SAndroid Build Coastguard Worker   };
94*03ce13f7SAndroid Build Coastguard Worker 
95*03ce13f7SAndroid Build Coastguard Worker   using LoopNodeList = CfgVector<LoopNode>;
96*03ce13f7SAndroid Build Coastguard Worker   using LoopNodePtrList = CfgVector<LoopNode *>;
97*03ce13f7SAndroid Build Coastguard Worker 
98*03ce13f7SAndroid Build Coastguard Worker   /// Process the node as part as part of Tarjan's algorithm and return either a
99*03ce13f7SAndroid Build Coastguard Worker   /// node to recurse into or nullptr when the node has been fully processed.
100*03ce13f7SAndroid Build Coastguard Worker   LoopNode *processNode(LoopNode &Node);
101*03ce13f7SAndroid Build Coastguard Worker 
102*03ce13f7SAndroid Build Coastguard Worker   /// The function to analyze for loops.
103*03ce13f7SAndroid Build Coastguard Worker   Cfg *const Func;
104*03ce13f7SAndroid Build Coastguard Worker   /// A list of decorated nodes in the same order as Func->getNodes() which
105*03ce13f7SAndroid Build Coastguard Worker   /// means the node's index will also be valid in this list.
106*03ce13f7SAndroid Build Coastguard Worker   LoopNodeList AllNodes;
107*03ce13f7SAndroid Build Coastguard Worker   /// This is used as a replacement for the call stack.
108*03ce13f7SAndroid Build Coastguard Worker   LoopNodePtrList WorkStack;
109*03ce13f7SAndroid Build Coastguard Worker   /// Track which loop a node belongs to.
110*03ce13f7SAndroid Build Coastguard Worker   LoopNodePtrList LoopStack;
111*03ce13f7SAndroid Build Coastguard Worker   /// The index to assign to the next visited node.
112*03ce13f7SAndroid Build Coastguard Worker   IndexT NextIndex = FirstDefinedIndex;
113*03ce13f7SAndroid Build Coastguard Worker   /// The number of nodes which have been marked deleted. This is used to track
114*03ce13f7SAndroid Build Coastguard Worker   /// when the iteration should end.
115*03ce13f7SAndroid Build Coastguard Worker   LoopNodePtrList::size_type NumDeletedNodes = 0;
116*03ce13f7SAndroid Build Coastguard Worker 
117*03ce13f7SAndroid Build Coastguard Worker   /// All the Loops, in descending order of size
118*03ce13f7SAndroid Build Coastguard Worker   CfgVector<CfgUnorderedSet<SizeT>> Loops;
119*03ce13f7SAndroid Build Coastguard Worker };
reset()120*03ce13f7SAndroid Build Coastguard Worker void LoopAnalyzer::LoopNode::reset() {
121*03ce13f7SAndroid Build Coastguard Worker   if (Deleted)
122*03ce13f7SAndroid Build Coastguard Worker     return;
123*03ce13f7SAndroid Build Coastguard Worker   Succ = BB->getOutEdges().begin();
124*03ce13f7SAndroid Build Coastguard Worker   Index = LowLink = UndefinedIndex;
125*03ce13f7SAndroid Build Coastguard Worker   OnStack = false;
126*03ce13f7SAndroid Build Coastguard Worker }
127*03ce13f7SAndroid Build Coastguard Worker 
successorsEnd() const128*03ce13f7SAndroid Build Coastguard Worker NodeList::const_iterator LoopAnalyzer::LoopNode::successorsEnd() const {
129*03ce13f7SAndroid Build Coastguard Worker   return BB->getOutEdges().end();
130*03ce13f7SAndroid Build Coastguard Worker }
131*03ce13f7SAndroid Build Coastguard Worker 
incrementLoopNestDepth()132*03ce13f7SAndroid Build Coastguard Worker void LoopAnalyzer::LoopNode::incrementLoopNestDepth() {
133*03ce13f7SAndroid Build Coastguard Worker   BB->incrementLoopNestDepth();
134*03ce13f7SAndroid Build Coastguard Worker }
135*03ce13f7SAndroid Build Coastguard Worker 
hasSelfEdge() const136*03ce13f7SAndroid Build Coastguard Worker bool LoopAnalyzer::LoopNode::hasSelfEdge() const {
137*03ce13f7SAndroid Build Coastguard Worker   for (CfgNode *Succ : BB->getOutEdges()) {
138*03ce13f7SAndroid Build Coastguard Worker     if (Succ == BB)
139*03ce13f7SAndroid Build Coastguard Worker       return true;
140*03ce13f7SAndroid Build Coastguard Worker   }
141*03ce13f7SAndroid Build Coastguard Worker   return false;
142*03ce13f7SAndroid Build Coastguard Worker }
143*03ce13f7SAndroid Build Coastguard Worker 
LoopAnalyzer(Cfg * Fn)144*03ce13f7SAndroid Build Coastguard Worker LoopAnalyzer::LoopAnalyzer(Cfg *Fn) : Func(Fn) {
145*03ce13f7SAndroid Build Coastguard Worker   const NodeList &Nodes = Func->getNodes();
146*03ce13f7SAndroid Build Coastguard Worker 
147*03ce13f7SAndroid Build Coastguard Worker   // Allocate memory ahead of time. This is why a vector is used instead of a
148*03ce13f7SAndroid Build Coastguard Worker   // stack which doesn't support reserving (or bulk erasure used below).
149*03ce13f7SAndroid Build Coastguard Worker   AllNodes.reserve(Nodes.size());
150*03ce13f7SAndroid Build Coastguard Worker   WorkStack.reserve(Nodes.size());
151*03ce13f7SAndroid Build Coastguard Worker   LoopStack.reserve(Nodes.size());
152*03ce13f7SAndroid Build Coastguard Worker 
153*03ce13f7SAndroid Build Coastguard Worker   // Create the LoopNodes from the function's CFG
154*03ce13f7SAndroid Build Coastguard Worker   for (CfgNode *Node : Nodes)
155*03ce13f7SAndroid Build Coastguard Worker     AllNodes.emplace_back(Node);
156*03ce13f7SAndroid Build Coastguard Worker   computeLoopNestDepth();
157*03ce13f7SAndroid Build Coastguard Worker }
158*03ce13f7SAndroid Build Coastguard Worker 
computeLoopNestDepth()159*03ce13f7SAndroid Build Coastguard Worker void LoopAnalyzer::computeLoopNestDepth() {
160*03ce13f7SAndroid Build Coastguard Worker   assert(AllNodes.size() == Func->getNodes().size());
161*03ce13f7SAndroid Build Coastguard Worker   assert(NextIndex == FirstDefinedIndex);
162*03ce13f7SAndroid Build Coastguard Worker   assert(NumDeletedNodes == 0);
163*03ce13f7SAndroid Build Coastguard Worker 
164*03ce13f7SAndroid Build Coastguard Worker   while (NumDeletedNodes < AllNodes.size()) {
165*03ce13f7SAndroid Build Coastguard Worker     // Prepare to run Tarjan's
166*03ce13f7SAndroid Build Coastguard Worker     for (LoopNode &Node : AllNodes)
167*03ce13f7SAndroid Build Coastguard Worker       Node.reset();
168*03ce13f7SAndroid Build Coastguard Worker 
169*03ce13f7SAndroid Build Coastguard Worker     assert(WorkStack.empty());
170*03ce13f7SAndroid Build Coastguard Worker     assert(LoopStack.empty());
171*03ce13f7SAndroid Build Coastguard Worker 
172*03ce13f7SAndroid Build Coastguard Worker     for (LoopNode &Node : AllNodes) {
173*03ce13f7SAndroid Build Coastguard Worker       if (Node.isDeleted() || Node.isVisited())
174*03ce13f7SAndroid Build Coastguard Worker         continue;
175*03ce13f7SAndroid Build Coastguard Worker 
176*03ce13f7SAndroid Build Coastguard Worker       WorkStack.push_back(&Node);
177*03ce13f7SAndroid Build Coastguard Worker 
178*03ce13f7SAndroid Build Coastguard Worker       while (!WorkStack.empty()) {
179*03ce13f7SAndroid Build Coastguard Worker         LoopNode &WorkNode = *WorkStack.back();
180*03ce13f7SAndroid Build Coastguard Worker         if (LoopNode *Succ = processNode(WorkNode))
181*03ce13f7SAndroid Build Coastguard Worker           WorkStack.push_back(Succ);
182*03ce13f7SAndroid Build Coastguard Worker         else
183*03ce13f7SAndroid Build Coastguard Worker           WorkStack.pop_back();
184*03ce13f7SAndroid Build Coastguard Worker       }
185*03ce13f7SAndroid Build Coastguard Worker     }
186*03ce13f7SAndroid Build Coastguard Worker   }
187*03ce13f7SAndroid Build Coastguard Worker }
188*03ce13f7SAndroid Build Coastguard Worker 
189*03ce13f7SAndroid Build Coastguard Worker LoopAnalyzer::LoopNode *
processNode(LoopAnalyzer::LoopNode & Node)190*03ce13f7SAndroid Build Coastguard Worker LoopAnalyzer::processNode(LoopAnalyzer::LoopNode &Node) {
191*03ce13f7SAndroid Build Coastguard Worker   if (!Node.isVisited()) {
192*03ce13f7SAndroid Build Coastguard Worker     Node.visit(NextIndex++);
193*03ce13f7SAndroid Build Coastguard Worker     LoopStack.push_back(&Node);
194*03ce13f7SAndroid Build Coastguard Worker     Node.setOnStack();
195*03ce13f7SAndroid Build Coastguard Worker   } else {
196*03ce13f7SAndroid Build Coastguard Worker     // Returning to a node after having recursed into Succ so continue
197*03ce13f7SAndroid Build Coastguard Worker     // iterating through successors after using the Succ.LowLink value that was
198*03ce13f7SAndroid Build Coastguard Worker     // computed in the recursion.
199*03ce13f7SAndroid Build Coastguard Worker     LoopNode &Succ = AllNodes[(*Node.currentSuccessor())->getIndex()];
200*03ce13f7SAndroid Build Coastguard Worker     Node.tryLink(Succ.getLowLink());
201*03ce13f7SAndroid Build Coastguard Worker     Node.nextSuccessor();
202*03ce13f7SAndroid Build Coastguard Worker   }
203*03ce13f7SAndroid Build Coastguard Worker 
204*03ce13f7SAndroid Build Coastguard Worker   // Visit the successors and recurse into unvisited nodes. The recursion could
205*03ce13f7SAndroid Build Coastguard Worker   // cause the iteration to be suspended but it will resume as the stack is
206*03ce13f7SAndroid Build Coastguard Worker   // unwound.
207*03ce13f7SAndroid Build Coastguard Worker   auto SuccEnd = Node.successorsEnd();
208*03ce13f7SAndroid Build Coastguard Worker   for (; Node.currentSuccessor() != SuccEnd; Node.nextSuccessor()) {
209*03ce13f7SAndroid Build Coastguard Worker     LoopNode &Succ = AllNodes[(*Node.currentSuccessor())->getIndex()];
210*03ce13f7SAndroid Build Coastguard Worker 
211*03ce13f7SAndroid Build Coastguard Worker     if (Succ.isDeleted())
212*03ce13f7SAndroid Build Coastguard Worker       continue;
213*03ce13f7SAndroid Build Coastguard Worker 
214*03ce13f7SAndroid Build Coastguard Worker     if (!Succ.isVisited())
215*03ce13f7SAndroid Build Coastguard Worker       return &Succ;
216*03ce13f7SAndroid Build Coastguard Worker     else if (Succ.isOnStack())
217*03ce13f7SAndroid Build Coastguard Worker       Node.tryLink(Succ.getIndex());
218*03ce13f7SAndroid Build Coastguard Worker   }
219*03ce13f7SAndroid Build Coastguard Worker 
220*03ce13f7SAndroid Build Coastguard Worker   if (Node.getLowLink() != Node.getIndex())
221*03ce13f7SAndroid Build Coastguard Worker     return nullptr;
222*03ce13f7SAndroid Build Coastguard Worker 
223*03ce13f7SAndroid Build Coastguard Worker   // Single node means no loop in the CFG
224*03ce13f7SAndroid Build Coastguard Worker   if (LoopStack.back() == &Node) {
225*03ce13f7SAndroid Build Coastguard Worker     LoopStack.back()->setOnStack(false);
226*03ce13f7SAndroid Build Coastguard Worker     if (Node.hasSelfEdge())
227*03ce13f7SAndroid Build Coastguard Worker       LoopStack.back()->incrementLoopNestDepth();
228*03ce13f7SAndroid Build Coastguard Worker     LoopStack.back()->setDeleted();
229*03ce13f7SAndroid Build Coastguard Worker     ++NumDeletedNodes;
230*03ce13f7SAndroid Build Coastguard Worker     LoopStack.pop_back();
231*03ce13f7SAndroid Build Coastguard Worker     return nullptr;
232*03ce13f7SAndroid Build Coastguard Worker   }
233*03ce13f7SAndroid Build Coastguard Worker 
234*03ce13f7SAndroid Build Coastguard Worker   // Reaching here means a loop has been found! It consists of the nodes on the
235*03ce13f7SAndroid Build Coastguard Worker   // top of the stack, down until the current node being processed, Node, is
236*03ce13f7SAndroid Build Coastguard Worker   // found.
237*03ce13f7SAndroid Build Coastguard Worker   for (auto It = LoopStack.rbegin(); It != LoopStack.rend(); ++It) {
238*03ce13f7SAndroid Build Coastguard Worker     (*It)->setOnStack(false);
239*03ce13f7SAndroid Build Coastguard Worker     (*It)->incrementLoopNestDepth();
240*03ce13f7SAndroid Build Coastguard Worker     // Remove the loop from the stack and delete the head node
241*03ce13f7SAndroid Build Coastguard Worker     if (*It == &Node) {
242*03ce13f7SAndroid Build Coastguard Worker       (*It)->setDeleted();
243*03ce13f7SAndroid Build Coastguard Worker       ++NumDeletedNodes;
244*03ce13f7SAndroid Build Coastguard Worker       CfgUnorderedSet<SizeT> LoopNodes;
245*03ce13f7SAndroid Build Coastguard Worker       for (auto LoopIter = It.base() - 1; LoopIter != LoopStack.end();
246*03ce13f7SAndroid Build Coastguard Worker            ++LoopIter) {
247*03ce13f7SAndroid Build Coastguard Worker         LoopNodes.insert((*LoopIter)->getNode()->getIndex());
248*03ce13f7SAndroid Build Coastguard Worker       }
249*03ce13f7SAndroid Build Coastguard Worker       Loops.push_back(LoopNodes);
250*03ce13f7SAndroid Build Coastguard Worker       LoopStack.erase(It.base() - 1, LoopStack.end());
251*03ce13f7SAndroid Build Coastguard Worker       break;
252*03ce13f7SAndroid Build Coastguard Worker     }
253*03ce13f7SAndroid Build Coastguard Worker   }
254*03ce13f7SAndroid Build Coastguard Worker 
255*03ce13f7SAndroid Build Coastguard Worker   return nullptr;
256*03ce13f7SAndroid Build Coastguard Worker }
ComputeLoopInfo(Cfg * Func)257*03ce13f7SAndroid Build Coastguard Worker CfgVector<Loop> ComputeLoopInfo(Cfg *Func) {
258*03ce13f7SAndroid Build Coastguard Worker   auto LoopBodies = LoopAnalyzer(Func).getLoopBodies();
259*03ce13f7SAndroid Build Coastguard Worker 
260*03ce13f7SAndroid Build Coastguard Worker   CfgVector<Loop> Loops;
261*03ce13f7SAndroid Build Coastguard Worker   Loops.reserve(LoopBodies.size());
262*03ce13f7SAndroid Build Coastguard Worker   std::sort(
263*03ce13f7SAndroid Build Coastguard Worker       LoopBodies.begin(), LoopBodies.end(),
264*03ce13f7SAndroid Build Coastguard Worker       [](const CfgUnorderedSet<SizeT> &A, const CfgUnorderedSet<SizeT> &B) {
265*03ce13f7SAndroid Build Coastguard Worker         return A.size() > B.size();
266*03ce13f7SAndroid Build Coastguard Worker       });
267*03ce13f7SAndroid Build Coastguard Worker   for (auto &LoopBody : LoopBodies) {
268*03ce13f7SAndroid Build Coastguard Worker     CfgNode *Header = nullptr;
269*03ce13f7SAndroid Build Coastguard Worker     bool IsSimpleLoop = true;
270*03ce13f7SAndroid Build Coastguard Worker     for (auto NodeIndex : LoopBody) {
271*03ce13f7SAndroid Build Coastguard Worker       CfgNode *Cur = Func->getNodes()[NodeIndex];
272*03ce13f7SAndroid Build Coastguard Worker       for (auto *Prev : Cur->getInEdges()) {
273*03ce13f7SAndroid Build Coastguard Worker         if (LoopBody.find(Prev->getIndex()) ==
274*03ce13f7SAndroid Build Coastguard Worker             LoopBody.end()) { // coming from outside
275*03ce13f7SAndroid Build Coastguard Worker           if (Header == nullptr) {
276*03ce13f7SAndroid Build Coastguard Worker             Header = Cur;
277*03ce13f7SAndroid Build Coastguard Worker           } else {
278*03ce13f7SAndroid Build Coastguard Worker             Header = nullptr;
279*03ce13f7SAndroid Build Coastguard Worker             IsSimpleLoop = false;
280*03ce13f7SAndroid Build Coastguard Worker             break;
281*03ce13f7SAndroid Build Coastguard Worker           }
282*03ce13f7SAndroid Build Coastguard Worker         }
283*03ce13f7SAndroid Build Coastguard Worker       }
284*03ce13f7SAndroid Build Coastguard Worker       if (!IsSimpleLoop) {
285*03ce13f7SAndroid Build Coastguard Worker         break;
286*03ce13f7SAndroid Build Coastguard Worker       }
287*03ce13f7SAndroid Build Coastguard Worker     }
288*03ce13f7SAndroid Build Coastguard Worker     if (!IsSimpleLoop)
289*03ce13f7SAndroid Build Coastguard Worker       continue; // To next potential loop
290*03ce13f7SAndroid Build Coastguard Worker 
291*03ce13f7SAndroid Build Coastguard Worker     CfgNode *PreHeader = nullptr;
292*03ce13f7SAndroid Build Coastguard Worker     for (auto *Prev : Header->getInEdges()) {
293*03ce13f7SAndroid Build Coastguard Worker       if (LoopBody.find(Prev->getIndex()) == LoopBody.end()) {
294*03ce13f7SAndroid Build Coastguard Worker         if (PreHeader == nullptr) {
295*03ce13f7SAndroid Build Coastguard Worker           PreHeader = Prev;
296*03ce13f7SAndroid Build Coastguard Worker         } else {
297*03ce13f7SAndroid Build Coastguard Worker           PreHeader = nullptr;
298*03ce13f7SAndroid Build Coastguard Worker           break;
299*03ce13f7SAndroid Build Coastguard Worker         }
300*03ce13f7SAndroid Build Coastguard Worker       }
301*03ce13f7SAndroid Build Coastguard Worker     }
302*03ce13f7SAndroid Build Coastguard Worker 
303*03ce13f7SAndroid Build Coastguard Worker     Loops.emplace_back(Header, PreHeader, LoopBody);
304*03ce13f7SAndroid Build Coastguard Worker   }
305*03ce13f7SAndroid Build Coastguard Worker   return Loops;
306*03ce13f7SAndroid Build Coastguard Worker }
307*03ce13f7SAndroid Build Coastguard Worker 
308*03ce13f7SAndroid Build Coastguard Worker } // end of namespace Ice
309