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