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