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