• 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 "me_cfg.h"
17 #include <iostream>
18 #include <algorithm>
19 #include <string>
20 #include "bb.h"
21 #include "ssa_mir_nodes.h"
22 #include "me_irmap.h"
23 #include "mir_builder.h"
24 #include "mir_lower.h"
25 #include "maple_phase_manager.h"
26 
27 namespace {
28 constexpr int kFuncNameLenLimit = 80;
29 }
30 
31 namespace maple {
32 #define MATCH_STMT(stmt, kOpCode)                                        \
33     do {                                                                 \
34         while ((stmt) != nullptr && (stmt)->GetOpCode() == OP_comment) { \
35             (stmt) = (stmt)->GetNext();                                  \
36         }                                                                \
37         if ((stmt) == nullptr || (stmt)->GetOpCode() != (kOpCode)) {     \
38             return false;                                                \
39         }                                                                \
40     } while (0)  // END define
41 
FindExprUse(const BaseNode & expr,StIdx stIdx) const42 bool MeCFG::FindExprUse(const BaseNode &expr, StIdx stIdx) const
43 {
44     if (expr.GetOpCode() == OP_addrof || expr.GetOpCode() == OP_dread) {
45         const auto &addofNode = static_cast<const AddrofNode &>(expr);
46         return addofNode.GetStIdx() == stIdx;
47     } else if (expr.GetOpCode() == OP_iread) {
48         return FindExprUse(*expr.Opnd(0), stIdx);
49     } else {
50         for (size_t i = 0; i < expr.NumOpnds(); ++i) {
51             if (FindExprUse(*expr.Opnd(i), stIdx)) {
52                 return true;
53             }
54         }
55     }
56     return false;
57 }
58 
FindDef(const StmtNode & stmt,StIdx stIdx) const59 bool MeCFG::FindDef(const StmtNode &stmt, StIdx stIdx) const
60 {
61     if (stmt.GetOpCode() != OP_dassign && !kOpcodeInfo.IsCallAssigned(stmt.GetOpCode())) {
62         return false;
63     }
64     if (stmt.GetOpCode() == OP_dassign) {
65         const auto &dassStmt = static_cast<const DassignNode &>(stmt);
66         return dassStmt.GetStIdx() == stIdx;
67     }
68     const auto &cNode = static_cast<const CallNode &>(stmt);
69     const CallReturnVector &nRets = cNode.GetReturnVec();
70     if (!nRets.empty()) {
71         DEBUG_ASSERT(nRets.size() == 1, "Single Ret value for now.");
72         StIdx idx = nRets[0].first;
73         RegFieldPair regFieldPair = nRets[0].second;
74         if (!regFieldPair.IsReg()) {
75             return idx == stIdx;
76         }
77     }
78     return false;
79 }
80 
IsStartTryBB(maple::BB & meBB) const81 bool MeCFG::IsStartTryBB(maple::BB &meBB) const
82 {
83     if (!meBB.GetAttributes(kBBAttrIsTry) || meBB.GetAttributes(kBBAttrIsTryEnd)) {
84         return false;
85     }
86     return (!meBB.GetStmtNodes().empty() && meBB.GetStmtNodes().front().GetOpCode() == OP_try);
87 }
88 
89 // CFG Verify
90 // Check bb-vec and bb-list are strictly consistent.
Verify() const91 void MeCFG::Verify() const
92 {
93     // Check every bb in bb-list.
94     auto eIt = valid_end();
95     for (auto bIt = valid_begin(); bIt != eIt; ++bIt) {
96         if (bIt == common_entry() || bIt == common_exit()) {
97             continue;
98         }
99         auto *bb = *bIt;
100         DEBUG_ASSERT(bb->GetBBId() < bbVec.size(), "CFG Error!");
101         DEBUG_ASSERT(bbVec.at(bb->GetBBId()) == bb, "CFG Error!");
102         if (bb->IsEmpty()) {
103             continue;
104         }
105         DEBUG_ASSERT(bb->GetKind() != kBBUnknown, "runtime check error");
106         // verify succ[1] is goto bb
107         if (bb->GetKind() == kBBCondGoto) {
108             if (!bb->GetAttributes(kBBAttrIsTry) && !bb->GetAttributes(kBBAttrWontExit)) {
109                 DEBUG_ASSERT(bb->GetStmtNodes().rbegin().base().d() != nullptr, "runtime check error");
110                 DEBUG_ASSERT(bb->GetSucc().size() == kBBVectorInitialSize, "runtime check error");
111             }
112             DEBUG_ASSERT(bb->GetSucc(1)->GetBBLabel() ==
113                              static_cast<CondGotoNode &>(bb->GetStmtNodes().back()).GetOffset(),
114                          "runtime check error");
115         } else if (bb->GetKind() == kBBGoto) {
116             if (bb->GetStmtNodes().back().GetOpCode() == OP_throw) {
117                 continue;
118             }
119             if (!bb->GetAttributes(kBBAttrIsTry) && !bb->GetAttributes(kBBAttrWontExit)) {
120                 DEBUG_ASSERT(bb->GetStmtNodes().rbegin().base().d() != nullptr, "runtime check error");
121                 DEBUG_ASSERT(bb->GetSucc().size() == 1, "runtime check error");
122             }
123             DEBUG_ASSERT(bb->GetSucc(0)->GetBBLabel() == static_cast<GotoNode &>(bb->GetStmtNodes().back()).GetOffset(),
124                          "runtime check error");
125         }
126     }
127 }
128 
129 // check that all the target labels in jump statements are defined
VerifyLabels() const130 void MeCFG::VerifyLabels() const
131 {
132     auto eIt = valid_end();
133     for (auto bIt = valid_begin(); bIt != eIt; ++bIt) {
134         BB *mirBB = *bIt;
135         auto &stmtNodes = mirBB->GetStmtNodes();
136         if (stmtNodes.rbegin().base().d() == nullptr) {
137             continue;
138         }
139         if (mirBB->GetKind() == kBBGoto) {
140             if (stmtNodes.back().GetOpCode() == OP_throw) {
141                 continue;
142             }
143             DEBUG_ASSERT(GetLabelBBAt(static_cast<GotoNode &>(stmtNodes.back()).GetOffset())->GetBBLabel() ==
144                              static_cast<GotoNode &>(stmtNodes.back()).GetOffset(),
145                          "undefined label in goto");
146         } else if (mirBB->GetKind() == kBBCondGoto) {
147             DEBUG_ASSERT(GetLabelBBAt(static_cast<CondGotoNode &>(stmtNodes.back()).GetOffset())->GetBBLabel() ==
148                              static_cast<CondGotoNode &>(stmtNodes.back()).GetOffset(),
149                          "undefined label in conditional branch");
150         } else if (mirBB->GetKind() == kBBSwitch) {
151             auto &switchStmt = static_cast<SwitchNode &>(stmtNodes.back());
152             LabelIdx targetLabIdx = switchStmt.GetDefaultLabel();
153             [[maybe_unused]] BB *bb = GetLabelBBAt(targetLabIdx);
154             DEBUG_ASSERT(bb->GetBBLabel() == targetLabIdx, "undefined label in switch");
155             for (size_t j = 0; j < switchStmt.GetSwitchTable().size(); ++j) {
156                 targetLabIdx = switchStmt.GetCasePair(j).second;
157                 bb = GetLabelBBAt(targetLabIdx);
158                 DEBUG_ASSERT(bb->GetBBLabel() == targetLabIdx, "undefined switch target label");
159             }
160         }
161     }
162 }
163 
Dump() const164 void MeCFG::Dump() const
165 {
166     // BSF Dump the cfg
167     LogInfo::MapleLogger() << "####### CFG Dump: ";
168     DEBUG_ASSERT(NumBBs() != 0, "size to be allocated is 0");
169     auto *visitedMap = static_cast<bool *>(calloc(NumBBs(), sizeof(bool)));
170     if (visitedMap != nullptr) {
171         std::queue<BB *> qu;
172         qu.push(GetFirstBB());
173         while (!qu.empty()) {
174             BB *bb = qu.front();
175             qu.pop();
176             if (bb == nullptr) {
177                 continue;
178             }
179             BBId id = bb->GetBBId();
180             if (visitedMap[static_cast<long>(id)]) {
181                 continue;
182             }
183             LogInfo::MapleLogger() << id << " ";
184             visitedMap[static_cast<long>(id)] = true;
185             auto it = bb->GetSucc().begin();
186             while (it != bb->GetSucc().end()) {
187                 BB *kidBB = *it;
188                 if (!visitedMap[static_cast<long>(kidBB->GetBBId())]) {
189                     qu.push(kidBB);
190                 }
191                 ++it;
192             }
193         }
194         LogInfo::MapleLogger() << '\n';
195         free(visitedMap);
196     }
197 }
198 
199 // replace special char in FunctionName for output file
ReplaceFilename(std::string & fileName)200 static void ReplaceFilename(std::string &fileName)
201 {
202     for (char &c : fileName) {
203         if (c == ';' || c == '/' || c == '|') {
204             c = '_';
205         }
206     }
207 }
208 
ConstructFileNameToDump(const std::string & prefix) const209 std::string MeCFG::ConstructFileNameToDump(const std::string &prefix) const
210 {
211     std::string fileName;
212     if (!prefix.empty()) {
213         fileName.append(prefix);
214         fileName.append("-");
215     }
216     // the func name length may exceed OS's file name limit, so truncate after 80 chars
217     if (func.GetName().size() <= kFuncNameLenLimit) {
218         fileName.append(func.GetName());
219     } else {
220         fileName.append(func.GetName().c_str(), kFuncNameLenLimit);
221     }
222     ReplaceFilename(fileName);
223     fileName.append(".dot");
224     return fileName;
225 }
226 
NewBasicBlock()227 BB *MeCFG::NewBasicBlock()
228 {
229     BB *newBB = memPool->New<BB>(&mecfgAlloc, &func.GetVersAlloc(), BBId(nextBBId++));
230     bbVec.push_back(newBB);
231     return newBB;
232 }
233 
234 // new a basic block and insert before position or after position
InsertNewBasicBlock(const BB & position,bool isInsertBefore)235 BB &MeCFG::InsertNewBasicBlock(const BB &position, bool isInsertBefore)
236 {
237     BB *newBB = memPool->New<BB>(&mecfgAlloc, &func.GetVersAlloc(), BBId(nextBBId++));
238 
239     auto bIt = std::find(begin(), end(), &position);
240     auto idx = position.GetBBId();
241     if (!isInsertBefore) {
242         ++bIt;
243         ++idx;
244     }
245     auto newIt = bbVec.insert(bIt, newBB);
246     auto eIt = end();
247     // update bb's idx
248     for (auto it = newIt; it != eIt; ++it) {
249         if ((*it) != nullptr) {
250             (*it)->SetBBId(BBId(idx));
251         }
252         ++idx;
253     }
254     return *newBB;
255 }
256 
DeleteBasicBlock(const BB & bb)257 void MeCFG::DeleteBasicBlock(const BB &bb)
258 {
259     DEBUG_ASSERT(bbVec[bb.GetBBId()] == &bb, "runtime check error");
260     /* update first_bb_ and last_bb if needed */
261     bbVec.at(bb.GetBBId()) = nullptr;
262 }
263 
264 /* get next bb in bbVec */
NextBB(const BB * bb)265 BB *MeCFG::NextBB(const BB *bb)
266 {
267     auto bbIt = std::find(begin(), end(), bb);
268     CHECK_FATAL(bbIt != end(), "bb must be inside bb_vec");
269     for (auto it = ++bbIt; it != end(); ++it) {
270         if (*it != nullptr) {
271             return *it;
272         }
273     }
274     return nullptr;
275 }
276 
277 /* get prev bb in bbVec */
PrevBB(const BB * bb)278 BB *MeCFG::PrevBB(const BB *bb)
279 {
280     auto bbIt = std::find(rbegin(), rend(), bb);
281     CHECK_FATAL(bbIt != rend(), "bb must be inside bb_vec");
282     for (auto it = ++bbIt; it != rend(); ++it) {
283         if (*it != nullptr) {
284             return *it;
285         }
286     }
287     return nullptr;
288 }
289 
SetTryBlockInfo(const StmtNode * nextStmt,StmtNode * tryStmt,BB * lastTryBB,BB * curBB,BB * newBB)290 void MeCFG::SetTryBlockInfo(const StmtNode *nextStmt, StmtNode *tryStmt, BB *lastTryBB, BB *curBB, BB *newBB)
291 {
292     if (nextStmt->GetOpCode() == OP_endtry) {
293         curBB->SetAttributes(kBBAttrIsTryEnd);
294         DEBUG_ASSERT(lastTryBB != nullptr, "null ptr check");
295         endTryBB2TryBB[curBB] = lastTryBB;
296     } else {
297         newBB->SetAttributes(kBBAttrIsTry);
298         bbTryNodeMap[newBB] = tryStmt;
299     }
300 }
301 
BuildSCCDFS(BB & bb,uint32 & visitIndex,std::vector<SCCOfBBs * > & sccNodes,std::vector<uint32> & visitedOrder,std::vector<uint32> & lowestOrder,std::vector<bool> & inStack,std::stack<uint32> & visitStack)302 void MeCFG::BuildSCCDFS(BB &bb, uint32 &visitIndex, std::vector<SCCOfBBs *> &sccNodes,
303                         std::vector<uint32> &visitedOrder, std::vector<uint32> &lowestOrder, std::vector<bool> &inStack,
304                         std::stack<uint32> &visitStack)
305 {
306     uint32 id = bb.UintID();
307     visitedOrder[id] = visitIndex;
308     lowestOrder[id] = visitIndex;
309     ++visitIndex;
310     visitStack.push(id);
311     inStack[id] = true;
312 
313     for (BB *succ : bb.GetSucc()) {
314         if (succ == nullptr) {
315             continue;
316         }
317         uint32 succId = succ->UintID();
318         if (!visitedOrder[succId]) {
319             BuildSCCDFS(*succ, visitIndex, sccNodes, visitedOrder, lowestOrder, inStack, visitStack);
320             if (lowestOrder[succId] < lowestOrder[id]) {
321                 lowestOrder[id] = lowestOrder[succId];
322             }
323         } else if (inStack[succId]) {
324             (void)backEdges.emplace(std::pair<uint32, uint32>(id, succId));
325             if (visitedOrder[succId] < lowestOrder[id]) {
326                 lowestOrder[id] = visitedOrder[succId];
327             }
328         }
329     }
330 
331     if (visitedOrder.at(id) == lowestOrder.at(id)) {
332         auto *sccNode = GetAlloc().GetMemPool()->New<SCCOfBBs>(numOfSCCs++, &bb, &GetAlloc());
333         uint32 stackTopId;
334         do {
335             stackTopId = visitStack.top();
336             visitStack.pop();
337             inStack[stackTopId] = false;
338             auto *topBB = static_cast<BB *>(GetAllBBs()[stackTopId]);
339             sccNode->AddBBNode(topBB);
340             sccOfBB[stackTopId] = sccNode;
341         } while (stackTopId != id);
342 
343         sccNodes.push_back(sccNode);
344     }
345 }
346 
VerifySCC()347 void MeCFG::VerifySCC()
348 {
349     for (BB *bb : GetAllBBs()) {
350         if (bb == nullptr || bb == GetCommonExitBB()) {
351             continue;
352         }
353         SCCOfBBs *scc = sccOfBB.at(bb->UintID());
354         CHECK_FATAL(scc != nullptr, "bb should belong to a scc");
355     }
356 }
357 
SCCTopologicalSort(std::vector<SCCOfBBs * > & sccNodes)358 void MeCFG::SCCTopologicalSort(std::vector<SCCOfBBs *> &sccNodes)
359 {
360     std::set<SCCOfBBs *> inQueue;
361     for (SCCOfBBs *node : sccNodes) {
362         if (!node->HasPred()) {
363             sccTopologicalVec.push_back(node);
364             (void)inQueue.insert(node);
365         }
366     }
367 
368     // Top-down iterates all nodes
369     for (size_t i = 0; i < sccTopologicalVec.size(); ++i) {
370         SCCOfBBs *sccBB = sccTopologicalVec[i];
371         for (SCCOfBBs *succ : sccBB->GetSucc()) {
372             if (inQueue.find(succ) == inQueue.end()) {
373                 // successor has not been visited
374                 bool predAllVisited = true;
375                 // check whether all predecessors of the current successor have been visited
376                 for (SCCOfBBs *pred : succ->GetPred()) {
377                     if (inQueue.find(pred) == inQueue.end()) {
378                         predAllVisited = false;
379                         break;
380                     }
381                 }
382                 if (predAllVisited) {
383                     sccTopologicalVec.push_back(succ);
384                     (void)inQueue.insert(succ);
385                 }
386             }
387         }
388     }
389 }
390 
391 // BBId is index of BB in the bbVec, so we should swap two BB's pos in bbVec, if we want to swap their BBId.
SwapBBId(BB & bb1,BB & bb2)392 void MeCFG::SwapBBId(BB &bb1, BB &bb2)
393 {
394     bbVec[bb1.GetBBId()] = &bb2;
395     bbVec[bb2.GetBBId()] = &bb1;
396     BBId tmp = bb1.GetBBId();
397     bb1.SetBBId(bb2.GetBBId());
398     bb2.SetBBId(tmp);
399 }
400 
401 // set bb succ frequency from bb freq
402 // no critical edge is expected
ConstructEdgeFreqFromBBFreq()403 void MeCFG::ConstructEdgeFreqFromBBFreq()
404 {
405     // set succfreqs
406     auto eIt = valid_end();
407     for (auto bIt = valid_begin(); bIt != eIt; ++bIt) {
408         auto *bb = *bIt;
409         if (!bb)
410             continue;
411         if (bb->GetSucc().size() == 1) {
412             bb->PushBackSuccFreq(bb->GetFrequency());
413         } else if (bb->GetSucc().size() == 2) { // bb has 2 succeed
414             auto *fallthru = bb->GetSucc(0);
415             auto *targetBB = bb->GetSucc(1);
416             if (fallthru->GetPred().size() == 1) {
417                 auto succ0Freq = fallthru->GetFrequency();
418                 bb->PushBackSuccFreq(succ0Freq);
419                 DEBUG_ASSERT(bb->GetFrequency() >= succ0Freq, "sanity check");
420                 bb->PushBackSuccFreq(bb->GetFrequency() - succ0Freq);
421             } else if (targetBB->GetPred().size() == 1) {
422                 auto succ1Freq = targetBB->GetFrequency();
423                 DEBUG_ASSERT(bb->GetFrequency() >= succ1Freq, "sanity check");
424                 bb->PushBackSuccFreq(bb->GetFrequency() - succ1Freq);
425                 bb->PushBackSuccFreq(succ1Freq);
426             } else {
427                 CHECK_FATAL(false, "ConstructEdgeFreqFromBBFreq::NYI critical edge");
428             }
429         } else if (bb->GetSucc().size() > 2) { // bb has 2 succeed
430             // switch case, no critical edge is supposted
431             for (size_t i = 0; i < bb->GetSucc().size(); ++i) {
432                 bb->PushBackSuccFreq(bb->GetSucc(i)->GetFrequency());
433             }
434         }
435     }
436 }
437 
438 // set bb frequency from stmt record
ConstructBBFreqFromStmtFreq()439 void MeCFG::ConstructBBFreqFromStmtFreq()
440 {
441     GcovFuncInfo *funcData = func.GetMirFunc()->GetFuncProfData();
442     if (!funcData)
443         return;
444     if (funcData->stmtFreqs.size() == 0)
445         return;
446     auto eIt = valid_end();
447     for (auto bIt = valid_begin(); bIt != eIt; ++bIt) {
448         if ((*bIt)->IsEmpty())
449             continue;
450         StmtNode &first = (*bIt)->GetFirst();
451         if (funcData->stmtFreqs.count(first.GetStmtID()) > 0) {
452             (*bIt)->SetFrequency(funcData->stmtFreqs[first.GetStmtID()]);
453         } else if (funcData->stmtFreqs.count((*bIt)->GetLast().GetStmtID()) > 0) {
454             (*bIt)->SetFrequency(funcData->stmtFreqs[(*bIt)->GetLast().GetStmtID()]);
455         } else {
456             LogInfo::MapleLogger() << "ERROR::  bb " << (*bIt)->GetBBId() << "frequency is not set"
457                                    << "\n";
458             DEBUG_ASSERT(0, "no freq set");
459         }
460     }
461     // add common entry and common exit
462     auto *bb = *common_entry();
463     uint64_t freq = 0;
464     for (size_t i = 0; i < bb->GetSucc().size(); ++i) {
465         freq += bb->GetSucc(i)->GetFrequency();
466     }
467     bb->SetFrequency(freq);
468     bb = *common_exit();
469     freq = 0;
470     for (size_t i = 0; i < bb->GetPred().size(); ++i) {
471         freq += bb->GetPred(i)->GetFrequency();
472     }
473     bb->SetFrequency(freq);
474     // set succfreqs
475     ConstructEdgeFreqFromBBFreq();
476     // clear stmtFreqs since cfg frequency is create
477     funcData->stmtFreqs.clear();
478 }
479 
ConstructStmtFreq()480 void MeCFG::ConstructStmtFreq()
481 {
482     GcovFuncInfo *funcData = func.GetMirFunc()->GetFuncProfData();
483     if (!funcData)
484         return;
485     auto eIt = valid_end();
486     // clear stmtFreqs
487     funcData->stmtFreqs.clear();
488     for (auto bIt = valid_begin(); bIt != eIt; ++bIt) {
489         auto *bb = *bIt;
490         if (bIt == common_entry()) {
491             funcData->entry_freq = bb->GetFrequency();
492             funcData->real_entryfreq = funcData->entry_freq;
493         }
494         for (auto &stmt : bb->GetStmtNodes()) {
495             Opcode op = stmt.GetOpCode();
496             // record bb start/end stmt
497             if (stmt.GetStmtID() == bb->GetFirst().GetStmtID() || stmt.GetStmtID() == bb->GetLast().GetStmtID() ||
498                 IsCallAssigned(op) || op == OP_call) {
499                 funcData->stmtFreqs[stmt.GetStmtID()] = bb->GetFrequency();
500             }
501         }
502     }
503 }
504 
VerifyBBFreq()505 void MeCFG::VerifyBBFreq()
506 {
507     for (size_t i = 2; i < bbVec.size(); ++i) {  // skip common entry and common exit
508         auto *bb = bbVec[i];
509         if (bb == nullptr || bb->GetAttributes(kBBAttrIsEntry) || bb->GetAttributes(kBBAttrIsExit)) {
510             continue;
511         }
512         // wontexit bb may has wrong succ, skip it
513         if (bb->GetSuccFreq().size() != bb->GetSucc().size() && !bb->GetAttributes(kBBAttrWontExit)) {
514             CHECK_FATAL(false, "VerifyBBFreq: succFreq size != succ size");
515         }
516         // bb freq == sum(out edge freq)
517         uint64 succSumFreq = 0;
518         for (auto succFreq : bb->GetSuccFreq()) {
519             succSumFreq += succFreq;
520         }
521         if (succSumFreq != bb->GetFrequency()) {
522             LogInfo::MapleLogger() << "[VerifyFreq failure] BB" << bb->GetBBId() << " freq: " << bb->GetFrequency()
523                                    << ", all succ edge freq sum: " << succSumFreq << std::endl;
524             LogInfo::MapleLogger() << func.GetName() << std::endl;
525             CHECK_FATAL(false, "VerifyFreq failure: bb freq != succ freq sum");
526         }
527     }
528 }
529 }  // namespace maple
530