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