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