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