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