1 /*
2  * Copyright (c) 2023 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 "loop.h"
17 #include "optimize_common.h"
18 
19 // This phase analyses the CFG and identify the loops. The implementation is
20 // based on the idea that, given two basic block a and b, if b is a's pred and
21 // a dominates b, then there is a loop from a to b. Loop identification is done
22 // in a preorder traversal of the dominator tree. In this order, outer loop is
23 // always detected before its nested loop(s). The building of the LoopDesc data
24 // structure takes advantage of this ordering.
25 namespace maplebe {
Dump() const26 void LoopDesc::Dump() const
27 {
28     LogInfo::MapleLogger() << "LoopDesc:" << header.GetId() << ", nest depth:" << nestDepth;
29     if (parentLoop != nullptr) {
30         LogInfo::MapleLogger() << ", parent:" << parentLoop->GetHeader().GetId();
31     }
32     LogInfo::MapleLogger() << "\n\tbackedge:";
33     for (auto bbId : backEdges) {
34         LogInfo::MapleLogger() << bbId << " ";
35     }
36     LogInfo::MapleLogger() << "\n\tmembers:";
37     for (auto bbId : loopBBs) {
38         LogInfo::MapleLogger() << bbId << " ";
39     }
40     LogInfo::MapleLogger() << "\n\texitBB:";
41     for (auto bbId : exitBBs) {
42         LogInfo::MapleLogger() << bbId << " ";
43     }
44     if (!childLoops.empty()) {
45         LogInfo::MapleLogger() << "\n\tchild loops:";
46         for (auto *childLoop : childLoops) {
47             LogInfo::MapleLogger() << childLoop->GetHeader().GetId() << " ";
48         }
49     }
50     LogInfo::MapleLogger() << "\n\n";
51 }
52 
GetOrCreateLoopDesc(BB &headBB)53 LoopDesc *LoopAnalysis::GetOrCreateLoopDesc(BB &headBB)
54 {
55     auto *loop = bbLoopParent[headBB.GetId()];
56     if (loop == nullptr || loop->GetHeader().GetId() != headBB.GetId()) {
57         // If the headBB is not in loop or loop's header is not the headBB, create a new loop.
58         loop = alloc.New<LoopDesc>(alloc, headBB);
59         loops.push_back(loop);
60     }
61     return loop;
62 }
63 
SetLoopParent4BB(const BB &bb, LoopDesc &loopDesc)64 void LoopAnalysis::SetLoopParent4BB(const BB &bb, LoopDesc &loopDesc)
65 {
66     if (bbLoopParent[bb.GetId()] != nullptr && bbLoopParent[bb.GetId()] != &loopDesc) {
67         if (loopDesc.GetParentLoop() == nullptr) {
68             loopDesc.SetParentLoop(*bbLoopParent[bb.GetId()]);
69             ASSERT_NOT_NULL(loopDesc.GetParentLoop());
70             loopDesc.GetParentLoop()->InsertChildLoops(loopDesc);
71             loopDesc.SetNestDepth(loopDesc.GetParentLoop()->GetNestDepth() + 1);
72         }
73     }
74     loopDesc.InsertLoopBBs(bb);
75     bbLoopParent[bb.GetId()] = &loopDesc;
76 }
77 
SetExitBBs(LoopDesc &loop) const78 void LoopAnalysis::SetExitBBs(LoopDesc &loop) const
79 {
80     // if loopBBs succs not in the loop, the succs is the loop's exitBB
81     for (auto bbId : loop.GetLoopBBs()) {
82         auto *bb = cgFunc.GetBBFromID(bbId);
83         for (auto *succ : bb->GetSuccs()) {
84             if (loop.Has(*succ)) {
85                 continue;
86             }
87             loop.InsertExitBBs(*succ);
88         }
89     }
90 }
91 
GenerateLoop(BB *bb)92 void LoopAnalysis::GenerateLoop(BB *bb)
93 {
94     for (auto *pred : bb->GetPreds()) {
95         if (!dom.Dominate(*bb, *pred)) {
96             continue;
97         }
98         auto *loop = GetOrCreateLoopDesc(*bb);
99         loop->InsertBackEdges(*pred);
100         std::list<BB*> bodyList;
101         bodyList.push_back(pred);
102         while (!bodyList.empty()) {
103             auto *curBB = bodyList.front();
104             bodyList.pop_front();
105             // skip bb or if it has already been dealt with
106             if (curBB == bb || loop->Has(*curBB)) {
107                 continue;
108             }
109             SetLoopParent4BB(*curBB, *loop);
110             for (auto *curPred : curBB->GetPreds()) {
111                 bodyList.push_back(curPred);
112             }
113         }
114         SetLoopParent4BB(*bb, *loop);
115         SetExitBBs(*loop);
116     }
117 }
118 
ProcessBB(BB &entryBB)119 void LoopAnalysis::ProcessBB(BB &entryBB)
120 {
121     std::queue<BB *> allBBs;
122     allBBs.emplace(&entryBB);
123     while (!allBBs.empty()) {
124         BB *bb = allBBs.front();
125         allBBs.pop();
126         if (bb == cgFunc.GetCommonExitBB()) {
127             continue;
128         }
129 
130         // generate loop based on the dom information
131         GenerateLoop(bb);
132         // process dom tree
133         for (auto domChildBBId : dom.GetDomChildren(bb->GetId())) {
134             allBBs.emplace(cgFunc.GetBBFromID(domChildBBId));
135         }
136     }
137 }
138 
Analysis()139 void LoopAnalysis::Analysis()
140 {
141     std::vector<BB*> entryBBs;
142     FOR_ALL_BB(bb, (&cgFunc))
143     {
144         if (bb->GetPreds().size() == 0) {
145             entryBBs.push_back(bb);
146         }
147     }
148 
149     for (auto *bb : entryBBs) {
150         ProcessBB(*bb);
151     }
152 }
153 
GetAnalysisDependence(AnalysisDep &aDep) const154 void CgLoopAnalysis::GetAnalysisDependence(AnalysisDep &aDep) const
155 {
156     aDep.AddRequired<CgDomAnalysis>();
157     aDep.SetPreservedAll();
158 }
159 
PhaseRun(maplebe::CGFunc &f)160 bool CgLoopAnalysis::PhaseRun(maplebe::CGFunc &f)
161 {
162     auto *domInfo = GET_ANALYSIS(CgDomAnalysis, f);
163     auto *memPool = GetPhaseMemPool();
164     loop = memPool->New<LoopAnalysis>(f, *memPool, *domInfo);
165     loop->Analysis();
166     if (CG_DEBUG_FUNC(f)) {
167         loop->Dump();
168         // do dot gen after detection so the loop backedge can be properly colored using the loop info
169         DotGenerator::GenerateDot("buildloop", f, f.GetMirModule(), f.GetName());
170     }
171     return false;
172 }
173 MAPLE_ANALYSIS_PHASE_REGISTER(CgLoopAnalysis, loopanalysis)
174 } /* namespace maplebe */
175