/builds/2mk6rsew/0/parcoach/parcoach/src/aSSA/PTACallGraph.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | #include "PTACallGraph.h" |
2 | | #include "parcoach/andersen/Andersen.h" |
3 | | |
4 | | #include "llvm/IR/Instructions.h" |
5 | | #include "llvm/IR/Module.h" |
6 | | |
7 | | #include <memory> |
8 | | #include <queue> |
9 | | |
10 | | using namespace llvm; |
11 | | |
12 | | AnalysisKey PTACallGraphAnalysis::Key; |
13 | | PTACallGraphAnalysis::Result |
14 | 1.76k | PTACallGraphAnalysis::run(Module &M, ModuleAnalysisManager &AM) { |
15 | 1.76k | TimeTraceScope TTS("PTACallGraphAnalysis"); |
16 | 1.76k | Andersen const &AA = AM.getResult<AndersenAA>(M); |
17 | 1.76k | return std::make_unique<PTACallGraph>(M, AA); |
18 | 1.76k | } |
19 | | |
20 | | PTACallGraph::PTACallGraph(llvm::Module const &M, Andersen const &AA) |
21 | | : AA(AA), Root(nullptr), ProgEntry(nullptr), |
22 | | ExternalCallingNode(getOrInsertFunction(nullptr)), |
23 | 1.76k | CallsExternalNode(std::make_unique<PTACallGraphNode>(nullptr)) { |
24 | | |
25 | 1.76k | TimeTraceScope TTS("PTACallGraph"); |
26 | 19.8k | for (Function const &F : M) { |
27 | 19.8k | addToCallGraph(F); |
28 | 19.8k | } |
29 | | |
30 | 1.76k | if (!Root) { |
31 | 5 | Root = ExternalCallingNode; |
32 | 5 | } |
33 | | |
34 | 1.76k | if (!ProgEntry) { |
35 | 5 | errs() << "Warning: no main function in module\n"; |
36 | 1.75k | } else { |
37 | | // Compute reachable functions from main |
38 | 1.75k | std::queue<PTACallGraphNode *> ToVisit; |
39 | 1.75k | std::set<PTACallGraphNode *> Visited; |
40 | | |
41 | 1.75k | ToVisit.push(ProgEntry); |
42 | 1.75k | Visited.insert(ProgEntry); |
43 | | |
44 | 21.4k | while (!ToVisit.empty()) { |
45 | 19.6k | PTACallGraphNode *N = ToVisit.front(); |
46 | 19.6k | ToVisit.pop(); |
47 | | |
48 | 19.6k | Function *F = N->getFunction(); |
49 | 19.6k | if (F) { |
50 | 17.9k | reachableFunctions.insert(F); |
51 | 17.9k | } |
52 | | |
53 | 63.2k | for (auto I = N->begin(), E = N->end(); I != E; ++I) { |
54 | 43.5k | PTACallGraphNode *CalleeNode = I->second; |
55 | 43.5k | assert(CalleeNode); |
56 | 43.5k | if (Visited.find(CalleeNode) == Visited.end()) { |
57 | 17.9k | Visited.insert(CalleeNode); |
58 | 17.9k | ToVisit.push(CalleeNode); |
59 | 17.9k | } |
60 | 43.5k | } |
61 | 19.6k | } |
62 | 1.75k | } |
63 | 1.76k | } |
64 | | |
65 | 1.76k | PTACallGraph::~PTACallGraph() { |
66 | | // TODO |
67 | 1.76k | } |
68 | | |
69 | 19.8k | void PTACallGraph::addToCallGraph(Function const &F) { |
70 | 19.8k | PTACallGraphNode *Node = getOrInsertFunction(&F); |
71 | | |
72 | | // If this function has external linkage, anything could call it. |
73 | 19.8k | if (!F.hasLocalLinkage()) { |
74 | 19.8k | ExternalCallingNode->addCalledFunction(nullptr, Node); |
75 | | |
76 | | // Found the entry point? |
77 | 19.8k | if (F.getName() == "main") { |
78 | 1.75k | assert(!Root && "there should be at most one main"); |
79 | 1.75k | Root = Node; // Found a main, keep track of it! |
80 | | |
81 | 1.75k | ProgEntry = Node; |
82 | 1.75k | } |
83 | 19.8k | } |
84 | | |
85 | | // If this function has its address taken, anything could call it. |
86 | 19.8k | if (F.hasAddressTaken()) { |
87 | 9 | ExternalCallingNode->addCalledFunction(nullptr, Node); |
88 | 9 | } |
89 | | |
90 | | // If this function is not defined in this translation unit, it could call |
91 | | // anything. |
92 | 19.8k | if (F.isDeclaration() && !F.isIntrinsic()) { |
93 | 16.1k | Node->addCalledFunction(nullptr, CallsExternalNode.get()); |
94 | 16.1k | } |
95 | | |
96 | | // Look for calls by this function. |
97 | 19.8k | for (BasicBlock const &BB : F) { |
98 | 189k | for (Instruction const &I : BB) { |
99 | 189k | if (auto const *CI = dyn_cast<CallInst>(&I)) { |
100 | 54.2k | Function const *Callee = CI->getCalledFunction(); |
101 | | |
102 | 54.2k | if (!Callee || !Intrinsic::isLeaf(Callee->getIntrinsicID())) { |
103 | | // Indirect calls of intrinsics are not allowed so no need to check. |
104 | | // We can be more precise here by using TargetArg returned by |
105 | | // Intrinsic::isLeaf. |
106 | 3 | Node->addCalledFunction(CI, CallsExternalNode.get()); |
107 | 54.2k | } else if (!Callee->isIntrinsic()) { |
108 | 27.4k | Node->addCalledFunction(CI, getOrInsertFunction(Callee)); |
109 | 27.4k | } |
110 | | |
111 | | // Indirect calls |
112 | 54.2k | if (!Callee) { |
113 | 3 | Value const *CalledValue = |
114 | 3 | CI->getCalledOperand(); // CI.getCalledValue(); |
115 | 3 | assert(CalledValue); |
116 | | |
117 | 3 | std::vector<Value const *> PtsSet; |
118 | | |
119 | 3 | bool Found = AA.getPointsToSet(CalledValue, PtsSet); |
120 | 3 | assert(Found && "coult not compute points to set for call inst"); |
121 | | |
122 | 3 | Found = false; |
123 | 6 | auto IsCandidateF = [&](Value const *V) { |
124 | 6 | const auto *CandidateF = dyn_cast<Function>(V); |
125 | 6 | if (!CandidateF) { |
126 | 0 | return false; |
127 | 0 | } |
128 | 6 | return (CI->arg_size() == CandidateF->arg_size() || |
129 | 6 | (CandidateF->isVarArg() && |
130 | 2 | CI->arg_size() > CandidateF->arg_size())); |
131 | 6 | }; |
132 | 6 | for (Value const *V : make_filter_range(PtsSet, IsCandidateF)) { |
133 | 6 | auto const *LocalCallee = cast<Function>(V); |
134 | 6 | Found = true; |
135 | | |
136 | 6 | indirectCallMap[CI].insert(LocalCallee); |
137 | | |
138 | 6 | if (Intrinsic::isLeaf(LocalCallee->getIntrinsicID())) { |
139 | 6 | Node->addCalledFunction(CI, getOrInsertFunction(LocalCallee)); |
140 | 6 | } |
141 | 6 | } |
142 | 3 | assert(Found && "could not find called function for call inst"); |
143 | 3 | (void)Found; |
144 | 3 | } |
145 | 54.2k | } |
146 | 189k | } |
147 | 15.2k | } |
148 | 19.8k | } |
149 | | |
150 | 94.0k | bool PTACallGraph::isReachableFromEntry(Function const &F) const { |
151 | 94.0k | if (ProgEntry) { |
152 | 94.0k | return reachableFunctions.find(&F) != reachableFunctions.end(); |
153 | 94.0k | } |
154 | 33 | return true; |
155 | 94.0k | } |
156 | | |
157 | 49.0k | PTACallGraphNode *PTACallGraph::getOrInsertFunction(llvm::Function const *F) { |
158 | 49.0k | auto &CGN = FunctionMap[F]; |
159 | 49.0k | if (CGN) { |
160 | 27.4k | return CGN.get(); |
161 | 27.4k | } |
162 | | |
163 | 21.6k | CGN = std::make_unique<PTACallGraphNode>(const_cast<Function *>(F)); |
164 | | // LLVM10: CGN = std::make_unique<PTACallGraphNode>(const_cast<Function |
165 | | // *>(F)); |
166 | 21.6k | return CGN.get(); |
167 | 49.0k | } |
168 | | |
169 | | void PTACallGraphNode::addCalledFunction(CallBase const *CB, |
170 | 63.4k | PTACallGraphNode *M) { |
171 | 63.4k | CalledFunctions.emplace_back(CB, M); |
172 | 63.4k | } |