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