• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_cfg.h"
17 #if TARGAARCH64
18 #include "aarch64_insn.h"
19 #endif
20 #if defined(TARGRISCV64) && TARGRISCV64
21 #include "riscv64_insn.h"
22 #endif
23 #if TARGARM32
24 #include "arm32_insn.h"
25 #endif
26 #include "cg_option.h"
27 #include "mpl_logging.h"
28 #if TARGX86_64
29 #include "x64_cgfunc.h"
30 #include "cg.h"
31 #endif
32 #include "triple.h"
33 #include <cstdlib>
34 
35 namespace maplebe {
BuildCFG()36 void CGCFG::BuildCFG()
37 {
38     if (cgFunc->HasBuiltCfg()) {
39         return;
40     }
41     /*
42      * Second Pass:
43      * Link preds/succs in the BBs
44      */
45     BB *firstBB = cgFunc->GetFirstBB();
46     for (BB *curBB = firstBB; curBB != nullptr; curBB = curBB->GetNext()) {
47         BB::BBKind kind = curBB->GetKind();
48         switch (kind) {
49             case BB::kBBIntrinsic:
50                 /*
51                  * An intrinsic BB append a MOP_wcbnz instruction at the end, check
52                  * AArch64CGFunc::SelectIntrinsicCall(IntrinsiccallNode *intrinsiccallNode) for details
53                  */
54                 CHECK_NULL_FATAL(curBB->GetLastMachineInsn());
55                 if (!curBB->GetLastMachineInsn()->IsBranch()) {
56                     break;
57                 }
58                 /* else fall through */
59                 [[clang::fallthrough]];
60             case BB::kBBIf: {
61                 BB *fallthruBB = curBB->GetNext();
62                 curBB->PushBackSuccs(*fallthruBB);
63                 fallthruBB->PushBackPreds(*curBB);
64                 Insn *branchInsn = curBB->GetLastMachineInsn();
65                 CHECK_FATAL(branchInsn != nullptr, "machine instruction must be exist in ifBB");
66                 DEBUG_ASSERT(branchInsn->IsCondBranch(), "must be a conditional branch generated from an intrinsic");
67                 /* Assume the last non-null operand is the branch target */
68                 uint32 opSz = branchInsn->GetOperandSize();
69                 DEBUG_ASSERT(opSz >= 1, "lastOpndIndex's opnd is greater than 1");
70                 Operand &lastOpnd = branchInsn->GetOperand(opSz - 1u);
71                 DEBUG_ASSERT(lastOpnd.IsLabelOpnd(), "label Operand must be exist in branch insn");
72                 auto &labelOpnd = static_cast<LabelOperand &>(lastOpnd);
73                 BB *brToBB = cgFunc->GetBBFromLab2BBMap(labelOpnd.GetLabelIndex());
74                 if (fallthruBB->GetId() != brToBB->GetId()) {
75                     curBB->PushBackSuccs(*brToBB);
76                     brToBB->PushBackPreds(*curBB);
77                 }
78                 break;
79             }
80             case BB::kBBGoto: {
81                 Insn *insn = curBB->GetLastMachineInsn();
82                 if (insn == nullptr) {
83                     curBB->SetKind(BB::kBBFallthru);
84                     continue;
85                 }
86                 CHECK_FATAL(insn != nullptr, "machine insn must be exist in gotoBB");
87                 DEBUG_ASSERT(insn->IsUnCondBranch(), "insn must be a unconditional branch insn");
88                 LabelIdx labelIdx = static_cast<LabelOperand &>(insn->GetOperand(0)).GetLabelIndex();
89                 BB *gotoBB = cgFunc->GetBBFromLab2BBMap(labelIdx);
90                 CHECK_FATAL(gotoBB != nullptr, "gotoBB is null");
91                 curBB->PushBackSuccs(*gotoBB);
92                 gotoBB->PushBackPreds(*curBB);
93                 break;
94             }
95             case BB::kBBIgoto: {
96                 CHECK_NULL_FATAL(CG::GetCurCGFunc()->GetMirModule().CurFunction());
97                 for (auto lidx :
98                      CG::GetCurCGFunc()->GetMirModule().CurFunction()->GetLabelTab()->GetAddrTakenLabels()) {
99                     BB *igotobb = cgFunc->GetBBFromLab2BBMap(lidx);
100                     CHECK_FATAL(igotobb, "igotobb is null");
101                     curBB->PushBackSuccs(*igotobb);
102                     igotobb->PushBackPreds(*curBB);
103                 }
104                 break;
105             }
106             case BB::kBBRangeGoto: {
107                 std::set<BB *, BBIdCmp> bbs;
108                 for (auto labelIdx : curBB->GetRangeGotoLabelVec()) {
109                     BB *gotoBB = cgFunc->GetBBFromLab2BBMap(labelIdx);
110                     bbs.insert(gotoBB);
111                 }
112                 for (auto gotoBB : bbs) {
113                     curBB->PushBackSuccs(*gotoBB);
114                     gotoBB->PushBackPreds(*curBB);
115                 }
116                 break;
117             }
118             case BB::kBBThrow:
119                 break;
120             case BB::kBBFallthru: {
121                 BB *fallthruBB = curBB->GetNext();
122                 if (fallthruBB != nullptr) {
123                     curBB->PushBackSuccs(*fallthruBB);
124                     fallthruBB->PushBackPreds(*curBB);
125                 }
126                 break;
127             }
128             default:
129                 break;
130         } /* end switch */
131     }
132     FindAndMarkUnreachable(*cgFunc);
133     cgFunc->SetHasBuiltCfg(true);
134 }
135 
CheckCFG()136 void CGCFG::CheckCFG()
137 {
138     FOR_ALL_BB(bb, cgFunc)
139     {
140         for (BB *sucBB : bb->GetSuccs()) {
141             bool found = false;
142             for (BB *sucPred : sucBB->GetPreds()) {
143                 if (sucPred == bb) {
144                     if (!found) {
145                         found = true;
146                     } else {
147                         LogInfo::MapleLogger()
148                             << "dup pred " << sucPred->GetId() << " for sucBB " << sucBB->GetId() << "\n";
149                         CHECK_FATAL_FALSE("CG_CFG check failed !");
150                     }
151                 }
152             }
153             if (!found) {
154                 LogInfo::MapleLogger() << "non pred for sucBB " << sucBB->GetId() << " for BB " << bb->GetId() << "\n";
155                 CHECK_FATAL_FALSE("CG_CFG check failed !");
156             }
157         }
158     }
159     FOR_ALL_BB(bb, cgFunc)
160     {
161         for (BB *predBB : bb->GetPreds()) {
162             bool found = false;
163             for (BB *predSucc : predBB->GetSuccs()) {
164                 if (predSucc == bb) {
165                     if (!found) {
166                         found = true;
167                     } else {
168                         LogInfo::MapleLogger()
169                             << "dup succ " << predSucc->GetId() << " for predBB " << predBB->GetId() << "\n";
170                         CHECK_FATAL_FALSE("CG_CFG check failed !");
171                     }
172                 }
173             }
174             if (!found) {
175                 LogInfo::MapleLogger() << "non succ for predBB " << predBB->GetId() << " for BB " << bb->GetId()
176                                        << "\n";
177                 CHECK_FATAL_FALSE("CG_CFG check failed !");
178             }
179         }
180     }
181 }
182 
CheckCFGFreq()183 void CGCFG::CheckCFGFreq()
184 {
185     auto verifyBBFreq = [this](const BB *bb, uint32 succFreq) {
186         uint32 res = bb->GetFrequency();
187         if ((res != 0 && abs(static_cast<int>(res - succFreq)) / res > 1.0) || (res == 0 && res != succFreq)) {
188             // Not included
189             if (bb->GetSuccs().size() > 1 && bb->GetPreds().size() > 1) {
190                 return;
191             }
192             LogInfo::MapleLogger() << cgFunc->GetName() << " curBB: " << bb->GetId() << " freq: " << bb->GetFrequency()
193                                    << std::endl;
194             CHECK_FATAL(false, "Verifyfreq failure BB frequency!");
195         }
196     };
197     FOR_ALL_BB(bb, cgFunc)
198     {
199         if (bb->IsUnreachable() || bb->IsCleanup()) {
200             continue;
201         }
202         uint32 res = 0;
203         if (bb->GetSuccs().size() > 1) {
204             for (auto *succBB : bb->GetSuccs()) {
205                 res += succBB->GetFrequency();
206                 if (succBB->GetPreds().size() > 1) {
207                     LogInfo::MapleLogger()
208                         << cgFunc->GetName() << " critical edges: curBB: " << bb->GetId() << std::endl;
209                     CHECK_FATAL(false, "The CFG has critical edges!");
210                 }
211             }
212             verifyBBFreq(bb, res);
213         } else if (bb->GetSuccs().size() == 1) {
214             auto *succBB = bb->GetSuccs().front();
215             if (succBB->GetPreds().size() == 1) {
216                 verifyBBFreq(bb, succBB->GetFrequency());
217             } else if (succBB->GetPreds().size() > 1) {
218                 for (auto *pred : succBB->GetPreds()) {
219                     res += pred->GetFrequency();
220                 }
221                 verifyBBFreq(succBB, res);
222             }
223         }
224     }
225     LogInfo::MapleLogger() << "Check Frequency for " << cgFunc->GetName() << " success!\n";
226 }
227 
228 InsnVisitor *CGCFG::insnVisitor;
229 
InitInsnVisitor(CGFunc & func) const230 void CGCFG::InitInsnVisitor(CGFunc &func) const
231 {
232     insnVisitor = func.NewInsnModifier();
233 }
234 
235 // Do custom deep copy
CloneInsn(Insn & originalInsn) const236 Insn *CGCFG::CloneInsn(Insn &originalInsn) const
237 {
238     cgFunc->IncTotalNumberOfInstructions();
239     return insnVisitor->CloneInsn(originalInsn);
240 }
241 
CreateVregFromReg(const RegOperand & pReg) const242 RegOperand *CGCFG::CreateVregFromReg(const RegOperand &pReg) const
243 {
244     return insnVisitor->CreateVregFromReg(pReg);
245 }
246 
247 /*
248  * return true if:
249  * mergee has only one predecessor which is merger,
250  * or mergee has other comments only predecessors & merger is soloGoto
251  * mergee can't have cfi instruction when postcfgo.
252  */
BBJudge(const BB & first,const BB & second) const253 bool CGCFG::BBJudge(const BB &first, const BB &second) const
254 {
255     if (first.GetKind() == BB::kBBReturn || second.GetKind() == BB::kBBReturn) {
256         return false;
257     }
258     // If the address of firstBB or secondBB is referenced by adrp_label insn,
259     // it can not be merged
260     if (first.IsAdrpLabel() || second.IsAdrpLabel()) {
261         return false;
262     }
263     if (&first == &second) {
264         return false;
265     }
266     if (second.GetPreds().size() == 1 && second.GetPreds().front() == &first) {
267         return true;
268     }
269     for (BB *bb : second.GetPreds()) {
270         if (bb != &first && !AreCommentAllPreds(*bb)) {
271             return false;
272         }
273     }
274     return first.IsSoloGoto();
275 }
276 
277 /*
278  * Check if a given BB mergee can be merged into BB merger.
279  * Returns true if:
280  * 1. mergee has only one predecessor which is merger, or mergee has
281  *   other comments only predecessors.
282  * 2. merge has only one successor which is mergee.
283  * 3. mergee can't have cfi instruction when postcfgo.
284  */
CanMerge(const BB & merger,const BB & mergee) const285 bool CGCFG::CanMerge(const BB &merger, const BB &mergee) const
286 {
287     if (!BBJudge(merger, mergee)) {
288         return false;
289     }
290     if (mergee.GetFirstInsn() != nullptr && mergee.GetFirstInsn()->IsCfiInsn()) {
291         return false;
292     }
293     return (merger.GetSuccs().size() == 1) && (merger.GetSuccs().front() == &mergee);
294 }
295 
296 /* Check if the given BB contains only comments and all its predecessors are comments */
AreCommentAllPreds(const BB & bb)297 bool CGCFG::AreCommentAllPreds(const BB &bb)
298 {
299     if (!bb.IsCommentBB()) {
300         return false;
301     }
302     for (BB *pred : bb.GetPreds()) {
303         if (!AreCommentAllPreds(*pred)) {
304             return false;
305         }
306     }
307     return true;
308 }
309 
310 /* Merge sucBB into curBB. */
MergeBB(BB & merger,BB & mergee,CGFunc & func)311 void CGCFG::MergeBB(BB &merger, BB &mergee, CGFunc &func)
312 {
313     BB *prevLast = mergee.GetPrev();
314     MergeBB(merger, mergee);
315     if (func.GetLastBB()->GetId() == mergee.GetId()) {
316         func.SetLastBB(*prevLast);
317     }
318     if (mergee.GetKind() == BB::kBBReturn) {
319         auto retIt = func.GetExitBBsVec().begin();
320         while (retIt != func.GetExitBBsVec().end()) {
321             if (*retIt == &mergee) {
322                 (void)func.EraseExitBBsVec(retIt);
323                 break;
324             } else {
325                 ++retIt;
326             }
327         }
328         func.PushBackExitBBsVec(merger);
329     }
330     if (mergee.GetKind() == BB::kBBNoReturn) {
331         auto noRetIt = func.GetNoRetCallBBVec().begin();
332         while (noRetIt != func.GetNoRetCallBBVec().end()) {
333             if (*noRetIt == &mergee) {
334                 (void)func.EraseNoReturnCallBB(noRetIt);
335                 break;
336             } else {
337                 ++noRetIt;
338             }
339         }
340         func.PushBackNoReturnCallBBsVec(merger);
341     }
342     if (mergee.GetKind() == BB::kBBRangeGoto) {
343         func.AddEmitSt(merger.GetId(), *func.GetEmitSt(mergee.GetId()));
344         func.DeleteEmitSt(mergee.GetId());
345     }
346 }
347 
MergeBB(BB & merger,BB & mergee)348 void CGCFG::MergeBB(BB &merger, BB &mergee)
349 {
350     if (merger.GetKind() == BB::kBBGoto && merger.GetLastMachineInsn() != nullptr) {
351         if (!merger.GetLastMachineInsn()->IsBranch()) {
352             CHECK_FATAL(false, "unexpected insn kind");
353         }
354         merger.RemoveInsn(*merger.GetLastMachineInsn());
355     }
356     merger.AppendBBInsns(mergee);
357     if (mergee.GetPrev() != nullptr) {
358         mergee.GetPrev()->SetNext(mergee.GetNext());
359     }
360     if (mergee.GetNext() != nullptr) {
361         mergee.GetNext()->SetPrev(mergee.GetPrev());
362     }
363     merger.RemoveSuccs(mergee);
364     for (BB *bb : mergee.GetSuccs()) {
365         bb->RemovePreds(mergee);
366         bb->PushBackPreds(merger);
367         merger.PushBackSuccs(*bb);
368     }
369     merger.SetKind(mergee.GetKind());
370     mergee.SetNext(nullptr);
371     mergee.SetPrev(nullptr);
372     mergee.ClearPreds();
373     mergee.ClearSuccs();
374     mergee.SetFirstInsn(nullptr);
375     mergee.SetLastInsn(nullptr);
376 }
377 
378 /*
379  * Find all reachable BBs by dfs in cgfunc and mark their field<unreachable> false, then all other bbs should be
380  * unreachable.
381  */
FindAndMarkUnreachable(CGFunc & func)382 void CGCFG::FindAndMarkUnreachable(CGFunc &func)
383 {
384     BB *firstBB = func.GetFirstBB();
385     std::stack<BB *> toBeAnalyzedBBs;
386     toBeAnalyzedBBs.push(firstBB);
387     std::unordered_set<uint32> instackBBs;
388 
389     BB *bb = firstBB;
390     /* set all bb's unreacable to true */
391     while (bb != nullptr) {
392         /* Check if bb is the first or the last BB of the function */
393         if (bb->IsCleanup() || InSwitchTable(bb->GetLabIdx(), func) || bb == func.GetFirstBB() ||
394             bb == func.GetLastBB()) {
395             toBeAnalyzedBBs.push(bb);
396         } else if (bb->IsLabelTaken() == false) {
397             bb->SetUnreachable(true);
398         }
399         bb = bb->GetNext();
400     }
401 
402     /* do a dfs to see which bbs are reachable */
403     while (!toBeAnalyzedBBs.empty()) {
404         bb = toBeAnalyzedBBs.top();
405         toBeAnalyzedBBs.pop();
406         (void)instackBBs.insert(bb->GetId());
407 
408         bb->SetUnreachable(false);
409 
410         for (BB *succBB : bb->GetSuccs()) {
411             if (instackBBs.count(succBB->GetId()) == 0) {
412                 toBeAnalyzedBBs.push(succBB);
413                 (void)instackBBs.insert(succBB->GetId());
414             }
415         }
416     }
417     FOR_ALL_BB(tmpBB, &func)
418     {
419         for (MapleList<BB *>::iterator predIt = tmpBB->GetPredsBegin(); predIt != tmpBB->GetPredsEnd(); ++predIt) {
420             if ((*predIt)->IsUnreachable()) {
421                 tmpBB->ErasePreds(predIt);
422             }
423         }
424     }
425 }
426 
427 /*
428  * Theoretically, every time you remove from a bb's preds, you should consider invoking this method.
429  *
430  * @param bb
431  * @param func
432  */
FlushUnReachableStatusAndRemoveRelations(BB & bb,const CGFunc & func) const433 void CGCFG::FlushUnReachableStatusAndRemoveRelations(BB &bb, const CGFunc &func) const
434 {
435     /* Check if bb is the first or the last BB of the function */
436     bool isFirstBBInfunc = (&bb == func.GetFirstBB());
437     bool isLastBBInfunc = (&bb == func.GetLastBB());
438     if (bb.IsCleanup() || InSwitchTable(bb.GetLabIdx(), func) || isFirstBBInfunc || isLastBBInfunc) {
439         return;
440     }
441     std::stack<BB *> toBeAnalyzedBBs;
442     toBeAnalyzedBBs.push(&bb);
443     std::set<uint32> instackBBs;
444     BB *it = nullptr;
445     while (!toBeAnalyzedBBs.empty()) {
446         it = toBeAnalyzedBBs.top();
447         (void)instackBBs.insert(it->GetId());
448         toBeAnalyzedBBs.pop();
449         /* Check if bb is the first or the last BB of the function */
450         isFirstBBInfunc = (it == func.GetFirstBB());
451         isLastBBInfunc = (it == func.GetLastBB());
452         bool needFlush = !isFirstBBInfunc && !isLastBBInfunc && !it->IsCleanup() && it->GetPreds().empty() &&
453                          !InSwitchTable(it->GetLabIdx(), *cgFunc) && !cgFunc->IsExitBB(*it) &&
454                          (it->IsLabelTaken() == false);
455         if (!needFlush) {
456             continue;
457         }
458         it->SetUnreachable(true);
459         it->SetFirstInsn(nullptr);
460         it->SetLastInsn(nullptr);
461         for (BB *succ : it->GetSuccs()) {
462             if (instackBBs.count(succ->GetId()) == 0) {
463                 toBeAnalyzedBBs.push(succ);
464                 (void)instackBBs.insert(succ->GetId());
465             }
466             succ->RemovePreds(*it);
467         }
468         it->ClearSuccs();
469     }
470 }
471 
RemoveBB(BB & curBB,bool isGotoIf) const472 void CGCFG::RemoveBB(BB &curBB, bool isGotoIf) const
473 {
474     if (!curBB.IsUnreachable()) {
475         BB *sucBB = CGCFG::GetTargetSuc(curBB, false, isGotoIf);
476         if (sucBB != nullptr) {
477             sucBB->RemovePreds(curBB);
478         }
479         BB *fallthruSuc = nullptr;
480         if (isGotoIf) {
481             for (BB *succ : curBB.GetSuccs()) {
482                 if (succ == sucBB) {
483                     continue;
484                 }
485                 fallthruSuc = succ;
486                 break;
487             }
488             DEBUG_ASSERT(fallthruSuc == curBB.GetNext(), "fallthru succ should be its next bb.");
489             if (fallthruSuc != nullptr) {
490                 fallthruSuc->RemovePreds(curBB);
491             }
492         }
493 
494         for (BB *preBB : curBB.GetPreds()) {
495             if (preBB->GetKind() == BB::kBBIgoto) {
496                 if (sucBB != nullptr) {
497                     sucBB->PushBackPreds(curBB);
498                 }
499                 return;
500             }
501             /*
502              * If curBB is the target of its predecessor, change
503              * the jump target.
504              */
505             if (&curBB == GetTargetSuc(*preBB, true, isGotoIf)) {
506                 LabelIdx targetLabel;
507                 if (curBB.GetNext()->GetLabIdx() == 0) {
508                     targetLabel = insnVisitor->GetCGFunc()->CreateLabel();
509                     curBB.GetNext()->SetLabIdx(targetLabel);
510                     cgFunc->SetLab2BBMap(targetLabel, *curBB.GetNext());
511                 } else {
512                     targetLabel = curBB.GetNext()->GetLabIdx();
513                 }
514                 insnVisitor->ModifyJumpTarget(targetLabel, *preBB);
515             }
516             if (fallthruSuc != nullptr && !fallthruSuc->IsPredecessor(*preBB)) {
517                 preBB->PushBackSuccs(*fallthruSuc);
518                 fallthruSuc->PushBackPreds(*preBB);
519             }
520             if (sucBB != nullptr && !sucBB->IsPredecessor(*preBB)) {
521                 preBB->PushBackSuccs(*sucBB);
522                 sucBB->PushBackPreds(*preBB);
523             }
524             preBB->RemoveSuccs(curBB);
525         }
526     }
527 
528     if (curBB.GetNext() != nullptr) {
529         cgFunc->GetCommonExitBB()->RemovePreds(curBB);
530         curBB.GetNext()->RemovePreds(curBB);
531         curBB.GetNext()->SetPrev(curBB.GetPrev());
532     } else {
533         cgFunc->SetLastBB(*curBB.GetPrev());
534     }
535     if (curBB.GetPrev() != nullptr) {
536         curBB.GetPrev()->SetNext(curBB.GetNext());
537     } else {
538         cgFunc->SetFirstBB(*curBB.GetNext());
539     }
540     cgFunc->ClearBBInVec(curBB.GetId());
541     /* remove callsite */
542     EHFunc *ehFunc = cgFunc->GetEHFunc();
543     if (ehFunc != nullptr && ehFunc->GetLSDACallSiteTable() != nullptr) {
544         ehFunc->GetLSDACallSiteTable()->RemoveCallSite(curBB);
545     }
546 }
547 
UpdateCommonExitBBInfo()548 void CGCFG::UpdateCommonExitBBInfo()
549 {
550     BB *commonExitBB = cgFunc->GetCommonExitBB();
551     ASSERT_NOT_NULL(commonExitBB);
552     commonExitBB->ClearPreds();
553     for (BB *exitBB : cgFunc->GetExitBBsVec()) {
554         if (!exitBB->IsUnreachable()) {
555             commonExitBB->PushBackPreds(*exitBB);
556         }
557     }
558     for (BB *noRetBB : cgFunc->GetNoRetCallBBVec()) {
559         if (!noRetBB->IsUnreachable()) {
560             commonExitBB->PushBackPreds(*noRetBB);
561         }
562     }
563     WontExitAnalysis();
564 }
565 
RetargetJump(BB & srcBB,BB & targetBB) const566 void CGCFG::RetargetJump(BB &srcBB, BB &targetBB) const
567 {
568     insnVisitor->ModifyJumpTarget(srcBB, targetBB);
569 }
570 
GetTargetSuc(BB & curBB,bool branchOnly,bool isGotoIf)571 BB *CGCFG::GetTargetSuc(BB &curBB, bool branchOnly, bool isGotoIf)
572 {
573     switch (curBB.GetKind()) {
574         case BB::kBBGoto:
575         case BB::kBBIntrinsic:
576         case BB::kBBIf: {
577             const Insn *origLastInsn = curBB.GetLastMachineInsn();
578             ASSERT_NOT_NULL(origLastInsn);
579             if (isGotoIf && (curBB.GetPrev() != nullptr) &&
580                 (curBB.GetKind() == BB::kBBGoto || curBB.GetKind() == BB::kBBIf) &&
581                 (curBB.GetPrev()->GetKind() == BB::kBBGoto || curBB.GetPrev()->GetKind() == BB::kBBIf)) {
582                 origLastInsn = curBB.GetPrev()->GetLastMachineInsn();
583             }
584             ASSERT_NOT_NULL(origLastInsn);
585             LabelIdx label = insnVisitor->GetJumpLabel(*origLastInsn);
586             for (BB *bb : curBB.GetSuccs()) {
587                 if (bb->GetLabIdx() == label) {
588                     return bb;
589                 }
590             }
591             break;
592         }
593         case BB::kBBIgoto: {
594             for (Insn *insn = curBB.GetLastInsn(); insn != nullptr; insn = insn->GetPrev()) {
595 #if TARGAARCH64
596                 if (Triple::GetTriple().IsAarch64BeOrLe() &&
597                     insn->GetMachineOpcode() == MOP_adrp_label) {
598                     int64 label = static_cast<ImmOperand&>(insn->GetOperand(1)).GetValue();
599                     for (BB *bb : curBB.GetSuccs()) {
600                         if (bb->GetLabIdx() == static_cast<LabelIdx>(label)) {
601                             return bb;
602                         }
603                     }
604                 }
605 #endif
606             }
607             /* can also be a MOP_xbr. */
608             return nullptr;
609         }
610         case BB::kBBFallthru: {
611             return (branchOnly ? nullptr : curBB.GetNext());
612         }
613         case BB::kBBThrow:
614             return nullptr;
615         default:
616             return nullptr;
617     }
618     return nullptr;
619 }
620 
InLSDA(LabelIdx label,const EHFunc * ehFunc)621 bool CGCFG::InLSDA(LabelIdx label [[maybe_unused]], const EHFunc *ehFunc [[maybe_unused]])
622 {
623     /* the function have no exception handle module */
624     if (ehFunc == nullptr) {
625         return false;
626     }
627 
628     if ((label == 0) || ehFunc->GetLSDACallSiteTable() == nullptr) {
629         return false;
630     }
631     if (label == ehFunc->GetLSDACallSiteTable()->GetCSTable().GetEndOffset()->GetLabelIdx() ||
632         label == ehFunc->GetLSDACallSiteTable()->GetCSTable().GetStartOffset()->GetLabelIdx()) {
633         return true;
634     }
635     return ehFunc->GetLSDACallSiteTable()->InCallSiteTable(label);
636 }
637 
InSwitchTable(LabelIdx label,const CGFunc & func)638 bool CGCFG::InSwitchTable(LabelIdx label, const CGFunc &func)
639 {
640     if (label == 0) {
641         return false;
642     }
643     return func.InSwitchTable(label);
644 }
645 
IsCompareAndBranchInsn(const Insn & insn) const646 bool CGCFG::IsCompareAndBranchInsn(const Insn &insn) const
647 {
648     return insnVisitor->IsCompareAndBranchInsn(insn);
649 }
650 
IsTestAndBranchInsn(const Insn & insn) const651 bool CGCFG::IsTestAndBranchInsn(const Insn &insn) const
652 {
653     return insnVisitor->IsTestAndBranchInsn(insn);
654 }
655 
IsAddOrSubInsn(const Insn & insn) const656 bool CGCFG::IsAddOrSubInsn(const Insn &insn) const
657 {
658     return insnVisitor->IsAddOrSubInsn(insn);
659 }
660 
FindLastCondBrInsn(BB & bb) const661 Insn *CGCFG::FindLastCondBrInsn(BB &bb) const
662 {
663     if (bb.GetKind() != BB::kBBIf) {
664         return nullptr;
665     }
666     FOR_BB_INSNS_REV(insn, (&bb))
667     {
668         if (insn->IsBranch()) {
669             return insn;
670         }
671     }
672     return nullptr;
673 }
674 
MarkLabelTakenBB() const675 void CGCFG::MarkLabelTakenBB() const
676 {
677     if (cgFunc->GetMirModule().GetSrcLang() != kSrcLangC) {
678         return;
679     }
680     for (BB *bb = cgFunc->GetFirstBB(); bb != nullptr; bb = bb->GetNext()) {
681         if (cgFunc->GetFunction().GetLabelTab()->GetAddrTakenLabels().find(bb->GetLabIdx()) !=
682             cgFunc->GetFunction().GetLabelTab()->GetAddrTakenLabels().end()) {
683             cgFunc->SetHasTakenLabel();
684             bb->SetLabelTaken();
685         }
686     }
687 }
688 
689 /*
690  * analyse the CFG to find the BBs that are not reachable from function entries
691  * and delete them
692  */
UnreachCodeAnalysis() const693 void CGCFG::UnreachCodeAnalysis() const
694 {
695     if (cgFunc->GetMirModule().GetSrcLang() == kSrcLangC &&
696         (cgFunc->HasTakenLabel() || (cgFunc->GetEHFunc() && cgFunc->GetEHFunc()->GetLSDAHeader()))) {
697         return;
698     }
699     /*
700      * Find all reachable BBs by dfs in cgfunc and mark their field<unreachable> false,
701      * then all other bbs should be unreachable.
702      */
703     BB *firstBB = cgFunc->GetFirstBB();
704     std::forward_list<BB *> toBeAnalyzedBBs;
705     toBeAnalyzedBBs.push_front(firstBB);
706     std::set<BB *, BBIdCmp> unreachBBs;
707 
708     BB *bb = firstBB;
709     /* set all bb's unreacable to true */
710     while (bb != nullptr) {
711         /* Check if bb is the firstBB/cleanupBB/returnBB/lastBB of the function */
712         if (bb->IsCleanup() || InSwitchTable(bb->GetLabIdx(), *cgFunc) || bb == cgFunc->GetFirstBB() ||
713             bb == cgFunc->GetLastBB() || bb->GetKind() == BB::kBBReturn) {
714             toBeAnalyzedBBs.push_front(bb);
715         } else {
716             (void)unreachBBs.insert(bb);
717         }
718         if (bb->IsLabelTaken() == false) {
719             bb->SetUnreachable(true);
720         }
721         bb = bb->GetNext();
722     }
723 
724     /* do a dfs to see which bbs are reachable */
725     while (!toBeAnalyzedBBs.empty()) {
726         bb = toBeAnalyzedBBs.front();
727         toBeAnalyzedBBs.pop_front();
728         if (!bb->IsUnreachable()) {
729             continue;
730         }
731         bb->SetUnreachable(false);
732         for (BB *succBB : bb->GetSuccs()) {
733             toBeAnalyzedBBs.push_front(succBB);
734             unreachBBs.erase(succBB);
735         }
736     }
737 
738     /* remove unreachable bb */
739     std::set<BB *, BBIdCmp>::iterator it;
740     for (it = unreachBBs.begin(); it != unreachBBs.end(); it++) {
741         BB *unreachBB = *it;
742         DEBUG_ASSERT(unreachBB != nullptr, "unreachBB must not be nullptr");
743         for (auto exitBB = cgFunc->GetExitBBsVec().begin(); exitBB != cgFunc->GetExitBBsVec().end(); ++exitBB) {
744             if (*exitBB == unreachBB) {
745                 cgFunc->GetExitBBsVec().erase(exitBB);
746                 break;
747             }
748         }
749         EHFunc *ehFunc = cgFunc->GetEHFunc();
750         /* if unreachBB InLSDA ,replace unreachBB's label with nextReachableBB before remove it. */
751         if (ehFunc != nullptr && ehFunc->NeedFullLSDA() && maplebe::CGCFG::InLSDA(unreachBB->GetLabIdx(), ehFunc)) {
752             /* find next reachable BB */
753             BB *nextReachableBB = nullptr;
754             for (BB *curBB = unreachBB; curBB != nullptr; curBB = curBB->GetNext()) {
755                 if (!curBB->IsUnreachable()) {
756                     nextReachableBB = curBB;
757                     break;
758                 }
759             }
760             CHECK_FATAL(nextReachableBB != nullptr, "nextReachableBB not be nullptr");
761             if (nextReachableBB->GetLabIdx() == 0) {
762                 LabelIdx labelIdx = cgFunc->CreateLabel();
763                 nextReachableBB->AddLabel(labelIdx);
764                 cgFunc->SetLab2BBMap(labelIdx, *nextReachableBB);
765             }
766 
767             ehFunc->GetLSDACallSiteTable()->UpdateCallSite(*unreachBB, *nextReachableBB);
768         }
769 
770         unreachBB->GetPrev()->SetNext(unreachBB->GetNext());
771         cgFunc->GetCommonExitBB()->RemovePreds(*unreachBB);
772         if (unreachBB->GetNext()) {
773             unreachBB->GetNext()->SetPrev(unreachBB->GetPrev());
774         }
775 
776         for (BB *sucBB : unreachBB->GetSuccs()) {
777             sucBB->RemovePreds(*unreachBB);
778         }
779 
780         unreachBB->ClearSuccs();
781 
782         cgFunc->ClearBBInVec(unreachBB->GetId());
783 
784         /* Clear insns in GOT Map. */
785         cgFunc->ClearUnreachableGotInfos(*unreachBB);
786         cgFunc->ClearUnreachableConstInfos(*unreachBB);
787     }
788 }
789 
FindWillExitBBs(BB * bb,std::set<BB *,BBIdCmp> * visitedBBs)790 void CGCFG::FindWillExitBBs(BB *bb, std::set<BB *, BBIdCmp> *visitedBBs)
791 {
792     std::queue<BB *> allBBs;
793     allBBs.push(bb);
794     while (!allBBs.empty()) {
795         BB *curBB = allBBs.front();
796         allBBs.pop();
797         if (visitedBBs->count(curBB) != 0) {
798             continue;
799         }
800         visitedBBs->insert(curBB);
801         for (auto *predBB : curBB->GetPreds()) {
802             allBBs.push(predBB);
803         }
804     }
805 }
806 
807 /*
808  * analyse the CFG to find the BBs that will not reach any function exit; these
809  * are BBs inside infinite loops; mark their wontExit flag and create
810  * artificial edges from them to commonExitBB
811  */
WontExitAnalysis()812 void CGCFG::WontExitAnalysis()
813 {
814     std::set<BB *, BBIdCmp> visitedBBs;
815     FindWillExitBBs(cgFunc->GetCommonExitBB(), &visitedBBs);
816     BB *bb = cgFunc->GetFirstBB();
817     while (bb != nullptr) {
818         if (visitedBBs.count(bb) == 0) {
819             bb->SetWontExit(true);
820             if (bb->GetKind() == BB::kBBGoto || bb->GetKind() == BB::kBBThrow) {
821                 // make this bb a predecessor of commonExitBB
822                 cgFunc->GetCommonExitBB()->PushBackPreds(*bb);
823             }
824         }
825         bb = bb->GetNext();
826     }
827 }
828 
FindLastRetBB()829 BB *CGCFG::FindLastRetBB()
830 {
831     FOR_ALL_BB_REV(bb, cgFunc)
832     {
833         if (bb->GetKind() == BB::kBBReturn) {
834             return bb;
835         }
836     }
837     return nullptr;
838 }
839 
UpdatePredsSuccsAfterSplit(BB & pred,BB & succ,BB & newBB) const840 void CGCFG::UpdatePredsSuccsAfterSplit(BB &pred, BB &succ, BB &newBB) const
841 {
842     /* connext newBB -> succ */
843     for (auto it = succ.GetPredsBegin(); it != succ.GetPredsEnd(); ++it) {
844         if (*it == &pred) {
845             auto origIt = it;
846             succ.ErasePreds(it);
847             if (origIt != succ.GetPredsBegin()) {
848                 --origIt;
849                 succ.InsertPred(origIt, newBB);
850             } else {
851                 succ.PushFrontPreds(newBB);
852             }
853             break;
854         }
855     }
856     newBB.PushBackSuccs(succ);
857 
858     /* connext pred -> newBB */
859     for (auto it = pred.GetSuccsBegin(); it != pred.GetSuccsEnd(); ++it) {
860         if (*it == &succ) {
861             auto origIt = it;
862             pred.EraseSuccs(it);
863             if (origIt != succ.GetSuccsBegin()) {
864                 --origIt;
865                 pred.InsertSucc(origIt, newBB);
866             } else {
867                 pred.PushFrontSuccs(newBB);
868             }
869             break;
870         }
871     }
872     newBB.PushBackPreds(pred);
873 
874     /* update phi */
875     for (const auto phiInsnIt : succ.GetPhiInsns()) {
876         auto &phiList = static_cast<PhiOperand &>(phiInsnIt.second->GetOperand(kInsnSecondOpnd));
877         for (const auto phiOpndIt : phiList.GetOperands()) {
878             uint32 fBBId = phiOpndIt.first;
879             DEBUG_ASSERT(fBBId != 0, "GetFromBBID = 0");
880             BB *predBB = cgFunc->GetBBFromID(fBBId);
881             if (predBB == &pred) {
882                 phiList.UpdateOpnd(fBBId, newBB.GetId(), *phiOpndIt.second);
883                 break;
884             }
885         }
886     }
887 }
888 
889 #if TARGAARCH64
BreakCriticalEdge(BB & pred,BB & succ) const890 void CGCFG::BreakCriticalEdge(BB &pred, BB &succ) const
891 {
892     LabelIdx newLblIdx = cgFunc->CreateLabel();
893     BB *newBB = cgFunc->CreateNewBB(newLblIdx, false, BB::kBBGoto, pred.GetFrequency());
894     newBB->SetCritical(true);
895     bool isFallThru = pred.GetNext() == &succ;
896     /* set prev, next */
897     if (isFallThru) {
898         BB *origNext = pred.GetNext();
899         origNext->SetPrev(newBB);
900         newBB->SetNext(origNext);
901         pred.SetNext(newBB);
902         newBB->SetPrev(&pred);
903         newBB->SetKind(BB::kBBFallthru);
904     } else {
905         BB *exitBB = cgFunc->GetExitBBsVec().size() == 0 ? nullptr : cgFunc->GetExitBB(0);
906         if (exitBB == nullptr || exitBB->IsUnreachable()) {
907             if (cgFunc->GetLastBB()->IsUnreachable()) {
908                 // nowhere to connect the newBB, drop it
909                 cgFunc->ClearBBInVec(newBB->GetId());
910                 return;
911             } else {
912                 cgFunc->GetLastBB()->PrependBB(*newBB);
913             }
914         } else {
915             exitBB->AppendBB(*newBB);
916             if (cgFunc->GetLastBB() == exitBB) {
917                 cgFunc->SetLastBB(*newBB);
918             }
919         }
920         newBB->AppendInsn(
921             cgFunc->GetInsnBuilder()->BuildInsn(MOP_xuncond, cgFunc->GetOrCreateLabelOperand(succ.GetLabIdx())));
922     }
923 
924     /* update offset if succ is goto target */
925     if (pred.GetKind() == BB::kBBIf) {
926         Insn *brInsn = FindLastCondBrInsn(pred);
927         DEBUG_ASSERT(brInsn != nullptr, "null ptr check");
928         LabelOperand &brTarget = static_cast<LabelOperand &>(brInsn->GetOperand(AArch64isa::GetJumpTargetIdx(*brInsn)));
929         if (brTarget.GetLabelIndex() == succ.GetLabIdx()) {
930             brInsn->SetOperand(AArch64isa::GetJumpTargetIdx(*brInsn), cgFunc->GetOrCreateLabelOperand(newLblIdx));
931         }
932     } else if (pred.GetKind() == BB::kBBRangeGoto) {
933         const MapleVector<LabelIdx> &labelVec = pred.GetRangeGotoLabelVec();
934         for (size_t i = 0; i < labelVec.size(); ++i) {
935             if (labelVec[i] == succ.GetLabIdx()) {
936                 /* single edge for multi jump target, so have to replace all. */
937                 pred.SetRangeGotoLabel(static_cast<uint32>(i), newLblIdx);
938             }
939         }
940         cgFunc->UpdateEmitSt(pred, succ.GetLabIdx(), newLblIdx);
941     } else {
942         DEBUG_ASSERT(0, "unexpeced bb kind in BreakCriticalEdge");
943     }
944 
945     /* update pred, succ */
946     UpdatePredsSuccsAfterSplit(pred, succ, *newBB);
947 }
948 #endif
949 
GetAnalysisDependence(AnalysisDep & aDep) const950 void CgHandleCFG::GetAnalysisDependence(AnalysisDep &aDep) const
951 {
952     aDep.SetPreservedAll();
953 }
954 
PhaseRun(maplebe::CGFunc & f)955 bool CgHandleCFG::PhaseRun(maplebe::CGFunc &f)
956 {
957     CGCFG *cfg = f.GetMemoryPool()->New<CGCFG>(f);
958     f.SetTheCFG(cfg);
959     cfg->MarkLabelTakenBB();
960     /* build control flow graph */
961     f.GetTheCFG()->BuildCFG();
962     f.HandleFuncCfg(cfg);
963 
964     /* analysis unreachable code */
965     f.GetTheCFG()->UnreachCodeAnalysis();
966     f.EraseUnreachableStackMapInsns();
967     return false;
968 }
969 MAPLE_ANALYSIS_PHASE_REGISTER(CgHandleCFG, handlecfg)
970 
971 } /* namespace maplebe */
972