• 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 
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