1 /*
2 * Copyright (c) 2021-2025 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/analysis.h"
19 #include "optimizer/ir/graph.h"
20 #include "optimizer/analysis/dominators_tree.h"
21 #include "optimizer/analysis/rpo.h"
22
23 namespace ark::compiler {
RunImpl()24 bool LoopAnalyzer::RunImpl()
25 {
26 GetGraph()->RunPass<DominatorsTree>();
27 ResetLoopInfo();
28 CreateRootLoop();
29 CollectBackEdges();
30 PopulateLoops();
31 for (auto loop : GetGraph()->GetRootLoop()->GetInnerLoops()) {
32 FindAndInsertPreHeaders(loop);
33 CheckActualLengthAsLoopInitOrBound(loop);
34 }
35 SetLoopProperties(GetGraph()->GetRootLoop(), 0);
36 return true;
37 }
38
ResetLoopInfo()39 void LoopAnalyzer::ResetLoopInfo()
40 {
41 for (auto block : GetGraph()->GetVectorBlocks()) {
42 if (block != nullptr) {
43 block->SetLoop(nullptr);
44 block->SetNextLoop(nullptr);
45 }
46 }
47 GetGraph()->SetRootLoop(nullptr);
48 GetGraph()->SetHasIrreducibleLoop(false);
49 GetGraph()->SetHasInfiniteLoop(false);
50 loopCounter_ = 0;
51 }
52
CreateNewLoop(BasicBlock * loopHeader)53 Loop *LoopAnalyzer::CreateNewLoop(BasicBlock *loopHeader)
54 {
55 auto loop = GetGraph()->GetAllocator()->New<Loop>(GetGraph()->GetAllocator(), loopHeader, loopCounter_++);
56 ASSERT(loop != nullptr);
57 loop->AppendBlock(loopHeader);
58 return loop;
59 }
60
CreateRootLoop()61 void LoopAnalyzer::CreateRootLoop()
62 {
63 ASSERT(GetGraph()->GetRootLoop() == nullptr);
64 auto rootLoop = GetGraph()->GetAllocator()->New<Loop>(GetGraph()->GetAllocator(), nullptr, loopCounter_++);
65 ASSERT(rootLoop != nullptr);
66 rootLoop->SetAsRoot();
67 GetGraph()->SetRootLoop(rootLoop);
68 }
69
CollectBackEdges()70 void LoopAnalyzer::CollectBackEdges()
71 {
72 blackMarker_ = GetGraph()->NewMarker();
73 grayMarker_ = GetGraph()->NewMarker();
74 BackEdgeSearch(GetGraph()->GetStartBlock());
75 GetGraph()->EraseMarker(blackMarker_);
76 GetGraph()->EraseMarker(grayMarker_);
77 }
78
79 /*
80 * Depth-first search to find back edges in the graph.
81 * When a block is visited for the first time it is marked with a gray marker,
82 * after visiting all his successors, a block is marked with a black marker.
83 * While doing DFS, if we encounter a block with a gray mark, then edge to this block is back edge.
84 */
BackEdgeSearch(BasicBlock * block)85 void LoopAnalyzer::BackEdgeSearch(BasicBlock *block)
86 {
87 block->SetMarker(grayMarker_);
88 block->SetMarker(blackMarker_);
89 for (auto succ : block->GetSuccsBlocks()) {
90 if (succ->IsMarked(grayMarker_)) {
91 ProcessNewBackEdge(succ, block);
92 } else if (!succ->IsMarked(blackMarker_)) {
93 BackEdgeSearch(succ);
94 }
95 }
96 block->ResetMarker(grayMarker_);
97 }
98
99 /*
100 * Create new Loop if it doesn't exists.
101 * Append information about its header, back edge and check if this loop is irreducible.
102 * Loop is irreducible when its header doesn't dominate back edge.
103 */
ProcessNewBackEdge(BasicBlock * header,BasicBlock * backEdge)104 void LoopAnalyzer::ProcessNewBackEdge(BasicBlock *header, BasicBlock *backEdge)
105 {
106 auto loop = header->GetLoop();
107 if (loop == nullptr) {
108 loop = CreateNewLoop(header);
109 }
110
111 loop->AppendBackEdge(backEdge);
112 if (!header->IsDominate(backEdge)) {
113 loop->SetIsIrreducible(true);
114 GetGraph()->SetHasIrreducibleLoop(true);
115 }
116 }
117
118 /*
119 * Get vector of forward edges indexes in descending order
120 */
GetForwardEdgesIndexes(BasicBlock * header)121 ArenaVector<int> LoopAnalyzer::GetForwardEdgesIndexes(BasicBlock *header)
122 {
123 // Mark back-edges
124 auto markerHolder = compiler::MarkerHolder(GetGraph());
125 auto backEdgeMarker = markerHolder.GetMarker();
126 auto &backEdges = header->GetLoop()->GetBackEdges();
127 for (auto backEdge : backEdges) {
128 backEdge->SetMarker(backEdgeMarker);
129 }
130
131 ArenaVector<int> indexes(header->GetGraph()->GetAllocator()->Adapter());
132 auto &predBlocks = header->GetPredsBlocks();
133 for (int idx = static_cast<int>(predBlocks.size()) - 1; idx >= 0; idx--) {
134 if (!predBlocks[idx]->IsMarked(backEdgeMarker)) {
135 indexes.push_back(idx);
136 }
137 }
138 ASSERT(indexes.size() + backEdges.size() == predBlocks.size());
139 return indexes;
140 }
141
MovePhiInputsToPreHeader(BasicBlock * header,BasicBlock * preHeader,const ArenaVector<int> & fwEdgesIndexes)142 void LoopAnalyzer::MovePhiInputsToPreHeader(BasicBlock *header, BasicBlock *preHeader,
143 const ArenaVector<int> &fwEdgesIndexes)
144 {
145 for (auto phi : header->PhiInsts()) {
146 auto newPhi = GetGraph()->CreateInstPhi(phi->GetType(), phi->GetPc());
147 for (auto idx : fwEdgesIndexes) {
148 auto pred {header->GetPredBlockByIndex(idx)};
149 auto phiIdx {phi->CastToPhi()->GetPredBlockIndex(pred)};
150 newPhi->AppendInput(phi->GetInput(phiIdx).GetInst());
151 phi->RemoveInput(phiIdx);
152 }
153 preHeader->AppendPhi(newPhi);
154 phi->AppendInput(newPhi);
155 }
156 }
157
UpdateControlFlowWithPreHeader(BasicBlock * header,BasicBlock * preHeader,const ArenaVector<int> & fwEdgesIndexes)158 void LoopAnalyzer::UpdateControlFlowWithPreHeader(BasicBlock *header, BasicBlock *preHeader,
159 const ArenaVector<int> &fwEdgesIndexes)
160 {
161 constexpr size_t IMM_2 = 2;
162 if (fwEdgesIndexes.size() >= IMM_2) {
163 for (auto predIdx : fwEdgesIndexes) {
164 auto edge = header->GetPredBlockByIndex(predIdx);
165 edge->ReplaceSucc(header, preHeader);
166 header->RemovePred(edge);
167 }
168 preHeader->AddSucc(header);
169 } else {
170 ASSERT(fwEdgesIndexes.size() == 1);
171 auto edge = header->GetPredBlockByIndex(fwEdgesIndexes[0]);
172 edge->ReplaceSucc(header, preHeader);
173 header->ReplacePred(edge, preHeader);
174 }
175 // Update RPO
176 GetGraph()->GetAnalysis<Rpo>().SetValid(true);
177 GetGraph()->GetAnalysis<Rpo>().AddBasicBlockBefore(header, preHeader);
178 }
179
180 /*
181 * Create block with the same amount of phi instructions as in a `header` and insert it before a `header`.
182 * Move relevant to forward edges phi inputs to pre-header.
183 */
CreatePreHeader(BasicBlock * header)184 BasicBlock *LoopAnalyzer::CreatePreHeader(BasicBlock *header)
185 {
186 auto fwEdgesIndexes = GetForwardEdgesIndexes(header);
187 auto preHeader = header->CreateImmediateDominator();
188 ASSERT(preHeader != nullptr);
189 preHeader->SetGuestPc(header->GetGuestPc());
190 if (fwEdgesIndexes.size() >= 2U) {
191 MovePhiInputsToPreHeader(header, preHeader, fwEdgesIndexes);
192 }
193 UpdateControlFlowWithPreHeader(header, preHeader, fwEdgesIndexes);
194 return preHeader;
195 }
196
PreHeaderExists(Loop * loop)197 bool LoopAnalyzer::PreHeaderExists(Loop *loop)
198 {
199 auto header = loop->GetHeader();
200 return header->GetPredsBlocks().size() - loop->GetBackEdges().size() == 1 &&
201 header->GetDominator()->GetLoop() == loop->GetOuterLoop() &&
202 header->GetDominator() != GetGraph()->GetStartBlock() && header->GetDominator()->GetNextLoop() == nullptr;
203 }
204
205 /*
206 * Find all loop pre-headers. If loop doesn't have pre-header, insert it
207 */
FindAndInsertPreHeaders(Loop * loop)208 void LoopAnalyzer::FindAndInsertPreHeaders(Loop *loop)
209 {
210 ASSERT(loop != nullptr && loop->GetHeader() != nullptr);
211 auto header = loop->GetHeader();
212
213 if (loop->IsTryCatchLoop()) {
214 loop->SetPreHeader(nullptr);
215 } else if (!loop->IsIrreducible()) {
216 BasicBlock *preHeader = nullptr;
217 if (PreHeaderExists(loop)) {
218 preHeader = header->GetDominator();
219 } else {
220 preHeader = CreatePreHeader(header);
221 preHeader->CopyTryCatchProps(header);
222 loop->GetOuterLoop()->AppendBlock(preHeader);
223 }
224 ASSERT(preHeader->GetNextLoop() == nullptr); // a preheader shouldn't relate to several loops.
225 loop->SetPreHeader(preHeader);
226 }
227
228 for (auto innerLoop : loop->GetInnerLoops()) {
229 FindAndInsertPreHeaders(innerLoop);
230 }
231 }
232
GetPreHeader() const233 BasicBlock *Loop::GetPreHeader() const
234 {
235 ASSERT(!preHeader_ || preHeader_->GetNextLoop() == this);
236 return preHeader_;
237 }
238
SetPreHeader(BasicBlock * preHeader)239 void Loop::SetPreHeader(BasicBlock *preHeader)
240 {
241 if (preHeader_ != nullptr && preHeader_->GetNextLoop() == this) {
242 preHeader_->SetNextLoop(nullptr);
243 }
244 preHeader_ = preHeader;
245 preHeader_->SetNextLoop(this);
246 }
SetPreHeader(std::nullptr_t preHeader)247 void Loop::SetPreHeader(std::nullptr_t preHeader)
248 {
249 if (preHeader_ != nullptr && preHeader_->GetNextLoop() == this) {
250 preHeader_->SetNextLoop(nullptr);
251 }
252 preHeader_ = preHeader;
253 }
254
PopulateIrreducibleLoop(Loop * loop)255 void LoopAnalyzer::PopulateIrreducibleLoop(Loop *loop)
256 {
257 // Add back-edges to the loop for further analysis
258 // Note that other blocks of `loop` besides the header are not added to it,
259 // and outer loop of inner loops will be not `loop`, but its outer reducible (maybe root) loop
260 for (auto backEdge : loop->GetBackEdges()) {
261 if (backEdge->GetLoop() != loop) {
262 loop->AppendBlock(backEdge);
263 }
264 }
265 }
266
267 /*
268 * Visiting existing loop headers to populate loops with blocks
269 * Search algorithm starts from the loop back edge and recursively adds all predecessors until loop header not found
270 */
PopulateLoops()271 void LoopAnalyzer::PopulateLoops()
272 {
273 for (auto it = GetGraph()->GetBlocksRPO().rbegin(); it != GetGraph()->GetBlocksRPO().rend(); it++) {
274 auto block = *it;
275 if (block->GetLoop() == nullptr || !block->IsLoopHeader()) {
276 continue;
277 }
278 auto loop = block->GetLoop();
279 if (loop->IsIrreducible()) {
280 PopulateIrreducibleLoop(loop);
281 } else {
282 blackMarker_ = GetGraph()->NewMarker();
283 block->SetMarker(blackMarker_);
284 for (auto backEdge : loop->GetBackEdges()) {
285 NaturalLoopSearch(loop, backEdge);
286 }
287 GetGraph()->EraseMarker(blackMarker_);
288 }
289 }
290
291 // Populate the root loop with blocks which are not assign to any loops
292 // Link all outer loops with the root loop
293 auto rootLoop = GetGraph()->GetRootLoop();
294 for (auto block : GetGraph()->GetBlocksRPO()) {
295 if (block->GetLoop() == nullptr) {
296 rootLoop->AppendBlock(block);
297 } else if (block->GetLoop()->GetOuterLoop() == nullptr) {
298 block->GetLoop()->SetOuterLoop(rootLoop);
299 rootLoop->AppendInnerLoop(block->GetLoop());
300 }
301 }
302 }
303
304 /*
305 * Depth-first search to find blocks in the loop.
306 * When a block is visited for the first time it is marked with a black marker, added to the loop
307 * (if it hasn't been already added to the inner loop), and search runs for all its predecessors.
308 * Header block is marked firstly to stop search on it.
309 */
NaturalLoopSearch(Loop * loop,BasicBlock * block)310 void LoopAnalyzer::NaturalLoopSearch(Loop *loop, BasicBlock *block)
311 {
312 if (!block->IsMarked(blackMarker_)) {
313 block->SetMarker(blackMarker_);
314
315 if (block->GetLoop() == nullptr) {
316 // `block` without assignment to any loop is found
317 loop->AppendBlock(block);
318 } else if (block->GetLoop()->GetHeader() != loop->GetHeader()) {
319 // `block` from an inner loop id found, because its header differs from searching loop header
320 if (block->GetLoop()->GetOuterLoop() == nullptr) {
321 // Link outer loop and inner loop
322 block->GetLoop()->SetOuterLoop(loop);
323 loop->AppendInnerLoop(block->GetLoop());
324 }
325 }
326
327 for (auto pred : block->GetPredsBlocks()) {
328 NaturalLoopSearch(loop, pred);
329 }
330 }
331 }
332
SetLoopProperties(Loop * loop,uint32_t depth)333 void LoopAnalyzer::SetLoopProperties(Loop *loop, uint32_t depth)
334 {
335 loop->CheckInfinity();
336 loop->SetDepth(depth);
337 if (loop->IsInfinite()) {
338 GetGraph()->SetHasInfiniteLoop(true);
339 }
340 depth++;
341 for (auto innerLoop : loop->GetInnerLoops()) {
342 SetLoopProperties(innerLoop, depth);
343 }
344 }
345
CheckActualLengthAsLoopInitOrBound(Loop * loop)346 void LoopAnalyzer::CheckActualLengthAsLoopInitOrBound(Loop *loop)
347 {
348 loop->CheckActualLengthAsLoopInitOrBound();
349 }
350
AppendBlock(BasicBlock * block)351 void Loop::AppendBlock(BasicBlock *block)
352 {
353 ASSERT(std::find(blocks_.begin(), blocks_.end(), block) == blocks_.end());
354 block->SetLoop(this);
355 blocks_.push_back(block);
356 }
357
RemoveBlock(BasicBlock * block)358 void Loop::RemoveBlock(BasicBlock *block)
359 {
360 ASSERT(block != GetHeader());
361 ASSERT(!HasBackEdge(block));
362 #ifndef NDEBUG
363 for (auto innerLoop : GetInnerLoops()) {
364 ASSERT(block != innerLoop->GetPreHeader());
365 }
366 #endif
367
368 auto blockIt = std::find(blocks_.begin(), blocks_.end(), block);
369 ASSERT(blockIt != blocks_.end());
370 blocks_.erase(blockIt);
371 }
372
CheckUpdateAndInit(Inst * inst,bool forActualLengthAsInit=true)373 static bool CheckUpdateAndInit(Inst *inst, bool forActualLengthAsInit = true)
374 {
375 if (!inst->IsAddSub() || !inst->GetInput(1).GetInst()->IsConst()) {
376 return false;
377 }
378 auto constInst = inst->GetInput(1).GetInst()->CastToConstant();
379 if (constInst->GetType() != DataType::INT64) {
380 return false;
381 }
382 auto constVal = static_cast<int64_t>(constInst->GetIntValue());
383 bool res = false;
384 if (forActualLengthAsInit) {
385 res = inst->IsAdd() ? constVal < 0 : constVal > 0;
386 } else {
387 res = inst->IsAdd() ? constVal > 0 : constVal < 0;
388 }
389 return res;
390 }
391
CheckUpdateAndInitForBound(CompareInst * cmpInst,PhiInst * phiInst)392 bool Loop::CheckUpdateAndInitForBound(CompareInst *cmpInst, PhiInst *phiInst)
393 {
394 if (GetBackEdges().size() != 1 || phiInst->GetPhiInputBb(0) != GetPreHeader()) {
395 return false;
396 }
397 auto initInst = phiInst->GetPhiInput(GetPreHeader());
398 if (!initInst->IsConst()) {
399 return false;
400 }
401 auto initConstInst = initInst->CastToConstant();
402 // only support init val greater than zero
403 if (initConstInst->GetType() != DataType::INT64 || static_cast<int64_t>(initConstInst->GetIntValue()) < 0) {
404 return false;
405 }
406 auto updateInst = phiInst->GetPhiInput(GetBackEdges()[0]);
407 // check i < len and (i + posative num or i - negative num)
408 return ((cmpInst->GetCc() == ConditionCode::CC_GE && cmpInst->GetInput(0).GetInst() == phiInst) ||
409 (cmpInst->GetCc() == ConditionCode::CC_LE && cmpInst->GetInput(1).GetInst() == phiInst)) &&
410 CheckUpdateAndInit(updateInst, false);
411 }
412
CheckActualLengthVariantAsLoopInit(Inst * & loadObject,CompareInst * cmpInst,PhiInst * phiInst)413 void Loop::CheckActualLengthVariantAsLoopInit(Inst *&loadObject, CompareInst *cmpInst, PhiInst *phiInst)
414 {
415 if (cmpInst->GetCc() == ConditionCode::CC_GE || cmpInst->GetCc() == ConditionCode::CC_GT) {
416 if (!cmpInst->GetInput(0).GetInst()->IsConst()) {
417 return;
418 }
419 } else if (cmpInst->GetCc() == ConditionCode::CC_LE || cmpInst->GetCc() == ConditionCode::CC_LT) {
420 if (!cmpInst->GetInput(1).GetInst()->IsConst()) {
421 return;
422 }
423 } else {
424 return;
425 }
426 bool operand0IsConst = cmpInst->GetInput(0).GetInst()->IsConst();
427 auto boundInst = operand0IsConst ? cmpInst->GetInput(0).GetInst()->CastToConstant()
428 : cmpInst->GetInput(1).GetInst()->CastToConstant();
429 // only support bound value is zero (phi >= 0 or phi > 0)
430 if (boundInst->GetType() == DataType::INT64 && boundInst->GetIntValue() == 0) {
431 if (GetBackEdges().size() != 1 || phiInst->GetPhiInputBb(0) != GetPreHeader()) {
432 return;
433 }
434 auto updateInst = phiInst->GetPhiInput(GetBackEdges()[0]);
435 auto initInst = phiInst->GetPhiInput(GetPreHeader());
436 // check i - positive num or i + negative num
437 if (CheckUpdateAndInit(updateInst) && CheckUpdateAndInit(initInst)) {
438 if (initInst->GetInput(0).GetInst()->GetOpcode() == Opcode::LoadObject) {
439 loadObject = initInst->GetInput(0).GetInst();
440 }
441 }
442 }
443 }
444
CheckActualLengthVariantAsLoopBound(Inst * & loadObject,CompareInst * cmpInst,PhiInst * phiInst)445 void Loop::CheckActualLengthVariantAsLoopBound(Inst *&loadObject, CompareInst *cmpInst, PhiInst *phiInst)
446 {
447 bool operand0IsPhi = cmpInst->GetInput(0).GetInst()->IsPhi();
448 auto boundInst = operand0IsPhi ? cmpInst->GetInput(1).GetInst() : cmpInst->GetInput(0).GetInst();
449 // only support div operation
450 if (boundInst->GetOpcode() != Opcode::Div) {
451 return;
452 }
453 if (boundInst->GetInput(1).GetInst()->GetOpcode() != Opcode::ZeroCheck &&
454 !boundInst->GetInput(1).GetInst()->IsConst()) {
455 return;
456 }
457 auto cstInst = boundInst->GetInput(1).GetInst();
458 if (!cstInst->IsConst()) {
459 if (!cstInst->GetInput(0).GetInst()->IsConst()) {
460 return;
461 }
462 cstInst = cstInst->GetInput(0).GetInst();
463 }
464 auto constInst = cstInst->CastToConstant();
465 if (constInst->GetType() != DataType::INT64 || static_cast<int64_t>(constInst->GetIntValue()) < 1) {
466 return;
467 }
468 if (!CheckUpdateAndInitForBound(cmpInst, phiInst)) {
469 return;
470 }
471 if (boundInst->GetInput(0).GetInst()->GetOpcode() == Opcode::LoadObject) {
472 loadObject = boundInst->GetInput(0).GetInst();
473 }
474 }
475
CheckActualLengthAsLoopBound(Inst * & loadObject,CompareInst * cmpInst,PhiInst * phiInst)476 void Loop::CheckActualLengthAsLoopBound(Inst *&loadObject, CompareInst *cmpInst, PhiInst *phiInst)
477 {
478 if (!CheckUpdateAndInitForBound(cmpInst, phiInst)) {
479 return;
480 }
481 bool operand0IsLoadObj = cmpInst->GetInput(0).GetInst()->GetOpcode() == Opcode::LoadObject;
482 loadObject = operand0IsLoadObj ? cmpInst->GetInput(0).GetInst() : cmpInst->GetInput(1).GetInst();
483 }
484
485 // Check inst ifImm, compare and phi.
PrecheckInst(CompareInst * & cmpInst,PhiInst * & phiInst)486 bool Loop::PrecheckInst(CompareInst *&cmpInst, PhiInst *&phiInst)
487 {
488 BasicBlock *header = GetHeader();
489 Inst *lastInst = header->GetLastInst();
490 if (lastInst == nullptr || lastInst->GetOpcode() != Opcode::IfImm) {
491 return false;
492 }
493 auto ifImm = lastInst->CastToIfImm();
494 if (ifImm->GetCc() != CC_NE || ifImm->GetImm() != 0 || header->GetTrueSuccessor()->GetLoop() == header->GetLoop()) {
495 return false;
496 }
497 if (ifImm->GetInput(0).GetInst()->GetOpcode() != Opcode::Compare) {
498 return false;
499 }
500 cmpInst = ifImm->GetInput(0).GetInst()->CastToCompare();
501 if (cmpInst->GetInput(0).GetInst()->IsPhi()) {
502 phiInst = cmpInst->GetInput(0).GetInst()->CastToPhi();
503 }
504 if (cmpInst->GetInput(1).GetInst()->IsPhi()) {
505 if (phiInst != nullptr) {
506 return false;
507 }
508 phiInst = cmpInst->GetInput(1).GetInst()->CastToPhi();
509 }
510 return phiInst != nullptr && phiInst->GetInputsCount() == 2; // 2: input operands num
511 }
512
CheckActualLengthAsLoopInitOrBound()513 void Loop::CheckActualLengthAsLoopInitOrBound()
514 {
515 if (IsRoot()) {
516 return;
517 }
518 CompareInst *cmpInst = nullptr;
519 PhiInst *phiInst = nullptr;
520 if (!PrecheckInst(cmpInst, phiInst)) {
521 return;
522 }
523 Inst *loadObject = nullptr;
524 if (cmpInst->GetInput(0).GetInst()->GetOpcode() == Opcode::LoadObject ||
525 cmpInst->GetInput(1).GetInst()->GetOpcode() == Opcode::LoadObject) {
526 // ex.1 for i in [0, actualLength)
527 CheckActualLengthAsLoopBound(loadObject, cmpInst, phiInst);
528 } else if (cmpInst->GetInput(0).GetInst()->IsConst() || cmpInst->GetInput(1).GetInst()->IsConst()) {
529 // ex.2 for i in [actualLength - 1, 0]
530 CheckActualLengthVariantAsLoopInit(loadObject, cmpInst, phiInst);
531 } else {
532 // ex.3 for i in [0, actualLength / 2)
533 CheckActualLengthVariantAsLoopBound(loadObject, cmpInst, phiInst);
534 }
535 Inst *arrayOriginRef = nullptr;
536 if (CheckArrayField(RuntimeInterface::ArrayField::ACTUAL_LENGTH, loadObject, arrayOriginRef)) {
537 SetArrayIndexVariable(phiInst);
538 ASSERT(arrayOriginRef != nullptr);
539 SetArrayOriginRef(arrayOriginRef);
540 }
541 }
542
IsOsrLoop() const543 bool Loop::IsOsrLoop() const
544 {
545 return !IsRoot() && GetHeader()->IsOsrEntry();
546 }
547
IsTryCatchLoop() const548 bool Loop::IsTryCatchLoop() const
549 {
550 return !IsRoot() && GetHeader()->IsCatchBegin();
551 }
552
553 /*
554 * Check if this loop is inside other
555 */
IsInside(Loop * other)556 bool Loop::IsInside(Loop *other)
557 {
558 auto outer = this->GetOuterLoop();
559 while (outer != nullptr) {
560 if (outer == other) {
561 return true;
562 }
563 outer = outer->GetOuterLoop();
564 }
565 return false;
566 }
567
MoveHeaderToSucc()568 void Loop::MoveHeaderToSucc()
569 {
570 ASSERT(header_->GetSuccsBlocks().size() == 1);
571 header_ = header_->GetSuccessor(0);
572 ASSERT(header_->GetLoop() == this);
573 auto it = std::find(blocks_.begin(), blocks_.end(), header_);
574 ASSERT(it != blocks_.end());
575 std::swap(*it, *blocks_.begin());
576 }
577
CheckInfinity()578 void Loop::CheckInfinity()
579 {
580 isInfinite_ = false;
581 if (isRoot_) {
582 return;
583 }
584 auto outerLoop = GetOuterLoop();
585 for (auto block : GetBlocks()) {
586 const auto &succs = block->GetSuccsBlocks();
587 bool hasExit = std::find_if(succs.begin(), succs.end(), [&outerLoop](const BasicBlock *bb) {
588 return bb->GetLoop() == outerLoop;
589 }) != succs.end();
590 if (hasExit) {
591 return;
592 }
593 }
594 isInfinite_ = true;
595 }
596
IsPostExitBlock(const BasicBlock * block) const597 bool Loop::IsPostExitBlock(const BasicBlock *block) const
598 {
599 for (auto loopBlock : GetBlocks()) {
600 for (auto succ : loopBlock->GetSuccsBlocks()) {
601 if (succ->GetLoop() != GetOuterLoop()) {
602 continue;
603 }
604
605 if (succ == block) {
606 return true;
607 }
608 }
609 }
610
611 return false;
612 }
613
614 /*
615 * Find outside block for the loop with single back-edge exit
616 */
GetLoopOutsideSuccessor(Loop * loop)617 BasicBlock *GetLoopOutsideSuccessor(Loop *loop)
618 {
619 ASSERT(loop->GetBackEdges().size() == 1);
620 auto backEdge = loop->GetBackEdges()[0];
621 auto headerSuccIdx = backEdge->GetSuccBlockIndex(loop->GetHeader());
622 ASSERT(backEdge->GetSuccsBlocks().size() == MAX_SUCCS_NUM);
623 auto outsideBlock = backEdge->GetSuccessor(1 - headerSuccIdx);
624 ASSERT(outsideBlock != nullptr);
625 return outsideBlock;
626 }
627
628 /**
629 * Check if the loop block sequence meets the requirements:
630 * - there is only one back-edge;
631 * - there is only one exit-point - from the back-edge;
632 */
IsLoopSingleBackEdgeExitPoint(Loop * loop)633 bool IsLoopSingleBackEdgeExitPoint(Loop *loop)
634 {
635 ASSERT(loop != nullptr);
636 if (loop->IsIrreducible()) {
637 return false;
638 }
639 if (loop->GetBackEdges().size() != 1) {
640 return false;
641 }
642 auto backEdge = loop->GetBackEdges()[0];
643 // Check there are no side-exits
644 for (auto block : loop->GetBlocks()) {
645 if (block == backEdge) {
646 continue;
647 }
648 for (auto succ : block->GetSuccsBlocks()) {
649 if (succ->GetLoop() != loop && !succ->GetLoop()->IsInside(loop)) {
650 return false;
651 }
652 }
653 }
654 return true;
655 }
656 } // namespace ark::compiler
657