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 "cg_dominance.h"
17 #include <set>
18 #include "cg_option.h"
19 #include "cgfunc.h"
20
21 /*
22 * This phase build dominance
23 */
24 namespace maplebe {
25 constexpr uint32 kBBVectorInitialSize = 2;
PostOrderWalk(const BB & bb,int32 & pid,MapleVector<bool> & visitedMap)26 void DomAnalysis::PostOrderWalk(const BB &bb, int32 &pid, MapleVector<bool> &visitedMap)
27 {
28 DEBUG_ASSERT(bb.GetId() < visitedMap.size(), "index out of range in Dominance::PostOrderWalk");
29 if (visitedMap[bb.GetId()]) {
30 return;
31 }
32 visitedMap[bb.GetId()] = true;
33 for (const BB *suc : bb.GetSuccs()) {
34 PostOrderWalk(*suc, pid, visitedMap);
35 }
36 DEBUG_ASSERT(bb.GetId() < postOrderIDVec.size(), "index out of range in Dominance::PostOrderWalk");
37 postOrderIDVec[bb.GetId()] = pid++;
38 }
39
GenPostOrderID()40 void DomAnalysis::GenPostOrderID()
41 {
42 DEBUG_ASSERT(!bbVec.empty(), "size to be allocated is 0");
43 MapleVector<bool> visitedMap(bbVec.size() + 1, false, cgFunc.GetFuncScopeAllocator()->Adapter());
44 int32 postOrderID = 0;
45 PostOrderWalk(commonEntryBB, postOrderID, visitedMap);
46 // initialize reversePostOrder
47 int32 maxPostOrderID = postOrderID - 1;
48 reversePostOrder.resize(static_cast<uint32>(maxPostOrderID + 1));
49 for (size_t i = 0; i < postOrderIDVec.size(); ++i) {
50 int32 postOrderNo = postOrderIDVec[i];
51 if (postOrderNo == -1) {
52 continue;
53 }
54 reversePostOrder[static_cast<uint32>(maxPostOrderID - postOrderNo)] = bbVec[i];
55 }
56 }
57
Intersect(BB & bb1,const BB & bb2)58 BB *DomAnalysis::Intersect(BB &bb1, const BB &bb2)
59 {
60 auto *ptrBB1 = &bb1;
61 auto *ptrBB2 = &bb2;
62 while (ptrBB1 != ptrBB2) {
63 while (postOrderIDVec[ptrBB1->GetId()] < postOrderIDVec[ptrBB2->GetId()]) {
64 ptrBB1 = GetDom(ptrBB1->GetId());
65 }
66 while (postOrderIDVec[ptrBB2->GetId()] < postOrderIDVec[ptrBB1->GetId()]) {
67 ptrBB2 = GetDom(ptrBB2->GetId());
68 }
69 }
70 return ptrBB1;
71 }
72
CommonEntryBBIsPred(const BB & bb) const73 bool DominanceBase::CommonEntryBBIsPred(const BB &bb) const
74 {
75 for (const BB *suc : commonEntryBB.GetSuccs()) {
76 if (suc == &bb) {
77 return true;
78 }
79 }
80 return false;
81 }
82
83 // Figure 3 in "A Simple, Fast Dominance Algorithm" by Keith Cooper et al.
ComputeDominance()84 void DomAnalysis::ComputeDominance()
85 {
86 SetDom(commonEntryBB.GetId(), &commonEntryBB);
87 bool changed;
88 do {
89 changed = false;
90 for (size_t i = 1; i < reversePostOrder.size(); ++i) {
91 BB *bb = reversePostOrder[i];
92 if (bb == nullptr) {
93 continue;
94 }
95 BB *pre = nullptr;
96 auto it = bb->GetPredsBegin();
97 if (CommonEntryBBIsPred(*bb) || bb->GetPreds().empty()) {
98 pre = &commonEntryBB;
99 } else {
100 pre = *it;
101 }
102 ++it;
103 while ((GetDom(pre->GetId()) == nullptr || pre == bb) && it != bb->GetPredsEnd()) {
104 pre = *it;
105 ++it;
106 }
107 BB *newIDom = pre;
108 for (; it != bb->GetPredsEnd(); ++it) {
109 pre = *it;
110 if (GetDom(pre->GetId()) != nullptr && pre != bb) {
111 newIDom = Intersect(*pre, *newIDom);
112 }
113 }
114 if (GetDom(bb->GetId()) != newIDom) {
115 SetDom(bb->GetId(), newIDom);
116 changed = true;
117 }
118 }
119 } while (changed);
120 }
121
122 // Figure 5 in "A Simple, Fast Dominance Algorithm" by Keith Cooper et al.
ComputeDomFrontiers()123 void DomAnalysis::ComputeDomFrontiers()
124 {
125 for (const BB *bb : bbVec) {
126 if (bb == nullptr || bb == &commonExitBB) {
127 continue;
128 }
129 if (bb->GetPreds().size() < kBBVectorInitialSize) {
130 continue;
131 }
132 for (BB *pre : bb->GetPreds()) {
133 BB *runner = pre;
134 while (runner != nullptr && runner != GetDom(bb->GetId()) && runner != &commonEntryBB) {
135 if (!HasDomFrontier(runner->GetId(), bb->GetId())) {
136 domFrontier[runner->GetId()].push_back(bb->GetId());
137 }
138 runner = GetDom(runner->GetId());
139 }
140 }
141 }
142 // check entry bb's predBB, such as :
143 // bb1 is commonEntryBB, bb2 is entryBB, bb2 is domFrontier of bb3 and bb7.
144 // 1
145 // |
146 // 2 <-
147 // / |
148 // 3 |
149 // / \ |
150 // 4 7---
151 // / \ ^
152 // | | |
153 // 5-->6--
154 for (BB *succ : commonEntryBB.GetSuccs()) {
155 if (succ->GetPreds().size() != 1) { // Only deal with one pred bb.
156 continue;
157 }
158 for (BB *pre : succ->GetPreds()) {
159 BB *runner = pre;
160 while (runner != GetDom(succ->GetId()) && runner != &commonEntryBB && runner != succ) {
161 if (!HasDomFrontier(runner->GetId(), succ->GetId())) {
162 domFrontier[runner->GetId()].push_back(succ->GetId());
163 }
164 runner = GetDom(runner->GetId());
165 }
166 }
167 }
168 }
169
ComputeDomChildren()170 void DomAnalysis::ComputeDomChildren()
171 {
172 for (auto *bb : reversePostOrder) {
173 if (bb == nullptr || GetDom(bb->GetId()) == nullptr) {
174 continue;
175 }
176 BB *parent = GetDom(bb->GetId());
177 if (parent == bb) {
178 continue;
179 }
180 domChildren[parent->GetId()].push_back(bb->GetId());
181 }
182 }
183
184 // bbidMarker indicates that the iterDomFrontier results for bbid < bbidMarker
185 // have been computed
GetIterDomFrontier(const BB * bb,MapleSet<uint32> * dfset,uint32 bbidMarker,std::vector<bool> & visitedMap)186 void DomAnalysis::GetIterDomFrontier(const BB *bb, MapleSet<uint32> *dfset, uint32 bbidMarker,
187 std::vector<bool> &visitedMap)
188 {
189 if (visitedMap[bb->GetId()]) {
190 return;
191 }
192 visitedMap[bb->GetId()] = true;
193 for (uint32 frontierbbid : domFrontier[bb->GetId()]) {
194 (void)dfset->insert(frontierbbid);
195 if (frontierbbid < bbidMarker) { // union with its computed result
196 dfset->insert(iterDomFrontier[frontierbbid].begin(), iterDomFrontier[frontierbbid].end());
197 } else { // recursive call
198 BB *frontierbb = bbVec[frontierbbid];
199 GetIterDomFrontier(frontierbb, dfset, bbidMarker, visitedMap);
200 }
201 }
202 }
203
ComputeIterDomFrontiers()204 void DomAnalysis::ComputeIterDomFrontiers()
205 {
206 for (BB *bb : bbVec) {
207 if (bb == nullptr || bb == &commonExitBB) {
208 continue;
209 }
210 std::vector<bool> visitedMap(bbVec.size(), false);
211 GetIterDomFrontier(bb, &iterDomFrontier[bb->GetId()], bb->GetId(), visitedMap);
212 }
213 }
214
ComputeDtPreorder(const BB & bb,uint32 & num)215 uint32 DomAnalysis::ComputeDtPreorder(const BB &bb, uint32 &num)
216 {
217 DEBUG_ASSERT(num < dtPreOrder.size(), "index out of range in Dominance::ComputeDtPreorder");
218 dtPreOrder[num] = bb.GetId();
219 dtDfn[bb.GetId()] = num;
220 uint32 maxDtDfnOut = num;
221 ++num;
222
223 for (uint32 k : domChildren[bb.GetId()]) {
224 maxDtDfnOut = ComputeDtPreorder(*bbVec[k], num);
225 }
226
227 dtDfnOut[bb.GetId()] = maxDtDfnOut;
228 return maxDtDfnOut;
229 }
230
231 // true if b1 dominates b2
Dominate(const BB & bb1,const BB & bb2)232 bool DomAnalysis::Dominate(const BB &bb1, const BB &bb2)
233 {
234 return dtDfn[bb1.GetId()] <= dtDfn[bb2.GetId()] && dtDfnOut[bb1.GetId()] >= dtDfnOut[bb2.GetId()];
235 }
236
Compute()237 void DomAnalysis::Compute()
238 {
239 GenPostOrderID();
240 ComputeDominance();
241 ComputeDomFrontiers();
242 ComputeDomChildren();
243 ComputeIterDomFrontiers();
244 uint32 num = 0;
245 (void)ComputeDtPreorder(*cgFunc.GetFirstBB(), num);
246 GetDtPreOrder().resize(num);
247 }
248
Dump()249 void DomAnalysis::Dump()
250 {
251 for (BB *bb : reversePostOrder) {
252 LogInfo::MapleLogger() << "postorder no " << postOrderIDVec[bb->GetId()];
253 LogInfo::MapleLogger() << " is bb:" << bb->GetId();
254 LogInfo::MapleLogger() << " im_dom is bb:" << GetDom(bb->GetId())->GetId();
255 LogInfo::MapleLogger() << " domfrontier: [";
256 for (uint32 id : domFrontier[bb->GetId()]) {
257 LogInfo::MapleLogger() << id << " ";
258 }
259 LogInfo::MapleLogger() << "] domchildren: [";
260 for (uint32 id : domChildren[bb->GetId()]) {
261 LogInfo::MapleLogger() << id << " ";
262 }
263 LogInfo::MapleLogger() << "]\n";
264 }
265 LogInfo::MapleLogger() << "\npreorder traversal of dominator tree:";
266 for (uint32 id : dtPreOrder) {
267 LogInfo::MapleLogger() << id << " ";
268 }
269 LogInfo::MapleLogger() << "\n\n";
270 }
271
272 /* ================= for PostDominance ================= */
PdomPostOrderWalk(const BB & bb,int32 & pid,MapleVector<bool> & visitedMap)273 void PostDomAnalysis::PdomPostOrderWalk(const BB &bb, int32 &pid, MapleVector<bool> &visitedMap)
274 {
275 DEBUG_ASSERT(bb.GetId() < visitedMap.size(), "index out of range in Dominance::PdomPostOrderWalk");
276 if (bbVec[bb.GetId()] == nullptr) {
277 return;
278 }
279 if (visitedMap[bb.GetId()]) {
280 return;
281 }
282 visitedMap[bb.GetId()] = true;
283 for (BB *pre : bb.GetPreds()) {
284 PdomPostOrderWalk(*pre, pid, visitedMap);
285 }
286 DEBUG_ASSERT(bb.GetId() < pdomPostOrderIDVec.size(), "index out of range in Dominance::PdomPostOrderWalk");
287 pdomPostOrderIDVec[bb.GetId()] = pid++;
288 }
289
PdomGenPostOrderID()290 void PostDomAnalysis::PdomGenPostOrderID()
291 {
292 DEBUG_ASSERT(!bbVec.empty(), "call calloc failed in Dominance::PdomGenPostOrderID");
293 MapleVector<bool> visitedMap(bbVec.size(), false, cgFunc.GetFuncScopeAllocator()->Adapter());
294 int32 postOrderID = 0;
295 PdomPostOrderWalk(commonExitBB, postOrderID, visitedMap);
296 // initialize pdomReversePostOrder
297 int32 maxPostOrderID = postOrderID - 1;
298 pdomReversePostOrder.resize(static_cast<uint32>(maxPostOrderID + 1));
299 for (size_t i = 0; i < pdomPostOrderIDVec.size(); ++i) {
300 int32 postOrderNo = pdomPostOrderIDVec[i];
301 if (postOrderNo == -1) {
302 continue;
303 }
304 pdomReversePostOrder[static_cast<uint32>(maxPostOrderID - postOrderNo)] = bbVec[i];
305 }
306 }
307
PdomIntersect(BB & bb1,const BB & bb2)308 BB *PostDomAnalysis::PdomIntersect(BB &bb1, const BB &bb2)
309 {
310 auto *ptrBB1 = &bb1;
311 auto *ptrBB2 = &bb2;
312 while (ptrBB1 != ptrBB2) {
313 while (pdomPostOrderIDVec[ptrBB1->GetId()] < pdomPostOrderIDVec[ptrBB2->GetId()]) {
314 ptrBB1 = GetPdom(ptrBB1->GetId());
315 }
316 while (pdomPostOrderIDVec[ptrBB2->GetId()] < pdomPostOrderIDVec[ptrBB1->GetId()]) {
317 ptrBB2 = GetPdom(ptrBB2->GetId());
318 }
319 }
320 return ptrBB1;
321 }
322
323 // Figure 3 in "A Simple, Fast Dominance Algorithm" by Keith Cooper et al.
ComputePostDominance()324 void PostDomAnalysis::ComputePostDominance()
325 {
326 SetPdom(commonExitBB.GetId(), &commonExitBB);
327 bool changed = false;
328 do {
329 changed = false;
330 for (size_t i = 1; i < pdomReversePostOrder.size(); ++i) {
331 BB *bb = pdomReversePostOrder[i];
332 BB *suc = nullptr;
333 auto it = bb->GetSuccsBegin();
334 if (cgFunc.IsExitBB(*bb) || bb->GetSuccs().empty() || (bb->IsWontExit() && bb->GetKind() == BB::kBBGoto)) {
335 suc = &commonExitBB;
336 } else {
337 suc = *it;
338 }
339 ++it;
340 while ((GetPdom(suc->GetId()) == nullptr || suc == bb) && it != bb->GetSuccsEnd()) {
341 suc = *it;
342 ++it;
343 }
344 if (GetPdom(suc->GetId()) == nullptr) {
345 suc = &commonExitBB;
346 }
347 BB *newIDom = suc;
348 for (; it != bb->GetSuccsEnd(); ++it) {
349 suc = *it;
350 if (GetPdom(suc->GetId()) != nullptr && suc != bb) {
351 newIDom = PdomIntersect(*suc, *newIDom);
352 }
353 }
354 if (GetPdom(bb->GetId()) != newIDom) {
355 SetPdom(bb->GetId(), newIDom);
356 DEBUG_ASSERT(GetPdom(newIDom->GetId()) != nullptr, "null ptr check");
357 changed = true;
358 }
359 }
360 } while (changed);
361 }
362
363 // Figure 5 in "A Simple, Fast Dominance Algorithm" by Keith Cooper et al.
ComputePdomFrontiers()364 void PostDomAnalysis::ComputePdomFrontiers()
365 {
366 for (const BB *bb : bbVec) {
367 if (bb == nullptr || bb == &commonEntryBB) {
368 continue;
369 }
370 if (bb->GetSuccs().size() < kBBVectorInitialSize) {
371 continue;
372 }
373 for (BB *suc : bb->GetSuccs()) {
374 BB *runner = suc;
375 while (runner != GetPdom(bb->GetId()) && runner != &commonEntryBB) {
376 if (!HasPdomFrontier(runner->GetId(), bb->GetId())) {
377 pdomFrontier[runner->GetId()].push_back(bb->GetId());
378 }
379 DEBUG_ASSERT(GetPdom(runner->GetId()) != nullptr, "ComputePdomFrontiers: pdoms[] is nullptr");
380 runner = GetPdom(runner->GetId());
381 }
382 }
383 }
384 }
385
ComputePdomChildren()386 void PostDomAnalysis::ComputePdomChildren()
387 {
388 for (const BB *bb : bbVec) {
389 if (bb == nullptr || GetPdom(bb->GetId()) == nullptr) {
390 continue;
391 }
392 const BB *parent = GetPdom(bb->GetId());
393 if (parent == bb) {
394 continue;
395 }
396 pdomChildren[parent->GetId()].push_back(bb->GetId());
397 }
398 }
399
400 // bbidMarker indicates that the iterPdomFrontier results for bbid < bbidMarker
401 // have been computed
GetIterPdomFrontier(const BB * bb,MapleSet<uint32> * dfset,uint32 bbidMarker,std::vector<bool> & visitedMap)402 void PostDomAnalysis::GetIterPdomFrontier(const BB *bb, MapleSet<uint32> *dfset, uint32 bbidMarker,
403 std::vector<bool> &visitedMap)
404 {
405 if (visitedMap[bb->GetId()]) {
406 return;
407 }
408 visitedMap[bb->GetId()] = true;
409 for (uint32 frontierbbid : pdomFrontier[bb->GetId()]) {
410 (void)dfset->insert(frontierbbid);
411 if (frontierbbid < bbidMarker) { // union with its computed result
412 dfset->insert(iterPdomFrontier[frontierbbid].begin(), iterPdomFrontier[frontierbbid].end());
413 } else { // recursive call
414 BB *frontierbb = bbVec[frontierbbid];
415 GetIterPdomFrontier(frontierbb, dfset, bbidMarker, visitedMap);
416 }
417 }
418 }
419
ComputeIterPdomFrontiers()420 void PostDomAnalysis::ComputeIterPdomFrontiers()
421 {
422 for (BB *bb : bbVec) {
423 if (bb == nullptr || bb == &commonEntryBB) {
424 continue;
425 }
426 std::vector<bool> visitedMap(bbVec.size(), false);
427 GetIterPdomFrontier(bb, &iterPdomFrontier[bb->GetId()], bb->GetId(), visitedMap);
428 }
429 }
430
ComputePdtPreorder(const BB & bb,uint32 & num)431 uint32 PostDomAnalysis::ComputePdtPreorder(const BB &bb, uint32 &num)
432 {
433 DEBUG_ASSERT(num < pdtPreOrder.size(), "index out of range in Dominance::ComputePdtPreOrder");
434 pdtPreOrder[num] = bb.GetId();
435 pdtDfn[bb.GetId()] = num;
436 uint32 maxDtDfnOut = num;
437 ++num;
438
439 for (uint32 k : pdomChildren[bb.GetId()]) {
440 maxDtDfnOut = ComputePdtPreorder(*bbVec[k], num);
441 }
442
443 pdtDfnOut[bb.GetId()] = maxDtDfnOut;
444 return maxDtDfnOut;
445 }
446
447 // true if b1 postdominates b2
PostDominate(const BB & bb1,const BB & bb2)448 bool PostDomAnalysis::PostDominate(const BB &bb1, const BB &bb2)
449 {
450 return pdtDfn[bb1.GetId()] <= pdtDfn[bb2.GetId()] && pdtDfnOut[bb1.GetId()] >= pdtDfnOut[bb2.GetId()];
451 }
452
Dump()453 void PostDomAnalysis::Dump()
454 {
455 for (BB *bb : pdomReversePostOrder) {
456 LogInfo::MapleLogger() << "pdom_postorder no " << pdomPostOrderIDVec[bb->GetId()];
457 LogInfo::MapleLogger() << " is bb:" << bb->GetId();
458 LogInfo::MapleLogger() << " im_pdom is bb:" << GetPdom(bb->GetId())->GetId();
459 LogInfo::MapleLogger() << " pdomfrontier: [";
460 for (uint32 id : pdomFrontier[bb->GetId()]) {
461 LogInfo::MapleLogger() << id << " ";
462 }
463 LogInfo::MapleLogger() << "] pdomchildren: [";
464 for (uint32 id : pdomChildren[bb->GetId()]) {
465 LogInfo::MapleLogger() << id << " ";
466 }
467 LogInfo::MapleLogger() << "]\n";
468 }
469 LogInfo::MapleLogger() << "\n";
470 LogInfo::MapleLogger() << "preorder traversal of post-dominator tree:";
471 for (uint32 id : pdtPreOrder) {
472 LogInfo::MapleLogger() << id << " ";
473 }
474 LogInfo::MapleLogger() << "\n\n";
475 }
476
Compute()477 void PostDomAnalysis::Compute()
478 {
479 PdomGenPostOrderID();
480 ComputePostDominance();
481 ComputePdomFrontiers();
482 ComputePdomChildren();
483 ComputeIterPdomFrontiers();
484 uint32 num = 0;
485 (void)ComputePdtPreorder(GetCommonExitBB(), num);
486 ResizePdtPreOrder(num);
487 }
488
PhaseRun(maplebe::CGFunc & f)489 bool CgDomAnalysis::PhaseRun(maplebe::CGFunc &f)
490 {
491 MemPool *domMemPool = GetPhaseMemPool();
492 domAnalysis =
493 domMemPool->New<DomAnalysis>(f, *domMemPool, *domMemPool, f.GetAllBBs(), *f.GetFirstBB(), *f.GetCommonExitBB());
494 domAnalysis->Compute();
495 if (CG_DEBUG_FUNC(f)) {
496 domAnalysis->Dump();
497 }
498 return false;
499 }
MAPLE_ANALYSIS_PHASE_REGISTER(CgDomAnalysis,domanalysis)500 MAPLE_ANALYSIS_PHASE_REGISTER(CgDomAnalysis, domanalysis)
501
502 bool CgPostDomAnalysis::PhaseRun(maplebe::CGFunc &f)
503 {
504 MemPool *pdomMemPool = GetPhaseMemPool();
505 pdomAnalysis = pdomMemPool->New<PostDomAnalysis>(f, *pdomMemPool, *pdomMemPool, f.GetAllBBs(), *f.GetFirstBB(),
506 *f.GetCommonExitBB());
507 pdomAnalysis->Compute();
508 if (CG_DEBUG_FUNC(f)) {
509 pdomAnalysis->Dump();
510 }
511 return false;
512 }
513 MAPLE_ANALYSIS_PHASE_REGISTER(CgPostDomAnalysis, pdomanalysis)
514 } /* namespace maplebe */
515