• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "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