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() == ≻
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