• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2022 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 "optimizer/ir/graph.h"
18 #include "optimizer/analysis/dominators_tree.h"
19 #include "optimizer/analysis/rpo.h"
20 #include "loop_analyzer.h"
21 
22 namespace panda::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     SearchInfiniteLoops(GetGraph()->GetRootLoop());
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     loop_counter_ = 0;
48 }
49 
CreateNewLoop(BasicBlock * loop_header)50 Loop *LoopAnalyzer::CreateNewLoop(BasicBlock *loop_header)
51 {
52     auto loop = GetGraph()->GetAllocator()->New<Loop>(GetGraph()->GetAllocator(), loop_header, loop_counter_++);
53     loop->AppendBlock(loop_header);
54     return loop;
55 }
56 
CreateRootLoop()57 void LoopAnalyzer::CreateRootLoop()
58 {
59     ASSERT(GetGraph()->GetRootLoop() == nullptr);
60     auto root_loop = GetGraph()->GetAllocator()->New<Loop>(GetGraph()->GetAllocator(), nullptr, loop_counter_++);
61     root_loop->SetAsRoot();
62     GetGraph()->SetRootLoop(root_loop);
63 }
64 
CollectBackEdges()65 void LoopAnalyzer::CollectBackEdges()
66 {
67     black_marker_ = GetGraph()->NewMarker();
68     gray_marker_ = GetGraph()->NewMarker();
69     BackEdgeSearch(GetGraph()->GetStartBlock());
70     GetGraph()->EraseMarker(black_marker_);
71     GetGraph()->EraseMarker(gray_marker_);
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(gray_marker_);
83     block->SetMarker(black_marker_);
84     for (auto succ : block->GetSuccsBlocks()) {
85         if (succ->IsMarked(gray_marker_)) {
86             ProcessNewBackEdge(succ, block);
87         } else if (!succ->IsMarked(black_marker_)) {
88             BackEdgeSearch(succ);
89         }
90     }
91     block->ResetMarker(gray_marker_);
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 * back_edge)99 void LoopAnalyzer::ProcessNewBackEdge(BasicBlock *header, BasicBlock *back_edge)
100 {
101     auto loop = header->GetLoop();
102     if (loop == nullptr) {
103         loop = CreateNewLoop(header);
104     }
105 
106     loop->AppendBackEdge(back_edge);
107     if (!header->IsDominate(back_edge)) {
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 marker_holder = compiler::MarkerHolder(GetGraph());
120     auto back_edge_marker = marker_holder.GetMarker();
121     auto &back_edges = header->GetLoop()->GetBackEdges();
122     for (auto back_edge : back_edges) {
123         back_edge->SetMarker(back_edge_marker);
124     }
125 
126     ArenaVector<int> indexes(header->GetGraph()->GetAllocator()->Adapter());
127     auto &pred_blocks = header->GetPredsBlocks();
128     for (int idx = static_cast<int>(pred_blocks.size()) - 1; idx >= 0; idx--) {
129         if (!pred_blocks[idx]->IsMarked(back_edge_marker)) {
130             indexes.push_back(idx);
131         }
132     }
133     ASSERT(indexes.size() + back_edges.size() == pred_blocks.size());
134     return indexes;
135 }
136 
MovePhiInputsToPreHeader(BasicBlock * header,BasicBlock * pre_header,const ArenaVector<int> & fw_edges_indexes)137 void LoopAnalyzer::MovePhiInputsToPreHeader(BasicBlock *header, BasicBlock *pre_header,
138                                             const ArenaVector<int> &fw_edges_indexes)
139 {
140     for (auto phi : header->PhiInsts()) {
141         auto new_phi = GetGraph()->CreateInstPhi(phi->GetType(), phi->GetPc());
142         for (auto idx : fw_edges_indexes) {
143             auto pred {header->GetPredBlockByIndex(idx)};
144             auto phi_idx {phi->CastToPhi()->GetPredBlockIndex(pred)};
145             new_phi->AppendInput(phi->GetInput(phi_idx).GetInst());
146             phi->RemoveInput(phi_idx);
147         }
148         pre_header->AppendPhi(new_phi);
149         phi->AppendInput(new_phi);
150     }
151 }
152 
UpdateControlFlowWithPreHeader(BasicBlock * header,BasicBlock * pre_header,const ArenaVector<int> & fw_edges_indexes)153 void LoopAnalyzer::UpdateControlFlowWithPreHeader(BasicBlock *header, BasicBlock *pre_header,
154                                                   const ArenaVector<int> &fw_edges_indexes)
155 {
156     constexpr size_t IMM_2 = 2;
157     if (fw_edges_indexes.size() >= IMM_2) {
158         for (auto pred_idx : fw_edges_indexes) {
159             auto edge = header->GetPredBlockByIndex(pred_idx);
160             edge->ReplaceSucc(header, pre_header);
161             header->RemovePred(edge);
162         }
163         pre_header->AddSucc(header);
164     } else {
165         ASSERT(fw_edges_indexes.size() == 1);
166         auto edge = header->GetPredBlockByIndex(fw_edges_indexes[0]);
167         edge->ReplaceSucc(header, pre_header);
168         header->ReplacePred(edge, pre_header);
169     }
170     // Update RPO
171     GetGraph()->GetAnalysis<Rpo>().SetValid(true);
172     GetGraph()->GetAnalysis<Rpo>().AddBasicBlockBefore(header, pre_header);
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 fw_edges_indexes = GetForwardEdgesIndexes(header);
182     auto pre_header = header->CreateImmediateDominator();
183     pre_header->SetGuestPc(header->GetGuestPc());
184     if (fw_edges_indexes.size() >= 2U) {
185         MovePhiInputsToPreHeader(header, pre_header, fw_edges_indexes);
186     }
187     UpdateControlFlowWithPreHeader(header, pre_header, fw_edges_indexes);
188     return pre_header;
189 }
190 
PreHeaderExists(Loop * loop)191 bool LoopAnalyzer::PreHeaderExists(Loop *loop)
192 {
193     auto header = loop->GetHeader();
194 
195     return header->GetPredsBlocks().size() - loop->GetBackEdges().size() == 1 &&
196            header->GetDominator()->GetLoop() == loop->GetOuterLoop() &&
197            header->GetDominator() != GetGraph()->GetStartBlock();
198 }
199 
200 /*
201  * Find all loop pre-headers. If loop doesn't have pre-header, insert it
202  */
FindAndInsertPreHeaders(Loop * loop)203 void LoopAnalyzer::FindAndInsertPreHeaders(Loop *loop)
204 {
205     ASSERT(loop != nullptr && loop->GetHeader() != nullptr);
206     auto header = loop->GetHeader();
207 
208     if (loop->IsTryCatchLoop()) {
209         loop->SetPreHeader(nullptr);
210     } else if (!loop->IsIrreducible()) {
211         BasicBlock *pre_header = nullptr;
212         if (PreHeaderExists(loop)) {
213             pre_header = header->GetDominator();
214         } else {
215             pre_header = CreatePreHeader(header);
216             pre_header->CopyTryCatchProps(header);
217             loop->GetOuterLoop()->AppendBlock(pre_header);
218         }
219         loop->SetPreHeader(pre_header);
220         pre_header->SetNextLoop(loop);
221     }
222 
223     for (auto inner_loop : loop->GetInnerLoops()) {
224         FindAndInsertPreHeaders(inner_loop);
225     }
226 }
227 
228 /*
229  * Visiting existing loop headers to populate loops with blocks
230  * Search algorithm starts from the loop back edge and recursively adds all predecessors until loop header not found
231  */
PopulateLoops()232 void LoopAnalyzer::PopulateLoops()
233 {
234     for (auto it = GetGraph()->GetBlocksRPO().rbegin(); it != GetGraph()->GetBlocksRPO().rend(); it++) {
235         auto block = *it;
236         if (block->GetLoop() == nullptr || !block->IsLoopHeader()) {
237             continue;
238         }
239         auto loop = block->GetLoop();
240         if (loop->IsIrreducible()) {
241             // Add back-edges to the loop for further analysis
242             for (auto back_edge : loop->GetBackEdges()) {
243                 if (back_edge->GetLoop() != loop) {
244                     loop->AppendBlock(back_edge);
245                 }
246             }
247         } else {
248             black_marker_ = GetGraph()->NewMarker();
249             block->SetMarker(black_marker_);
250             for (auto back_edge : loop->GetBackEdges()) {
251                 NaturalLoopSearch(loop, back_edge);
252             }
253             GetGraph()->EraseMarker(black_marker_);
254         }
255     }
256 
257     // Populate the root loop with blocks which are not assign to any loops
258     // Link all outer loops with the root loop
259     auto root_loop = GetGraph()->GetRootLoop();
260     for (auto block : GetGraph()->GetBlocksRPO()) {
261         if (block->GetLoop() == nullptr) {
262             root_loop->AppendBlock(block);
263         } else if (block->GetLoop()->GetOuterLoop() == nullptr) {
264             block->GetLoop()->SetOuterLoop(root_loop);
265             root_loop->AppendInnerLoop(block->GetLoop());
266         }
267     }
268 }
269 
270 /*
271  * Depth-first search to find blocks in the loop.
272  * When a block is visited for the first time it is marked with a black marker, added to the loop
273  * (if it hasn't been already added to the inner loop), and search runs for all its predecessors.
274  * Header block is marked firstly to stop search on it.
275  */
NaturalLoopSearch(Loop * loop,BasicBlock * block)276 void LoopAnalyzer::NaturalLoopSearch(Loop *loop, BasicBlock *block)
277 {
278     if (!block->IsMarked(black_marker_)) {
279         block->SetMarker(black_marker_);
280 
281         if (block->GetLoop() == nullptr) {
282             // `block` without assignment to any loop is found
283             loop->AppendBlock(block);
284         } else if (block->GetLoop()->GetHeader() != loop->GetHeader()) {
285             // `block` from an inner loop id found, because its header differs from searching loop header
286             if (block->GetLoop()->GetOuterLoop() == nullptr) {
287                 // Link outer loop and inner loop
288                 block->GetLoop()->SetOuterLoop(loop);
289                 loop->AppendInnerLoop(block->GetLoop());
290             }
291         }
292 
293         for (auto pred : block->GetPredsBlocks()) {
294             NaturalLoopSearch(loop, pred);
295         }
296     }
297 }
298 
SearchInfiniteLoops(Loop * loop)299 void LoopAnalyzer::SearchInfiniteLoops(Loop *loop)
300 {
301     loop->CheckInfinity();
302     if (loop->IsInfinite()) {
303         GetGraph()->SetHasInfiniteLoop(true);
304     }
305     for (auto inner_loop : loop->GetInnerLoops()) {
306         SearchInfiniteLoops(inner_loop);
307     }
308 }
309 
AppendBlock(BasicBlock * block)310 void Loop::AppendBlock(BasicBlock *block)
311 {
312     ASSERT(std::find(blocks_.begin(), blocks_.end(), block) == blocks_.end());
313     block->SetLoop(this);
314     blocks_.push_back(block);
315 }
316 
RemoveBlock(BasicBlock * block)317 void Loop::RemoveBlock(BasicBlock *block)
318 {
319     ASSERT(block != GetHeader());
320     ASSERT(!HasBackEdge(block));
321 #ifndef NDEBUG
322     for (auto inner_loop : GetInnerLoops()) {
323         ASSERT(block != inner_loop->GetPreHeader());
324     }
325 #endif
326 
327     auto block_it = std::find(blocks_.begin(), blocks_.end(), block);
328     ASSERT(block_it != blocks_.end());
329     blocks_.erase(block_it);
330 }
331 
IsOsrLoop() const332 bool Loop::IsOsrLoop() const
333 {
334     return !IsRoot() && GetHeader()->IsOsrEntry();
335 }
336 
IsTryCatchLoop() const337 bool Loop::IsTryCatchLoop() const
338 {
339     return !IsRoot() && GetHeader()->IsCatchBegin();
340 }
341 
342 /*
343  * Check if this loop is inside other
344  */
IsInside(Loop * other)345 bool Loop::IsInside(Loop *other)
346 {
347     auto outer = this->GetOuterLoop();
348     while (outer != nullptr) {
349         if (outer == other) {
350             return true;
351         }
352         outer = outer->GetOuterLoop();
353     }
354     return false;
355 }
356 
MoveHeaderToSucc()357 void Loop::MoveHeaderToSucc()
358 {
359     ASSERT(header_->GetSuccsBlocks().size() == 1);
360     header_ = header_->GetSuccessor(0);
361     ASSERT(header_->GetLoop() == this);
362     auto it = std::find(blocks_.begin(), blocks_.end(), header_);
363     ASSERT(it != blocks_.end());
364     std::swap(*it, *blocks_.begin());
365 }
366 
CheckInfinity()367 void Loop::CheckInfinity()
368 {
369     is_infinite_ = false;
370     if (is_root_) {
371         return;
372     }
373     auto outer_loop = GetOuterLoop();
374     for (auto block : GetBlocks()) {
375         const auto &succs = block->GetSuccsBlocks();
376         bool has_exit = std::find_if(succs.begin(), succs.end(), [&outer_loop](const BasicBlock *bb) {
377                             return bb->GetLoop() == outer_loop;
378                         }) != succs.end();
379         if (has_exit) {
380             return;
381         }
382     }
383     is_infinite_ = true;
384 }
385 
386 /*
387  * Find outside block for the loop with single back-edge exit
388  */
GetLoopOutsideSuccessor(Loop * loop)389 BasicBlock *GetLoopOutsideSuccessor(Loop *loop)
390 {
391     ASSERT(loop->GetBackEdges().size() == 1);
392     auto back_edge = loop->GetBackEdges()[0];
393     auto header_succ_idx = back_edge->GetSuccBlockIndex(loop->GetHeader());
394     ASSERT(back_edge->GetSuccsBlocks().size() == MAX_SUCCS_NUM);
395     auto outside_block = back_edge->GetSuccessor(1 - header_succ_idx);
396     ASSERT(outside_block != nullptr);
397     return outside_block;
398 }
399 
400 /**
401  * Check if the loop block sequence meets the requirements:
402  * - there is only one back-edge;
403  * - there is only one exit-point - from the back-edge;
404  */
IsLoopSingleBackEdgeExitPoint(Loop * loop)405 bool IsLoopSingleBackEdgeExitPoint(Loop *loop)
406 {
407     ASSERT(loop != nullptr);
408     if (loop->IsIrreducible()) {
409         return false;
410     }
411     if (loop->GetBackEdges().size() != 1) {
412         return false;
413     }
414     auto back_edge = loop->GetBackEdges()[0];
415     // Check there are no side-exits
416     for (auto block : loop->GetBlocks()) {
417         if (block == back_edge) {
418             continue;
419         }
420         for (auto succ : block->GetSuccsBlocks()) {
421             if (succ->GetLoop() != loop) {
422                 return false;
423             }
424         }
425     }
426     return true;
427 }
428 }  // namespace panda::compiler
429