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 "cgbb.h"
17 #include "cgfunc.h"
18
19 namespace maplebe {
20 constexpr uint32 kCondBrNum = 2;
21 constexpr uint32 kSwitchCaseNum = 5;
22
23 const std::string BB::bbNames[BB::kBBLast] = {"BB_ft", "BB_if", "BB_goto", "BB_igoto",
24 "BB_ret", "BB_intrinsic", "BB_rangegoto", "BB_throw"};
25
InsertInsnBefore(Insn & existing,Insn & newInsn)26 Insn *BB::InsertInsnBefore(Insn &existing, Insn &newInsn)
27 {
28 Insn *pre = existing.GetPrev();
29 newInsn.SetPrev(pre);
30 newInsn.SetNext(&existing);
31 existing.SetPrev(&newInsn);
32 if (pre != nullptr) {
33 pre->SetNext(&newInsn);
34 }
35 if (&existing == firstInsn) {
36 firstInsn = &newInsn;
37 }
38 newInsn.SetBB(this);
39 return &newInsn;
40 }
41
InsertInsnAfter(Insn & existing,Insn & newInsn)42 Insn *BB::InsertInsnAfter(Insn &existing, Insn &newInsn)
43 {
44 newInsn.SetPrev(&existing);
45 newInsn.SetNext(existing.GetNext());
46 existing.SetNext(&newInsn);
47 if (&existing == lastInsn) {
48 lastInsn = &newInsn;
49 } else if (newInsn.GetNext()) {
50 newInsn.GetNext()->SetPrev(&newInsn);
51 }
52 newInsn.SetBB(this);
53 internalFlag1++;
54 return &newInsn;
55 }
56
ReplaceInsn(Insn & insn,Insn & newInsn)57 void BB::ReplaceInsn(Insn &insn, Insn &newInsn)
58 {
59 if (insn.IsAccessRefField()) {
60 newInsn.MarkAsAccessRefField(true);
61 }
62 if (insn.GetDoNotRemove()) {
63 newInsn.SetDoNotRemove(true);
64 }
65 newInsn.SetPrev(insn.GetPrev());
66 newInsn.SetNext(insn.GetNext());
67 if (&insn == lastInsn) {
68 lastInsn = &newInsn;
69 } else if (newInsn.GetNext() != nullptr) {
70 newInsn.GetNext()->SetPrev(&newInsn);
71 }
72 if (firstInsn == &insn) {
73 firstInsn = &newInsn;
74 } else if (newInsn.GetPrev() != nullptr) {
75 newInsn.GetPrev()->SetNext(&newInsn);
76 }
77 newInsn.SetComment(insn.GetComment());
78 newInsn.SetBB(this);
79 }
80
RemoveInsn(Insn & insn)81 void BB::RemoveInsn(Insn &insn)
82 {
83 if ((firstInsn == &insn) && (lastInsn == &insn)) {
84 firstInsn = lastInsn = nullptr;
85 } else if (firstInsn == &insn) {
86 firstInsn = insn.GetNext();
87 } else if (lastInsn == &insn) {
88 lastInsn = insn.GetPrev();
89 }
90 /* remove insn from lir list */
91 Insn *prevInsn = insn.GetPrev();
92 Insn *nextInsn = insn.GetNext();
93 if (prevInsn != nullptr) {
94 prevInsn->SetNext(nextInsn);
95 }
96 if (nextInsn != nullptr) {
97 nextInsn->SetPrev(prevInsn);
98 }
99 }
100
RemoveInsnPair(Insn & insn,const Insn & nextInsn)101 void BB::RemoveInsnPair(Insn &insn, const Insn &nextInsn)
102 {
103 DEBUG_ASSERT(insn.GetNext() == &nextInsn, "next_insn is supposed to follow insn");
104 DEBUG_ASSERT(nextInsn.GetPrev() == &insn, "next_insn is supposed to follow insn");
105 if ((firstInsn == &insn) && (lastInsn == &nextInsn)) {
106 firstInsn = lastInsn = nullptr;
107 } else if (firstInsn == &insn) {
108 firstInsn = nextInsn.GetNext();
109 } else if (lastInsn == &nextInsn) {
110 lastInsn = insn.GetPrev();
111 }
112 if (insn.GetPrev() != nullptr) {
113 insn.GetPrev()->SetNext(nextInsn.GetNext());
114 }
115 if (nextInsn.GetNext() != nullptr) {
116 nextInsn.GetNext()->SetPrev(insn.GetPrev());
117 }
118 }
119
120 /* Remove insns in this bb from insn1 to insn2. */
RemoveInsnSequence(Insn & insn,const Insn & nextInsn)121 void BB::RemoveInsnSequence(Insn &insn, const Insn &nextInsn)
122 {
123 DEBUG_ASSERT(insn.GetBB() == this, "remove insn sequence in one bb");
124 DEBUG_ASSERT(nextInsn.GetBB() == this, "remove insn sequence in one bb");
125 if ((firstInsn == &insn) && (lastInsn == &nextInsn)) {
126 firstInsn = lastInsn = nullptr;
127 } else if (firstInsn == &insn) {
128 firstInsn = nextInsn.GetNext();
129 } else if (lastInsn == &nextInsn) {
130 lastInsn = insn.GetPrev();
131 }
132
133 if (insn.GetPrev() != nullptr) {
134 insn.GetPrev()->SetNext(nextInsn.GetNext());
135 }
136 if (nextInsn.GetNext() != nullptr) {
137 nextInsn.GetNext()->SetPrev(insn.GetPrev());
138 }
139 }
140
141 /* append all insns from bb into this bb */
AppendBBInsns(BB & bb)142 void BB::AppendBBInsns(BB &bb)
143 {
144 if (firstInsn == nullptr) {
145 firstInsn = bb.firstInsn;
146 lastInsn = bb.lastInsn;
147 if (firstInsn != nullptr) {
148 FOR_BB_INSNS(i, &bb)
149 {
150 i->SetBB(this);
151 }
152 }
153 return;
154 }
155 if ((bb.firstInsn == nullptr) || (bb.lastInsn == nullptr)) {
156 return;
157 }
158 FOR_BB_INSNS_SAFE(insn, &bb, nextInsn)
159 {
160 AppendInsn(*insn);
161 }
162 }
163
164 /* prepend all insns from bb into this bb */
InsertAtBeginning(BB & bb)165 void BB::InsertAtBeginning(BB &bb)
166 {
167 if (bb.firstInsn == nullptr) { /* nothing to add */
168 return;
169 }
170
171 FOR_BB_INSNS(insn, &bb)
172 {
173 insn->SetBB(this);
174 }
175
176 if (firstInsn == nullptr) {
177 firstInsn = bb.firstInsn;
178 lastInsn = bb.lastInsn;
179 } else {
180 bb.lastInsn->SetNext(firstInsn);
181 firstInsn->SetPrev(bb.lastInsn);
182 firstInsn = bb.firstInsn;
183 }
184 bb.firstInsn = bb.lastInsn = nullptr;
185 }
186
187 /* append all insns from bb into this bb */
InsertAtEnd(BB & bb)188 void BB::InsertAtEnd(BB &bb)
189 {
190 if (bb.firstInsn == nullptr) { /* nothing to add */
191 return;
192 }
193
194 FOR_BB_INSNS(insn, &bb)
195 {
196 insn->SetBB(this);
197 }
198
199 if (firstInsn == nullptr) {
200 firstInsn = bb.firstInsn;
201 lastInsn = bb.lastInsn;
202 } else {
203 bb.firstInsn->SetPrev(lastInsn);
204 lastInsn->SetNext(bb.firstInsn);
205 lastInsn = bb.lastInsn;
206 }
207 bb.firstInsn = bb.lastInsn = nullptr;
208 }
209
210 /* Insert all insns from bb into this bb before the last instr */
InsertAtEndMinus1(BB & bb)211 void BB::InsertAtEndMinus1(BB &bb)
212 {
213 if (bb.firstInsn == nullptr) { /* nothing to add */
214 return;
215 }
216
217 if (NumInsn() == 1) {
218 InsertAtBeginning(bb);
219 return;
220 }
221
222 FOR_BB_INSNS(insn, &bb)
223 {
224 insn->SetBB(this);
225 }
226
227 if (firstInsn == nullptr) {
228 firstInsn = bb.firstInsn;
229 lastInsn = bb.lastInsn;
230 } else {
231 /* Add between prevLast and lastInsn */
232 Insn *prevLast = lastInsn->GetPrev();
233 bb.firstInsn->SetPrev(prevLast);
234 prevLast->SetNext(bb.firstInsn);
235 lastInsn->SetPrev(bb.lastInsn);
236 bb.lastInsn->SetNext(lastInsn);
237 }
238 bb.firstInsn = bb.lastInsn = nullptr;
239 }
240
241 /* Number of instructions excluding DbgInsn and comments */
NumInsn() const242 int32 BB::NumInsn() const
243 {
244 int32 bbSize = 0;
245 FOR_BB_INSNS_CONST(i, this)
246 {
247 if (i->IsImmaterialInsn() || i->IsDbgInsn()) {
248 continue;
249 }
250 ++bbSize;
251 }
252 return bbSize;
253 }
254
IsInPhiList(regno_t regNO)255 bool BB::IsInPhiList(regno_t regNO)
256 {
257 for (auto phiInsnIt : phiInsnList) {
258 Insn *phiInsn = phiInsnIt.second;
259 if (phiInsn == nullptr) {
260 continue;
261 }
262 auto &phiListOpnd = static_cast<PhiOperand &>(phiInsn->GetOperand(kInsnSecondOpnd));
263 for (auto phiListIt : phiListOpnd.GetOperands()) {
264 RegOperand *phiUseOpnd = phiListIt.second;
265 if (phiUseOpnd == nullptr) {
266 continue;
267 }
268 if (phiUseOpnd->GetRegisterNumber() == regNO) {
269 return true;
270 }
271 }
272 }
273 return false;
274 }
275
IsInPhiDef(regno_t regNO)276 bool BB::IsInPhiDef(regno_t regNO)
277 {
278 for (auto phiInsnIt : phiInsnList) {
279 Insn *phiInsn = phiInsnIt.second;
280 if (phiInsn == nullptr) {
281 continue;
282 }
283 auto &phiDefOpnd = static_cast<RegOperand &>(phiInsn->GetOperand(kInsnFirstOpnd));
284 if (phiDefOpnd.GetRegisterNumber() == regNO) {
285 return true;
286 }
287 }
288 return false;
289 }
290
HasCriticalEdge()291 bool BB::HasCriticalEdge()
292 {
293 constexpr int minPredsNum = 2;
294 if (preds.size() < minPredsNum) {
295 return false;
296 }
297 for (BB *pred : preds) {
298 if (pred->GetKind() == BB::kBBGoto || pred->GetKind() == BB::kBBIgoto) {
299 continue;
300 }
301 if (pred->GetSuccs().size() > 1) {
302 return true;
303 }
304 }
305 return false;
306 }
307
Dump() const308 void BB::Dump() const
309 {
310 LogInfo::MapleLogger() << "=== BB " << this << " <" << GetKindName();
311 if (labIdx) {
312 LogInfo::MapleLogger() << "[labeled with " << labIdx << "]";
313 if (labelTaken) {
314 LogInfo::MapleLogger() << " taken";
315 }
316 }
317 LogInfo::MapleLogger() << "> <" << id << "> ";
318 if (isCleanup) {
319 LogInfo::MapleLogger() << "[is_cleanup] ";
320 }
321 if (unreachable) {
322 LogInfo::MapleLogger() << "[unreachable] ";
323 }
324 LogInfo::MapleLogger() << "frequency:" << frequency << "===\n";
325
326 Insn *insn = firstInsn;
327 while (insn != nullptr) {
328 insn->Dump();
329 insn = insn->GetNext();
330 }
331 }
332
IsCommentBB() const333 bool BB::IsCommentBB() const
334 {
335 if (GetKind() != kBBFallthru) {
336 return false;
337 }
338 FOR_BB_INSNS_CONST(insn, this)
339 {
340 if (insn->IsMachineInstruction()) {
341 return false;
342 }
343 }
344 return true;
345 }
346
347 /* return true if bb has no real insns. */
IsEmptyOrCommentOnly() const348 bool BB::IsEmptyOrCommentOnly() const
349 {
350 return (IsEmpty() || IsCommentBB());
351 }
352
IsSoloGoto() const353 bool BB::IsSoloGoto() const
354 {
355 if (GetKind() != kBBGoto) {
356 return false;
357 }
358 if (GetHasCfi()) {
359 return false;
360 }
361 FOR_BB_INSNS_CONST(insn, this)
362 {
363 if (!insn->IsMachineInstruction()) {
364 continue;
365 }
366 return (insn->IsUnCondBranch());
367 }
368 return false;
369 }
370
GetValidPrev()371 BB *BB::GetValidPrev()
372 {
373 BB *pre = GetPrev();
374 while (pre != nullptr && (pre->IsEmptyOrCommentOnly() || pre->IsUnreachable())) {
375 pre = pre->GetPrev();
376 }
377 return pre;
378 }
379
SeekCycles()380 void Bfs::SeekCycles()
381 {
382 MapleVector<bool> visited(cgfunc->NumBBs(), false, alloc.Adapter());
383 MapleVector<bool> onPath(cgfunc->NumBBs(), false, alloc.Adapter());
384 MapleStack<BB*> workStack(alloc.Adapter());
385
386 // searhing workStack BBs cycle
387 auto seekCycles = [this, &visited, &onPath, &workStack]() {
388 while (!workStack.empty()) {
389 auto *bb = workStack.top();
390 if (visited[bb->GetId()]) {
391 onPath[bb->GetId()] = false;
392 workStack.pop();
393 continue;
394 }
395
396 visited[bb->GetId()] = true;
397 onPath[bb->GetId()] = true;
398 for (auto *succBB : bb->GetSuccs()) {
399 if (!visited[succBB->GetId()]) {
400 workStack.push(succBB);
401 } else if (onPath[succBB->GetId()]) {
402 (void)cycleSuccs[bb->GetId()].insert(succBB->GetId());
403 }
404 }
405 }
406 };
407
408 bool changed = false;
409 do {
410 changed = false;
411 FOR_ALL_BB(bb, cgfunc)
412 {
413 if (!visited[bb->GetId()]) {
414 workStack.push(bb);
415 seekCycles();
416 changed = true;
417 }
418 }
419 } while (changed);
420 }
421
AllPredBBVisited(const BB & bb,long & level) const422 bool Bfs::AllPredBBVisited(const BB &bb, long &level) const
423 {
424 // check pred bb is in cycle
425 auto predBBInCycle = [this](const BB &bb, const BB &predBB) {
426 for (auto bbId : cycleSuccs[predBB.GetId()]) {
427 if (bb.GetId() == bbId) {
428 return true;
429 }
430 }
431 return false;
432 };
433
434 bool isAllPredsVisited = true;
435 for (const auto *predBB : bb.GetPreds()) {
436 if (!predBBInCycle(bb, *predBB) && !visitedBBs[predBB->GetId()]) {
437 isAllPredsVisited = false;
438 break;
439 }
440 level = std::max(level, predBB->GetInternalFlag2());
441 }
442 return isAllPredsVisited;
443 }
444
445 /*
446 * During live interval construction, bb has only one predecessor and/or one
447 * successor are stright line bb. It can be considered to be a single large bb
448 * for the purpose of finding live interval. This is to prevent extending live
449 * interval of registers unnecessarily when interleaving bb from other paths.
450 */
MarkStraightLineBBInBFS(BB * bb)451 BB *Bfs::MarkStraightLineBBInBFS(BB *bb)
452 {
453 while (true) {
454 if (bb->GetSuccs().size() != 1) {
455 break;
456 }
457 BB *sbb = bb->GetSuccs().front();
458 if (visitedBBs[sbb->GetId()]) {
459 break;
460 }
461 if (sbb->GetPreds().size() != 1) {
462 break;
463 }
464 sortedBBs.push_back(sbb);
465 visitedBBs[sbb->GetId()] = true;
466 sbb->SetInternalFlag2(bb->GetInternalFlag2() + 1);
467 bb = sbb;
468 }
469 return bb;
470 }
471
SearchForStraightLineBBs(BB & bb)472 BB *Bfs::SearchForStraightLineBBs(BB &bb)
473 {
474 if ((bb.GetSuccs().size() != kCondBrNum)) {
475 return &bb;
476 }
477 BB *sbb1 = bb.GetSuccs().front();
478 BB *sbb2 = bb.GetSuccs().back();
479 size_t predSz1 = sbb1->GetPreds().size();
480 size_t predSz2 = sbb2->GetPreds().size();
481 BB *candidateBB = nullptr;
482 if ((predSz1 == 1) && (predSz2 > kSwitchCaseNum)) {
483 candidateBB = sbb1;
484 } else if ((predSz2 == 1) && (predSz1 > kSwitchCaseNum)) {
485 candidateBB = sbb2;
486 } else {
487 return &bb;
488 }
489 DEBUG_ASSERT(candidateBB->GetId() < visitedBBs.size(), "index out of range in RA::SearchForStraightLineBBs");
490 if (visitedBBs[candidateBB->GetId()]) {
491 return &bb;
492 }
493 if (candidateBB->GetSuccs().size() != 1) {
494 return &bb;
495 }
496
497 sortedBBs.push_back(candidateBB);
498 visitedBBs[candidateBB->GetId()] = true;
499 return MarkStraightLineBBInBFS(candidateBB);
500 }
501
BFS(BB & curBB)502 void Bfs::BFS(BB &curBB)
503 {
504 std::queue<BB *> workList;
505 workList.push(&curBB);
506 DEBUG_ASSERT(curBB.GetId() < cgfunc->NumBBs(), "RA::BFS visitedBBs overflow");
507 DEBUG_ASSERT(curBB.GetId() < visitedBBs.size(), "index out of range in RA::BFS");
508 visitedBBs[curBB.GetId()] = true;
509 do {
510 BB *bb = workList.front();
511 sortedBBs.push_back(bb);
512 DEBUG_ASSERT(bb->GetId() < cgfunc->NumBBs(), "RA::BFS visitedBBs overflow");
513 visitedBBs[bb->GetId()] = true;
514 workList.pop();
515 /* Look for straight line bb */
516 bb = MarkStraightLineBBInBFS(bb);
517 /* Look for an 'if' followed by some straight-line bb */
518 bb = SearchForStraightLineBBs(*bb);
519 for (auto *ibb : bb->GetSuccs()) {
520 /* See if there are unvisited predecessor */
521 if (visitedBBs[ibb->GetId()]) {
522 continue;
523 }
524 long prevLevel = 0;
525 if (AllPredBBVisited(*ibb, prevLevel)) {
526 ibb->SetInternalFlag2(prevLevel + 1);
527 workList.push(ibb);
528 DEBUG_ASSERT(ibb->GetId() < cgfunc->NumBBs(), "GCRA::BFS visitedBBs overflow");
529 visitedBBs[ibb->GetId()] = true;
530 }
531 }
532 } while (!workList.empty());
533 }
534
ComputeBlockOrder()535 void Bfs::ComputeBlockOrder()
536 {
537 cycleSuccs.assign(cgfunc->NumBBs(), MapleSet<BBID>(alloc.Adapter()));
538 SeekCycles();
539
540 sortedBBs.clear();
541 visitedBBs.assign(cgfunc->NumBBs(), false);
542 BB *cleanupBB = nullptr;
543 FOR_ALL_BB(bb, cgfunc)
544 {
545 bb->SetInternalFlag1(0);
546 bb->SetInternalFlag2(1);
547 if (bb->IsCleanup()) {
548 DEBUG_ASSERT(cleanupBB == nullptr, "one cleanupBB in the function only");
549 cleanupBB = bb;
550 }
551 }
552 if (cleanupBB != nullptr) {
553 cleanupBB->SetInternalFlag1(1);
554 }
555
556 bool changed;
557 size_t sortedCnt = 0;
558 bool done = false;
559 do {
560 changed = false;
561 FOR_ALL_BB(bb, cgfunc)
562 {
563 if (bb->GetInternalFlag1() == 1 || bb->IsUnreachable()) {
564 continue;
565 }
566 if (visitedBBs[bb->GetId()]) {
567 continue;
568 }
569 changed = true;
570 long prevLevel = 0;
571 if (AllPredBBVisited(*bb, prevLevel)) {
572 bb->SetInternalFlag2(prevLevel + 1);
573 BFS(*bb);
574 }
575 }
576 /* Make sure there is no infinite loop. */
577 if (sortedCnt == sortedBBs.size()) {
578 if (!done) {
579 done = true;
580 } else {
581 LogInfo::MapleLogger() << "Error: RA BFS loop " << sortedCnt
582 << " in func " << cgfunc->GetName() << "\n";
583 CHECK_FATAL(false, "");
584 }
585 }
586 sortedCnt = sortedBBs.size();
587 } while (changed);
588
589 if (cleanupBB != nullptr) {
590 sortedBBs.push_back(cleanupBB);
591 }
592 }
593
GetAnalysisDependence(AnalysisDep & aDep) const594 void CgBBSort::GetAnalysisDependence(AnalysisDep &aDep) const
595 {
596 #if TARGX86_64
597 if (Triple::GetTriple().GetArch() == Triple::ArchType::x64) {
598 aDep.AddRequired<CgHandleCFG>();
599 }
600 #endif
601 aDep.SetPreservedAll();
602 }
603
PhaseRun(CGFunc & f)604 bool CgBBSort::PhaseRun(CGFunc &f)
605 {
606 MemPool *memPool = GetPhaseMemPool();
607 bfs = memPool->New<Bfs>(f, *memPool);
608 CHECK_FATAL(bfs != nullptr, "NIY, ptr null check.");
609 bfs->ComputeBlockOrder();
610 return false;
611 }
612 MAPLE_ANALYSIS_PHASE_REGISTER(CgBBSort, bbsort)
613 } /* namespace maplebe */
614