• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "optimizer/ir/basicblock.h"
17 #include "loop_analyzer.h"
18 #include "optimizer/ir/graph.h"
19 #include "optimizer/analysis/dominators_tree.h"
20 #include "optimizer/analysis/rpo.h"
21 
22 namespace ark::compiler {
RunImpl()23 bool LoopAnalyzer::RunImpl()
24 {
25     GetGraph()->RunPass<DominatorsTree>();
26     ResetLoopInfo();
27     CreateRootLoop();
28     CollectBackEdges();
29     PopulateLoops();
30     for (auto loop : GetGraph()->GetRootLoop()->GetInnerLoops()) {
31         FindAndInsertPreHeaders(loop);
32     }
33     SetLoopProperties(GetGraph()->GetRootLoop(), 0);
34     return true;
35 }
36 
ResetLoopInfo()37 void LoopAnalyzer::ResetLoopInfo()
38 {
39     for (auto block : GetGraph()->GetVectorBlocks()) {
40         if (block != nullptr) {
41             block->SetLoop(nullptr);
42         }
43     }
44     GetGraph()->SetRootLoop(nullptr);
45     GetGraph()->SetHasIrreducibleLoop(false);
46     GetGraph()->SetHasInfiniteLoop(false);
47     loopCounter_ = 0;
48 }
49 
CreateNewLoop(BasicBlock * loopHeader)50 Loop *LoopAnalyzer::CreateNewLoop(BasicBlock *loopHeader)
51 {
52     auto loop = GetGraph()->GetAllocator()->New<Loop>(GetGraph()->GetAllocator(), loopHeader, loopCounter_++);
53     loop->AppendBlock(loopHeader);
54     return loop;
55 }
56 
CreateRootLoop()57 void LoopAnalyzer::CreateRootLoop()
58 {
59     ASSERT(GetGraph()->GetRootLoop() == nullptr);
60     auto rootLoop = GetGraph()->GetAllocator()->New<Loop>(GetGraph()->GetAllocator(), nullptr, loopCounter_++);
61     rootLoop->SetAsRoot();
62     GetGraph()->SetRootLoop(rootLoop);
63 }
64 
CollectBackEdges()65 void LoopAnalyzer::CollectBackEdges()
66 {
67     blackMarker_ = GetGraph()->NewMarker();
68     grayMarker_ = GetGraph()->NewMarker();
69     BackEdgeSearch(GetGraph()->GetStartBlock());
70     GetGraph()->EraseMarker(blackMarker_);
71     GetGraph()->EraseMarker(grayMarker_);
72 }
73 
74 /*
75  * Depth-first search to find back edges in the graph.
76  * When a block is visited for the first time it is marked with a gray marker,
77  * after visiting all his successors, a block is marked with a black marker.
78  * While doing DFS, if we encounter a block with a gray mark, then edge to this block is back edge.
79  */
BackEdgeSearch(BasicBlock * block)80 void LoopAnalyzer::BackEdgeSearch(BasicBlock *block)
81 {
82     block->SetMarker(grayMarker_);
83     block->SetMarker(blackMarker_);
84     for (auto succ : block->GetSuccsBlocks()) {
85         if (succ->IsMarked(grayMarker_)) {
86             ProcessNewBackEdge(succ, block);
87         } else if (!succ->IsMarked(blackMarker_)) {
88             BackEdgeSearch(succ);
89         }
90     }
91     block->ResetMarker(grayMarker_);
92 }
93 
94 /*
95  * Create new Loop if it doesn't exists.
96  * Append information about its header, back edge and check if this loop is irreducible.
97  * Loop is irreducible when its header doesn't dominate back edge.
98  */
ProcessNewBackEdge(BasicBlock * header,BasicBlock * backEdge)99 void LoopAnalyzer::ProcessNewBackEdge(BasicBlock *header, BasicBlock *backEdge)
100 {
101     auto loop = header->GetLoop();
102     if (loop == nullptr) {
103         loop = CreateNewLoop(header);
104     }
105 
106     loop->AppendBackEdge(backEdge);
107     if (!header->IsDominate(backEdge)) {
108         loop->SetIsIrreducible(true);
109         GetGraph()->SetHasIrreducibleLoop(true);
110     }
111 }
112 
113 /*
114  * Get vector of forward edges indexes in descending order
115  */
GetForwardEdgesIndexes(BasicBlock * header)116 ArenaVector<int> LoopAnalyzer::GetForwardEdgesIndexes(BasicBlock *header)
117 {
118     // Mark back-edges
119     auto markerHolder = compiler::MarkerHolder(GetGraph());
120     auto backEdgeMarker = markerHolder.GetMarker();
121     auto &backEdges = header->GetLoop()->GetBackEdges();
122     for (auto backEdge : backEdges) {
123         backEdge->SetMarker(backEdgeMarker);
124     }
125 
126     ArenaVector<int> indexes(header->GetGraph()->GetAllocator()->Adapter());
127     auto &predBlocks = header->GetPredsBlocks();
128     for (int idx = static_cast<int>(predBlocks.size()) - 1; idx >= 0; idx--) {
129         if (!predBlocks[idx]->IsMarked(backEdgeMarker)) {
130             indexes.push_back(idx);
131         }
132     }
133     ASSERT(indexes.size() + backEdges.size() == predBlocks.size());
134     return indexes;
135 }
136 
MovePhiInputsToPreHeader(BasicBlock * header,BasicBlock * preHeader,const ArenaVector<int> & fwEdgesIndexes)137 void LoopAnalyzer::MovePhiInputsToPreHeader(BasicBlock *header, BasicBlock *preHeader,
138                                             const ArenaVector<int> &fwEdgesIndexes)
139 {
140     for (auto phi : header->PhiInsts()) {
141         auto newPhi = GetGraph()->CreateInstPhi(phi->GetType(), phi->GetPc());
142         for (auto idx : fwEdgesIndexes) {
143             auto pred {header->GetPredBlockByIndex(idx)};
144             auto phiIdx {phi->CastToPhi()->GetPredBlockIndex(pred)};
145             newPhi->AppendInput(phi->GetInput(phiIdx).GetInst());
146             phi->RemoveInput(phiIdx);
147         }
148         preHeader->AppendPhi(newPhi);
149         phi->AppendInput(newPhi);
150     }
151 }
152 
UpdateControlFlowWithPreHeader(BasicBlock * header,BasicBlock * preHeader,const ArenaVector<int> & fwEdgesIndexes)153 void LoopAnalyzer::UpdateControlFlowWithPreHeader(BasicBlock *header, BasicBlock *preHeader,
154                                                   const ArenaVector<int> &fwEdgesIndexes)
155 {
156     constexpr size_t IMM_2 = 2;
157     if (fwEdgesIndexes.size() >= IMM_2) {
158         for (auto predIdx : fwEdgesIndexes) {
159             auto edge = header->GetPredBlockByIndex(predIdx);
160             edge->ReplaceSucc(header, preHeader);
161             header->RemovePred(edge);
162         }
163         preHeader->AddSucc(header);
164     } else {
165         ASSERT(fwEdgesIndexes.size() == 1);
166         auto edge = header->GetPredBlockByIndex(fwEdgesIndexes[0]);
167         edge->ReplaceSucc(header, preHeader);
168         header->ReplacePred(edge, preHeader);
169     }
170     // Update RPO
171     GetGraph()->GetAnalysis<Rpo>().SetValid(true);
172     GetGraph()->GetAnalysis<Rpo>().AddBasicBlockBefore(header, preHeader);
173 }
174 
175 /*
176  * Create block with the same amount of phi instructions as in a `header` and insert it before a `header`.
177  * Move relevant to forward edges phi inputs to pre-header.
178  */
CreatePreHeader(BasicBlock * header)179 BasicBlock *LoopAnalyzer::CreatePreHeader(BasicBlock *header)
180 {
181     auto fwEdgesIndexes = GetForwardEdgesIndexes(header);
182     auto preHeader = header->CreateImmediateDominator();
183     preHeader->SetGuestPc(header->GetGuestPc());
184     if (fwEdgesIndexes.size() >= 2U) {
185         MovePhiInputsToPreHeader(header, preHeader, fwEdgesIndexes);
186     }
187     UpdateControlFlowWithPreHeader(header, preHeader, fwEdgesIndexes);
188     return preHeader;
189 }
190 
PreHeaderExists(Loop * loop)191 bool LoopAnalyzer::PreHeaderExists(Loop *loop)
192 {
193     auto header = loop->GetHeader();
194     return header->GetPredsBlocks().size() - loop->GetBackEdges().size() == 1 &&
195            header->GetDominator()->GetLoop() == loop->GetOuterLoop() &&
196            header->GetDominator() != GetGraph()->GetStartBlock();
197 }
198 
199 /*
200  * Find all loop pre-headers. If loop doesn't have pre-header, insert it
201  */
FindAndInsertPreHeaders(Loop * loop)202 void LoopAnalyzer::FindAndInsertPreHeaders(Loop *loop)
203 {
204     ASSERT(loop != nullptr && loop->GetHeader() != nullptr);
205     auto header = loop->GetHeader();
206 
207     if (loop->IsTryCatchLoop()) {
208         loop->SetPreHeader(nullptr);
209     } else if (!loop->IsIrreducible()) {
210         BasicBlock *preHeader = nullptr;
211         if (PreHeaderExists(loop)) {
212             preHeader = header->GetDominator();
213         } else {
214             preHeader = CreatePreHeader(header);
215             preHeader->CopyTryCatchProps(header);
216             loop->GetOuterLoop()->AppendBlock(preHeader);
217         }
218         loop->SetPreHeader(preHeader);
219         preHeader->SetNextLoop(loop);
220     }
221 
222     for (auto innerLoop : loop->GetInnerLoops()) {
223         FindAndInsertPreHeaders(innerLoop);
224     }
225 }
226 
PopulateIrreducibleLoop(Loop * loop)227 void LoopAnalyzer::PopulateIrreducibleLoop(Loop *loop)
228 {
229     // Add back-edges to the loop for further analysis
230     // Note that other blocks of `loop` besides the header are not added to it,
231     // and outer loop of inner loops will be not `loop`, but its outer reducible (maybe root) loop
232     for (auto backEdge : loop->GetBackEdges()) {
233         if (backEdge->GetLoop() != loop) {
234             loop->AppendBlock(backEdge);
235         }
236     }
237 }
238 
239 /*
240  * Visiting existing loop headers to populate loops with blocks
241  * Search algorithm starts from the loop back edge and recursively adds all predecessors until loop header not found
242  */
PopulateLoops()243 void LoopAnalyzer::PopulateLoops()
244 {
245     for (auto it = GetGraph()->GetBlocksRPO().rbegin(); it != GetGraph()->GetBlocksRPO().rend(); it++) {
246         auto block = *it;
247         if (block->GetLoop() == nullptr || !block->IsLoopHeader()) {
248             continue;
249         }
250         auto loop = block->GetLoop();
251         if (loop->IsIrreducible()) {
252             PopulateIrreducibleLoop(loop);
253         } else {
254             blackMarker_ = GetGraph()->NewMarker();
255             block->SetMarker(blackMarker_);
256             for (auto backEdge : loop->GetBackEdges()) {
257                 NaturalLoopSearch(loop, backEdge);
258             }
259             GetGraph()->EraseMarker(blackMarker_);
260         }
261     }
262 
263     // Populate the root loop with blocks which are not assign to any loops
264     // Link all outer loops with the root loop
265     auto rootLoop = GetGraph()->GetRootLoop();
266     for (auto block : GetGraph()->GetBlocksRPO()) {
267         if (block->GetLoop() == nullptr) {
268             rootLoop->AppendBlock(block);
269         } else if (block->GetLoop()->GetOuterLoop() == nullptr) {
270             block->GetLoop()->SetOuterLoop(rootLoop);
271             rootLoop->AppendInnerLoop(block->GetLoop());
272         }
273     }
274 }
275 
276 /*
277  * Depth-first search to find blocks in the loop.
278  * When a block is visited for the first time it is marked with a black marker, added to the loop
279  * (if it hasn't been already added to the inner loop), and search runs for all its predecessors.
280  * Header block is marked firstly to stop search on it.
281  */
NaturalLoopSearch(Loop * loop,BasicBlock * block)282 void LoopAnalyzer::NaturalLoopSearch(Loop *loop, BasicBlock *block)
283 {
284     if (!block->IsMarked(blackMarker_)) {
285         block->SetMarker(blackMarker_);
286 
287         if (block->GetLoop() == nullptr) {
288             // `block` without assignment to any loop is found
289             loop->AppendBlock(block);
290         } else if (block->GetLoop()->GetHeader() != loop->GetHeader()) {
291             // `block` from an inner loop id found, because its header differs from searching loop header
292             if (block->GetLoop()->GetOuterLoop() == nullptr) {
293                 // Link outer loop and inner loop
294                 block->GetLoop()->SetOuterLoop(loop);
295                 loop->AppendInnerLoop(block->GetLoop());
296             }
297         }
298 
299         for (auto pred : block->GetPredsBlocks()) {
300             NaturalLoopSearch(loop, pred);
301         }
302     }
303 }
304 
SetLoopProperties(Loop * loop,uint32_t depth)305 void LoopAnalyzer::SetLoopProperties(Loop *loop, uint32_t depth)
306 {
307     loop->CheckInfinity();
308     loop->SetDepth(depth);
309     if (loop->IsInfinite()) {
310         GetGraph()->SetHasInfiniteLoop(true);
311     }
312     depth++;
313     for (auto innerLoop : loop->GetInnerLoops()) {
314         SetLoopProperties(innerLoop, depth);
315     }
316 }
317 
AppendBlock(BasicBlock * block)318 void Loop::AppendBlock(BasicBlock *block)
319 {
320     ASSERT(std::find(blocks_.begin(), blocks_.end(), block) == blocks_.end());
321     block->SetLoop(this);
322     blocks_.push_back(block);
323 }
324 
RemoveBlock(BasicBlock * block)325 void Loop::RemoveBlock(BasicBlock *block)
326 {
327     ASSERT(block != GetHeader());
328     ASSERT(!HasBackEdge(block));
329 #ifndef NDEBUG
330     for (auto innerLoop : GetInnerLoops()) {
331         ASSERT(block != innerLoop->GetPreHeader());
332     }
333 #endif
334 
335     auto blockIt = std::find(blocks_.begin(), blocks_.end(), block);
336     ASSERT(blockIt != blocks_.end());
337     blocks_.erase(blockIt);
338 }
339 
IsOsrLoop() const340 bool Loop::IsOsrLoop() const
341 {
342     return !IsRoot() && GetHeader()->IsOsrEntry();
343 }
344 
IsTryCatchLoop() const345 bool Loop::IsTryCatchLoop() const
346 {
347     return !IsRoot() && GetHeader()->IsCatchBegin();
348 }
349 
350 /*
351  * Check if this loop is inside other
352  */
IsInside(Loop * other)353 bool Loop::IsInside(Loop *other)
354 {
355     auto outer = this->GetOuterLoop();
356     while (outer != nullptr) {
357         if (outer == other) {
358             return true;
359         }
360         outer = outer->GetOuterLoop();
361     }
362     return false;
363 }
364 
MoveHeaderToSucc()365 void Loop::MoveHeaderToSucc()
366 {
367     ASSERT(header_->GetSuccsBlocks().size() == 1);
368     header_ = header_->GetSuccessor(0);
369     ASSERT(header_->GetLoop() == this);
370     auto it = std::find(blocks_.begin(), blocks_.end(), header_);
371     ASSERT(it != blocks_.end());
372     std::swap(*it, *blocks_.begin());
373 }
374 
CheckInfinity()375 void Loop::CheckInfinity()
376 {
377     isInfinite_ = false;
378     if (isRoot_) {
379         return;
380     }
381     auto outerLoop = GetOuterLoop();
382     for (auto block : GetBlocks()) {
383         const auto &succs = block->GetSuccsBlocks();
384         bool hasExit = std::find_if(succs.begin(), succs.end(), [&outerLoop](const BasicBlock *bb) {
385                            return bb->GetLoop() == outerLoop;
386                        }) != succs.end();
387         if (hasExit) {
388             return;
389         }
390     }
391     isInfinite_ = true;
392 }
393 
IsPostExitBlock(const BasicBlock * block) const394 bool Loop::IsPostExitBlock(const BasicBlock *block) const
395 {
396     for (auto loopBlock : GetBlocks()) {
397         for (auto succ : loopBlock->GetSuccsBlocks()) {
398             if (succ->GetLoop() != GetOuterLoop()) {
399                 continue;
400             }
401 
402             if (succ == block) {
403                 return true;
404             }
405         }
406     }
407 
408     return false;
409 }
410 
411 /*
412  * Find outside block for the loop with single back-edge exit
413  */
GetLoopOutsideSuccessor(Loop * loop)414 BasicBlock *GetLoopOutsideSuccessor(Loop *loop)
415 {
416     ASSERT(loop->GetBackEdges().size() == 1);
417     auto backEdge = loop->GetBackEdges()[0];
418     auto headerSuccIdx = backEdge->GetSuccBlockIndex(loop->GetHeader());
419     ASSERT(backEdge->GetSuccsBlocks().size() == MAX_SUCCS_NUM);
420     auto outsideBlock = backEdge->GetSuccessor(1 - headerSuccIdx);
421     ASSERT(outsideBlock != nullptr);
422     return outsideBlock;
423 }
424 
425 /**
426  * Check if the loop block sequence meets the requirements:
427  * - there is only one back-edge;
428  * - there is only one exit-point - from the back-edge;
429  */
IsLoopSingleBackEdgeExitPoint(Loop * loop)430 bool IsLoopSingleBackEdgeExitPoint(Loop *loop)
431 {
432     ASSERT(loop != nullptr);
433     if (loop->IsIrreducible()) {
434         return false;
435     }
436     if (loop->GetBackEdges().size() != 1) {
437         return false;
438     }
439     auto backEdge = loop->GetBackEdges()[0];
440     // Check there are no side-exits
441     for (auto block : loop->GetBlocks()) {
442         if (block == backEdge) {
443             continue;
444         }
445         for (auto succ : block->GetSuccsBlocks()) {
446             if (succ->GetLoop() != loop) {
447                 return false;
448             }
449         }
450     }
451     return true;
452 }
453 }  // namespace ark::compiler
454