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 #ifndef MPL2MPL_INCLUDE_CALL_GRAPH_H 17 #define MPL2MPL_INCLUDE_CALL_GRAPH_H 18 #include "class_hierarchy_phase.h" 19 #include "mir_builder.h" 20 #include "mir_nodes.h" 21 #include "scc.h" 22 #include "base_graph_node.h" 23 namespace maple { 24 enum CallType { 25 kCallTypeInvalid, 26 kCallTypeCall, 27 kCallTypeVirtualCall, 28 kCallTypeSuperCall, 29 kCallTypeInterfaceCall, 30 kCallTypeIcall, 31 kCallTypeIntrinsicCall, 32 kCallTypeXinitrinsicCall, 33 kCallTypeIntrinsicCallWithType, 34 kCallTypeCustomCall, 35 kCallTypePolymorphicCall, 36 kCallTypeFakeThreadStartRun 37 }; 38 39 struct NodeComparator { operatorNodeComparator40 bool operator()(const MIRFunction *lhs, const MIRFunction *rhs) const 41 { 42 return lhs->GetPuidx() < rhs->GetPuidx(); 43 } 44 }; 45 46 template <typename T> 47 struct Comparator { operatorComparator48 bool operator()(const T *lhs, const T *rhs) const 49 { 50 return lhs->GetID() < rhs->GetID(); 51 } 52 }; 53 54 // Information description of each callsite 55 class CallInfo { 56 public: 57 CallInfo(CallType type, MIRFunction &call, StmtNode *node, uint32 ld, uint32 stmtId, bool local = false) areAllArgsLocal(local)58 : areAllArgsLocal(local), cType(type), mirFunc(&call), callStmt(node), loopDepth(ld), id(stmtId) 59 { 60 } 61 // For fake callInfo, only id needed CallInfo(uint32 stmtId)62 explicit CallInfo(uint32 stmtId) : id(stmtId) {} 63 ~CallInfo() = default; 64 GetID()65 uint32 GetID() const 66 { 67 return id; 68 } 69 70 const std::string GetCalleeName() const; GetCallType()71 CallType GetCallType() const 72 { 73 return cType; 74 } 75 GetLoopDepth()76 uint32 GetLoopDepth() const 77 { 78 return loopDepth; 79 } 80 81 const std::string GetCallTypeName() const; GetCallStmt()82 const StmtNode *GetCallStmt() const 83 { 84 return callStmt; 85 } GetCallStmt()86 StmtNode *GetCallStmt() 87 { 88 return callStmt; 89 } 90 SetCallStmt(StmtNode * value)91 void SetCallStmt(StmtNode *value) 92 { 93 callStmt = value; 94 } 95 GetFunc()96 MIRFunction *GetFunc() 97 { 98 return mirFunc; 99 } 100 AreAllArgsLocal()101 bool AreAllArgsLocal() const 102 { 103 return areAllArgsLocal; 104 } 105 SetAllArgsLocal()106 void SetAllArgsLocal() 107 { 108 areAllArgsLocal = true; 109 } 110 111 private: 112 bool areAllArgsLocal; 113 CallType cType; // Call type 114 MIRFunction *mirFunc; // Used to get signature 115 StmtNode *callStmt; // Call statement 116 uint32 loopDepth; 117 uint32 id; 118 }; 119 120 // Node in callgraph 121 class CGNode : public BaseGraphNode { 122 public: AddNumRefs()123 void AddNumRefs() 124 { 125 ++numReferences; 126 } 127 DecreaseNumRefs()128 void DecreaseNumRefs() 129 { 130 --numReferences; 131 } 132 NumReferences()133 uint32 NumReferences() const 134 { 135 return numReferences; 136 } 137 CGNode(MIRFunction * func,MapleAllocator & allocater,uint32 index)138 CGNode(MIRFunction *func, MapleAllocator &allocater, uint32 index) 139 : alloc(&allocater), 140 id(index), 141 sccNode(nullptr), 142 mirFunc(func), 143 callees(alloc->Adapter()), 144 vcallCandidates(alloc->Adapter()), 145 isVcallCandidatesValid(false), 146 icallCandidates(alloc->Adapter()), 147 isIcallCandidatesValid(false), 148 numReferences(0), 149 callers(alloc->Adapter()), 150 stmtCount(0), 151 nodeCount(0), 152 mustNotBeInlined(false), 153 vcallCands(alloc->Adapter()) 154 { 155 } 156 157 ~CGNode() = default; 158 159 void Dump(std::ofstream &fout) const; 160 void DumpDetail() const; 161 GetMIRFunction()162 MIRFunction *GetMIRFunction() const 163 { 164 return mirFunc; 165 } 166 167 void AddCallsite(CallInfo &, CGNode *); 168 void AddCallsite(CallInfo *, MapleSet<CGNode *, Comparator<CGNode>> *); 169 void RemoveCallsite(const CallInfo *, CGNode *); 170 GetID()171 uint32 GetID() const override 172 { 173 return id; 174 } 175 GetSCCNode()176 SCCNode<CGNode> *GetSCCNode() 177 { 178 return sccNode; 179 } 180 SetSCCNode(SCCNode<CGNode> * node)181 void SetSCCNode(SCCNode<CGNode> *node) 182 { 183 sccNode = node; 184 } 185 GetPuIdx()186 PUIdx GetPuIdx() const 187 { 188 return (mirFunc != nullptr) ? static_cast<int32>(mirFunc->GetPuidx()) : PUIdx(UINT32_MAX); // invalid idx 189 } 190 GetMIRFuncName()191 const std::string &GetMIRFuncName() const 192 { 193 return (mirFunc != nullptr) ? mirFunc->GetName() : GlobalTables::GetStrTable().GetStringFromStrIdx(GStrIdx(0)); 194 } 195 196 void AddCandsForCallNode(const KlassHierarchy &kh); AddVCallCandidate(MIRFunction * func)197 void AddVCallCandidate(MIRFunction *func) 198 { 199 vcallCands.push_back(func); 200 } 201 HasSetVCallCandidates()202 bool HasSetVCallCandidates() const 203 { 204 return !vcallCands.empty(); 205 } 206 207 MIRFunction *HasOneCandidate() const; GetVCallCandidates()208 const MapleVector<MIRFunction *> &GetVCallCandidates() const 209 { 210 return vcallCands; 211 } 212 213 // add caller to CGNode AddCaller(CGNode * caller,StmtNode * stmt)214 void AddCaller(CGNode *caller, StmtNode *stmt) 215 { 216 if (callers.find(caller) == callers.end()) { 217 auto *callStmts = alloc->New<MapleSet<StmtNode *>>(alloc->Adapter()); 218 callers.emplace(caller, callStmts); 219 } 220 callers[caller]->emplace(stmt); 221 } 222 DelCaller(CGNode * caller)223 void DelCaller(CGNode *caller) 224 { 225 if (callers.find(caller) != callers.end()) { 226 callers.erase(caller); 227 } 228 } 229 DelCallee(CallInfo * callInfo,CGNode * callee)230 void DelCallee(CallInfo *callInfo, CGNode *callee) 231 { 232 (void)callees[callInfo]->erase(callee); 233 } 234 HasCaller()235 bool HasCaller() const 236 { 237 return (!callers.empty()); 238 } 239 NumberOfUses()240 uint32 NumberOfUses() const 241 { 242 return static_cast<uint32>(callers.size()); 243 } 244 245 bool IsCalleeOf(CGNode *func) const; IncrStmtCount()246 void IncrStmtCount() 247 { 248 ++stmtCount; 249 } 250 IncrNodeCountBy(uint32 x)251 void IncrNodeCountBy(uint32 x) 252 { 253 nodeCount += x; 254 } 255 GetStmtCount()256 uint32 GetStmtCount() const 257 { 258 return stmtCount; 259 } 260 GetNodeCount()261 uint32 GetNodeCount() const 262 { 263 return nodeCount; 264 } 265 Reset()266 void Reset() 267 { 268 stmtCount = 0; 269 nodeCount = 0; 270 numReferences = 0; 271 callees.clear(); 272 vcallCands.clear(); 273 } 274 NumberOfCallSites()275 uint32 NumberOfCallSites() const 276 { 277 return static_cast<uint32>(callees.size()); 278 } 279 GetCallee()280 const MapleMap<CallInfo *, MapleSet<CGNode *, Comparator<CGNode>> *, Comparator<CallInfo>> &GetCallee() const 281 { 282 return callees; 283 } 284 GetCallee()285 MapleMap<CallInfo *, MapleSet<CGNode *, Comparator<CGNode>> *, Comparator<CallInfo>> &GetCallee() 286 { 287 return callees; 288 } 289 GetCaller()290 const MapleMap<CGNode *, MapleSet<StmtNode *> *, Comparator<CGNode>> &GetCaller() const 291 { 292 return callers; 293 } 294 GetCaller()295 MapleMap<CGNode *, MapleSet<StmtNode *> *, Comparator<CGNode>> &GetCaller() 296 { 297 return callers; 298 } 299 GetSCCNode()300 const SCCNode<CGNode> *GetSCCNode() const 301 { 302 return sccNode; 303 } 304 IsMustNotBeInlined()305 bool IsMustNotBeInlined() const 306 { 307 return mustNotBeInlined; 308 } 309 SetMustNotBeInlined()310 void SetMustNotBeInlined() 311 { 312 mustNotBeInlined = true; 313 } 314 IsVcallCandidatesValid()315 bool IsVcallCandidatesValid() const 316 { 317 return isVcallCandidatesValid; 318 } 319 SetVcallCandidatesValid()320 void SetVcallCandidatesValid() 321 { 322 isVcallCandidatesValid = true; 323 } 324 AddVcallCandidate(CGNode * item)325 void AddVcallCandidate(CGNode *item) 326 { 327 (void)vcallCandidates.insert(item); 328 } 329 GetVcallCandidates()330 MapleSet<CGNode *, Comparator<CGNode>> &GetVcallCandidates() 331 { 332 return vcallCandidates; 333 } 334 IsIcallCandidatesValid()335 bool IsIcallCandidatesValid() const 336 { 337 return isIcallCandidatesValid; 338 } 339 SetIcallCandidatesValid()340 void SetIcallCandidatesValid() 341 { 342 isIcallCandidatesValid = true; 343 } 344 AddIcallCandidate(CGNode * item)345 void AddIcallCandidate(CGNode *item) 346 { 347 (void)icallCandidates.insert(item); 348 } 349 GetIcallCandidates()350 MapleSet<CGNode *, Comparator<CGNode>> &GetIcallCandidates() 351 { 352 return icallCandidates; 353 } 354 IsAddrTaken()355 bool IsAddrTaken() const 356 { 357 return addrTaken; 358 } 359 SetAddrTaken()360 void SetAddrTaken() 361 { 362 addrTaken = true; 363 } 364 GetOutNodes(std::vector<BaseGraphNode * > & outNodes)365 void GetOutNodes(std::vector<BaseGraphNode *> &outNodes) final 366 { 367 for (auto &callSite : std::as_const(GetCallee())) { 368 for (auto &cgIt : *callSite.second) { 369 CGNode *calleeNode = cgIt; 370 outNodes.emplace_back(calleeNode); 371 } 372 } 373 } 374 GetOutNodes(std::vector<BaseGraphNode * > & outNodes)375 void GetOutNodes(std::vector<BaseGraphNode *> &outNodes) const final 376 { 377 for (auto &callSite : std::as_const(GetCallee())) { 378 for (auto &cgIt : *callSite.second) { 379 CGNode *calleeNode = cgIt; 380 outNodes.emplace_back(calleeNode); 381 } 382 } 383 } 384 GetInNodes(std::vector<BaseGraphNode * > & inNodes)385 void GetInNodes(std::vector<BaseGraphNode *> &inNodes) final 386 { 387 for (auto pair : std::as_const(GetCaller())) { 388 CGNode *callerNode = pair.first; 389 inNodes.emplace_back(callerNode); 390 } 391 } 392 GetInNodes(std::vector<BaseGraphNode * > & inNodes)393 void GetInNodes(std::vector<BaseGraphNode *> &inNodes) const final 394 { 395 for (auto pair : std::as_const(GetCaller())) { 396 CGNode *callerNode = pair.first; 397 inNodes.emplace_back(callerNode); 398 } 399 } 400 GetIdentity()401 const std::string GetIdentity() override 402 { 403 std::string sccIdentity; 404 if (GetMIRFunction() != nullptr) { 405 sccIdentity = 406 "function(" + std::to_string(GetMIRFunction()->GetPuidx()) + "): " + GetMIRFunction()->GetName(); 407 } else { 408 sccIdentity = "function: external"; 409 } 410 return sccIdentity; 411 } 412 // check frequency 413 int64_t GetFuncFrequency() const; 414 int64_t GetCallsiteFrequency(const StmtNode *callstmt) const; 415 416 private: 417 // mirFunc is generated from callStmt's puIdx from mpl instruction 418 // mirFunc will be nullptr if CGNode represents an external/intrinsic call 419 MapleAllocator *alloc; 420 uint32 id; 421 SCCNode<CGNode> *sccNode; // the id of the scc where this cgnode belongs to 422 MIRFunction *mirFunc; 423 // Each callsite corresponds to one element 424 MapleMap<CallInfo *, MapleSet<CGNode *, Comparator<CGNode>> *, Comparator<CallInfo>> callees; 425 MapleSet<CGNode *, Comparator<CGNode>> vcallCandidates; // vcall candidates of mirFunc 426 bool isVcallCandidatesValid; 427 MapleSet<CGNode *, Comparator<CGNode>> icallCandidates; // icall candidates of mirFunc 428 bool isIcallCandidatesValid; 429 uint32 numReferences; // The number of the node in this or other CGNode's callees 430 // function candidate for virtual call 431 // now the candidates would be same function name from base class to subclass 432 // with type inference, the candidates would be reduced 433 MapleMap<CGNode *, MapleSet<StmtNode *> *, Comparator<CGNode>> callers; 434 uint32 stmtCount; // count number of statements in the function, reuse this as callsite id 435 uint32 nodeCount; // count number of MIR nodes in the function/ 436 // this flag is used to mark the function which will read the current method invocation stack or something else, 437 // so it cannot be inlined and all the parent nodes which contain this node should not be inlined, either. 438 bool mustNotBeInlined; 439 MapleVector<MIRFunction *> vcallCands; 440 441 bool addrTaken = false; // whether this function is taken address 442 }; 443 444 using Callsite = std::pair<CallInfo *, MapleSet<CGNode *, Comparator<CGNode>> *>; 445 using CalleeIt = MapleMap<CallInfo *, MapleSet<CGNode *, Comparator<CGNode>> *, Comparator<CallInfo>>::iterator; 446 using Caller2Cands = std::pair<PUIdx, Callsite>; 447 448 class CallGraph : public AnalysisResult { 449 public: 450 CallGraph(MIRModule &m, MemPool &memPool, MemPool &tempPool, KlassHierarchy &kh, const std::string &fn); 451 ~CallGraph() = default; 452 InitCallExternal()453 void InitCallExternal() 454 { 455 callExternal = cgAlloc.GetMemPool()->New<CGNode>(static_cast<MIRFunction *>(nullptr), cgAlloc, numOfNodes++); 456 } 457 CallExternal()458 const CGNode *CallExternal() const 459 { 460 return callExternal; 461 } 462 GetEntryNode()463 const CGNode *GetEntryNode() const 464 { 465 return entryNode; 466 } 467 GetRootNodes()468 const MapleVector<CGNode *> &GetRootNodes() const 469 { 470 return rootNodes; 471 } 472 GetKlassh()473 const KlassHierarchy *GetKlassh() const 474 { 475 return klassh; 476 } 477 GetSCCTopVec()478 const MapleVector<SCCNode<CGNode> *> &GetSCCTopVec() const 479 { 480 return sccTopologicalVec; 481 } 482 GetNodesMap()483 const MapleMap<MIRFunction *, CGNode *, NodeComparator> &GetNodesMap() const 484 { 485 return nodesMap; 486 } 487 488 MIRType *GetFuncTypeFromFuncAddr(const BaseNode *); 489 CallNode *ReplaceIcallToCall(BlockNode &body, IcallNode *icall, PUIdx newPUIdx); 490 void CollectAddroffuncFromExpr(const BaseNode *expr); 491 void CollectAddroffuncFromStmt(const StmtNode *stmt); 492 void CollectAddroffuncFromConst(MIRConst *mirConst); 493 void Dump() const; 494 CGNode *GetCGNode(MIRFunction *func) const; 495 CGNode *GetCGNode(PUIdx puIdx) const; 496 void UpdateCaleeCandidate(PUIdx callerPuIdx, IcallNode *icall, PUIdx calleePuidx, CallNode *call); 497 void UpdateCaleeCandidate(PUIdx callerPuIdx, IcallNode *icall, std::set<PUIdx> &candidate); 498 SCCNode<CGNode> *GetSCCNode(MIRFunction *func) const; 499 bool IsRootNode(MIRFunction *func) const; CurFunction()500 MIRFunction *CurFunction() const 501 { 502 return mirModule->CurFunction(); 503 } 504 IsInIPA()505 bool IsInIPA() const 506 { 507 return mirModule->IsInIPA(); 508 } 509 510 // iterator 511 using iterator = MapleMap<MIRFunction *, CGNode *>::iterator; Begin()512 iterator Begin() 513 { 514 return nodesMap.begin(); 515 } 516 End()517 iterator End() 518 { 519 return nodesMap.end(); 520 } 521 GetMIRFunction(const iterator & it)522 MIRFunction *GetMIRFunction(const iterator &it) const 523 { 524 return (*it).first; 525 } 526 GetCGNode(const iterator & it)527 CGNode *GetCGNode(const iterator &it) const 528 { 529 return (*it).second; 530 } 531 532 void DelNode(CGNode &node); 533 void ClearFunctionList(); 534 SetDebugFlag(bool flag)535 void SetDebugFlag(bool flag) 536 { 537 debugFlag = flag; 538 } 539 GetNodes(std::vector<CGNode * > & nodes)540 void GetNodes(std::vector<CGNode *> &nodes) 541 { 542 for (auto const &it : nodesMap) { 543 CGNode *node = it.second; 544 nodes.emplace_back(node); 545 } 546 } 547 548 private: 549 CallType GetCallType(Opcode op) const; 550 void FindRootNodes(); 551 void RemoveFileStaticRootNodes(); // file static and inline but not extern root nodes can be removed 552 void SetCompilationFunclist() const; 553 GenCallInfo(CallType type,MIRFunction * call,StmtNode * s,uint32 loopDepth,uint32 callsiteID)554 CallInfo *GenCallInfo(CallType type, MIRFunction *call, StmtNode *s, uint32 loopDepth, uint32 callsiteID) 555 { 556 return cgAlloc.GetMemPool()->New<CallInfo>(type, *call, s, loopDepth, callsiteID); 557 } 558 559 bool debugFlag = false; 560 MIRModule *mirModule; 561 MapleAllocator cgAlloc; 562 MapleAllocator tempAlloc; 563 MIRBuilder *mirBuilder; 564 CGNode *entryNode; // For main function, nullptr if there is multiple entries 565 MapleVector<CGNode *> rootNodes; 566 MapleString fileName; // used for output dot file 567 KlassHierarchy *klassh; 568 MapleMap<MIRFunction *, CGNode *, NodeComparator> nodesMap; 569 MapleVector<SCCNode<CGNode> *> sccTopologicalVec; 570 MapleMap<StIdx, BaseNode *> localConstValueMap; // used to record the local constant value 571 MapleMap<TyIdx, MapleSet<Caller2Cands> *> icallToFix; 572 MapleSet<PUIdx> addressTakenPuidxs; 573 CGNode *callExternal = nullptr; // Auxiliary node used in icall/intrinsic call 574 uint32 numOfNodes; 575 std::unordered_set<uint64> callsiteHash; 576 }; 577 578 class IPODevirtulize { 579 public: IPODevirtulize(MIRModule * m,MemPool * memPool,KlassHierarchy * kh)580 IPODevirtulize(MIRModule *m, MemPool *memPool, KlassHierarchy *kh) 581 : cgAlloc(memPool), mirBuilder(cgAlloc.GetMemPool()->New<MIRBuilder>(m)), klassh(kh) 582 { 583 } 584 585 ~IPODevirtulize() = default; GetKlassh()586 const KlassHierarchy *GetKlassh() const 587 { 588 return klassh; 589 } 590 591 private: 592 MapleAllocator cgAlloc; 593 MIRBuilder *mirBuilder; 594 KlassHierarchy *klassh; 595 }; 596 597 } // namespace maple 598 #endif // MPL2MPL_INCLUDE_CALLGRAPH_H 599