• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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