/builds/2mk6rsew/0/parcoach/parcoach/src/aSSA/CollListFunctionAnalysis.cpp
Line | Count | Source |
1 | | #include "parcoach/CollListFunctionAnalysis.h" |
2 | | |
3 | | #include "parcoach/CollectiveList.h" |
4 | | #include "parcoach/DepGraphDCF.h" |
5 | | #include "parcoach/MPICommAnalysis.h" |
6 | | #include "parcoach/Options.h" |
7 | | |
8 | | #include "PTACallGraph.h" |
9 | | #include "Utils.h" |
10 | | |
11 | | #include "llvm/ADT/SCCIterator.h" |
12 | | #include "llvm/IR/InstIterator.h" |
13 | | |
14 | | #define DEBUG_TYPE "coll-list-func" |
15 | | |
16 | | using namespace llvm; |
17 | | |
18 | | namespace parcoach { |
19 | | namespace { |
20 | | |
21 | | struct CollListCFGVisitor : CFGVisitor<CollListCFGVisitor> { |
22 | | using CFGVisitor::CFGVisitor; |
23 | | CollListCFGVisitor(ModuleAnalysisManager &AM, PTACallGraph const &CG, |
24 | | SmallPtrSetImpl<Value *> const &Comms) |
25 | 1.76k | : CFGVisitor(AM), PTACG(CG), Communicators(Comms){}; |
26 | | PTACallGraph const &PTACG; |
27 | | SmallPtrSetImpl<Value *> const &Communicators; |
28 | | CollectiveList::CommToBBToCollListMap CollListsPerComm; |
29 | | |
30 | | template <typename SuccessorsRange> |
31 | | CollectiveList compute(CollectiveList::BBToCollListMap &Lists, |
32 | | SuccessorsRange Successors, BasicBlock *BB, |
33 | 14.6k | bool IsLoopHeader, Value *Comm) { |
34 | 14.6k | bool IsNAVS = CollectiveList::NeighborsAreNAVS( |
35 | 14.6k | Lists, BB, Successors.begin(), Successors.end()); |
36 | 14.6k | LLVM_DEBUG(dbgs() << "NAVS computed from succ: " << IsNAVS << "\n"); |
37 | 14.6k | CollectiveList Current{}; |
38 | | |
39 | 14.6k | if (IsLoopHeader) { |
40 | 459 | if (IsNAVS) { |
41 | 2 | Current.extendWith<NavsElement>(); |
42 | 457 | } else { |
43 | | // Push the original loop coll set |
44 | 457 | Current.extendWith(Lists[BB]); |
45 | 457 | } |
46 | 14.2k | } else { |
47 | 14.2k | Current = CollectiveList::CreateFromBB(Lists, PTACG, IsNAVS, *BB, Comm); |
48 | 14.2k | } |
49 | | |
50 | 14.6k | LLVM_DEBUG(dbgs() << "Current CollectiveList: " << Current.toString() |
51 | 14.6k | << "\n"); |
52 | | |
53 | 14.6k | if (!IsNAVS) { |
54 | | // If we're looking at the exit node it doesn't have any successor. |
55 | 13.9k | if (!empty(Successors)) { |
56 | 11.9k | assert(Lists.count(*Successors.begin()) && |
57 | 11.9k | "Successor should have been computed already."); |
58 | 11.9k | CollectiveList const &SuccSet = Lists[*Successors.begin()]; |
59 | 11.9k | Current.extendWith(SuccSet); |
60 | 11.9k | } |
61 | 13.9k | } |
62 | 14.6k | return Current; |
63 | 14.6k | } CollListFunctionAnalysis.cpp:_ZN8parcoach12_GLOBAL__N_118CollListCFGVisitor7computeIN4llvm14iterator_rangeIPKPNS3_10BasicBlockEEEEENS_14CollectiveListERNS3_8DenseMapIS6_SA_NS3_12DenseMapInfoIS6_vEENS3_6detail12DenseMapPairIS6_SA_EEEET_S6_bPNS3_5ValueE Line | Count | Source | 33 | 459 | bool IsLoopHeader, Value *Comm) { | 34 | 459 | bool IsNAVS = CollectiveList::NeighborsAreNAVS( | 35 | 459 | Lists, BB, Successors.begin(), Successors.end()); | 36 | 459 | LLVM_DEBUG(dbgs() << "NAVS computed from succ: " << IsNAVS << "\n"); | 37 | 459 | CollectiveList Current{}; | 38 | | | 39 | 459 | if (IsLoopHeader) { | 40 | 459 | if (IsNAVS) { | 41 | 2 | Current.extendWith<NavsElement>(); | 42 | 457 | } else { | 43 | | // Push the original loop coll set | 44 | 457 | Current.extendWith(Lists[BB]); | 45 | 457 | } | 46 | 459 | } else { | 47 | 0 | Current = CollectiveList::CreateFromBB(Lists, PTACG, IsNAVS, *BB, Comm); | 48 | 0 | } | 49 | | | 50 | 459 | LLVM_DEBUG(dbgs() << "Current CollectiveList: " << Current.toString() | 51 | 459 | << "\n"); | 52 | | | 53 | 459 | if (!IsNAVS) { | 54 | | // If we're looking at the exit node it doesn't have any successor. | 55 | 457 | if (!empty(Successors)) { | 56 | 457 | assert(Lists.count(*Successors.begin()) && | 57 | 457 | "Successor should have been computed already."); | 58 | 457 | CollectiveList const &SuccSet = Lists[*Successors.begin()]; | 59 | 457 | Current.extendWith(SuccSet); | 60 | 457 | } | 61 | 457 | } | 62 | 459 | return Current; | 63 | 459 | } |
CollListFunctionAnalysis.cpp:_ZN8parcoach12_GLOBAL__N_118CollListCFGVisitor7computeIN4llvm14iterator_rangeINS3_12SuccIteratorINS3_11InstructionENS3_10BasicBlockEEEEEEENS_14CollectiveListERNS3_8DenseMapIPS7_SA_NS3_12DenseMapInfoISC_vEENS3_6detail12DenseMapPairISC_SA_EEEET_SC_bPNS3_5ValueE Line | Count | Source | 33 | 14.2k | bool IsLoopHeader, Value *Comm) { | 34 | 14.2k | bool IsNAVS = CollectiveList::NeighborsAreNAVS( | 35 | 14.2k | Lists, BB, Successors.begin(), Successors.end()); | 36 | 14.2k | LLVM_DEBUG(dbgs() << "NAVS computed from succ: " << IsNAVS << "\n"); | 37 | 14.2k | CollectiveList Current{}; | 38 | | | 39 | 14.2k | if (IsLoopHeader) { | 40 | 0 | if (IsNAVS) { | 41 | 0 | Current.extendWith<NavsElement>(); | 42 | 0 | } else { | 43 | | // Push the original loop coll set | 44 | 0 | Current.extendWith(Lists[BB]); | 45 | 0 | } | 46 | 14.2k | } else { | 47 | 14.2k | Current = CollectiveList::CreateFromBB(Lists, PTACG, IsNAVS, *BB, Comm); | 48 | 14.2k | } | 49 | | | 50 | 14.2k | LLVM_DEBUG(dbgs() << "Current CollectiveList: " << Current.toString() | 51 | 14.2k | << "\n"); | 52 | | | 53 | 14.2k | if (!IsNAVS) { | 54 | | // If we're looking at the exit node it doesn't have any successor. | 55 | 13.4k | if (!empty(Successors)) { | 56 | 11.5k | assert(Lists.count(*Successors.begin()) && | 57 | 11.5k | "Successor should have been computed already."); | 58 | 11.5k | CollectiveList const &SuccSet = Lists[*Successors.begin()]; | 59 | 11.5k | Current.extendWith(SuccSet); | 60 | 11.5k | } | 61 | 13.4k | } | 62 | 14.2k | return Current; | 63 | 14.2k | } |
|
64 | | |
65 | | void visitBB(BasicBlock *BB, |
66 | 14.1k | LoopAggretationInfo const *LoopAnalysisResult = nullptr) { |
67 | 14.1k | LLVM_DEBUG({ |
68 | 14.1k | dbgs() << "CFGVisitor::visitBB::"; |
69 | 14.1k | if (LoopAnalysisResult) { |
70 | 14.1k | dbgs() << "header::"; |
71 | 14.1k | } |
72 | 14.1k | BB->printAsOperand(dbgs()); |
73 | 14.1k | dbgs() << "\n"; |
74 | 14.1k | }); |
75 | 14.6k | for (Value *Comm : Communicators) { |
76 | 14.6k | auto &Lists = CollListsPerComm[Comm]; |
77 | 14.6k | CollectiveList Current; |
78 | 14.6k | if (LoopAnalysisResult) { |
79 | 459 | assert(Lists[BB].getLoopHeader() && |
80 | 459 | "Visiting header which is not a loop?!"); |
81 | 459 | auto const &Successors = |
82 | 459 | LoopAnalysisResult->LoopHeaderToSuccessors.find(BB)->second; |
83 | 459 | Lists[BB] = |
84 | 459 | compute(Lists, make_range(Successors.begin(), Successors.end()), BB, |
85 | 459 | true, Comm); |
86 | 14.2k | } else { |
87 | 14.2k | Lists[BB] = compute(Lists, successors(BB), BB, false, Comm); |
88 | 14.2k | } |
89 | 14.6k | } |
90 | 14.1k | } |
91 | | |
92 | 1.82k | void Visit(Function &F, LoopCFGInfo const &LoopAnalysisResult) { |
93 | 1.82k | for (auto const &[Comm, Lists] : LoopAnalysisResult.CommToBBToCollList) { |
94 | 1.43k | for (auto const &[BB, Colls] : Lists) { |
95 | 1.43k | CollListsPerComm[Comm].insert({BB, Colls}); |
96 | 1.43k | } |
97 | 427 | } |
98 | 1.82k | CFGVisitor::Visit(F, LoopAnalysisResult.LAI); |
99 | 1.82k | LLVM_DEBUG({ |
100 | 1.82k | dbgs() << "CollLists per communicator at end of function:\n"; |
101 | 1.82k | for (auto const &[Comm, Lists] : CollListsPerComm) { |
102 | 1.82k | dbgs() << "comm:"; |
103 | 1.82k | Comm->print(dbgs()); |
104 | 1.82k | dbgs() << "\n"; |
105 | 1.82k | for (auto const &[BB, Set] : Lists) { |
106 | 1.82k | BB->printAsOperand(dbgs()); |
107 | 1.82k | dbgs() << ": " << Set.toString() << "\n"; |
108 | 1.82k | } |
109 | 1.82k | dbgs() << "-----\n"; |
110 | 1.82k | } |
111 | 1.82k | }); |
112 | 1.82k | } |
113 | | }; |
114 | | |
115 | | void checkWarnings( |
116 | | Function &F, CollectiveList::CommToBBToCollListMap const &CollListsPerComm, |
117 | | DepGraphDCF const &DG, WarningCollection &Warnings, |
118 | 1.82k | FunctionAnalysisManager &FAM, bool EmitDotDG) { |
119 | 1.82k | llvm::LoopInfo &LI = FAM.getResult<llvm::LoopAnalysis>(F); |
120 | 188k | auto IsaDirectCallToCollective = [](Instruction const &I) { |
121 | 188k | if (CallInst const *CI = dyn_cast<CallInst>(&I)) { |
122 | 53.8k | Function const *F = CI->getCalledFunction(); |
123 | 53.8k | if (F) { |
124 | 53.8k | return Collective::isCollective(*F); |
125 | 53.8k | } |
126 | 53.8k | } |
127 | 134k | return false; |
128 | 188k | }; |
129 | 1.82k | auto Candidates = |
130 | 1.82k | make_filter_range(instructions(F), IsaDirectCallToCollective); |
131 | 6.87k | for (Instruction &I : Candidates) { |
132 | 6.87k | CallInst &CI = cast<CallInst>(I); |
133 | 6.87k | Function &F = *CI.getCalledFunction(); |
134 | 6.87k | Collective const *Coll = Collective::find(F); |
135 | 6.87k | assert(Coll && "Coll expected to be not null because of filter"); |
136 | | // Get conditionals from the callsite |
137 | 6.87k | std::set<BasicBlock const *> CallIpdf; |
138 | 6.87k | DG.getCallInterIPDF(&CI, CallIpdf); |
139 | 6.87k | LLVM_DEBUG(dbgs() << "Call to " << Coll->Name << "\n"); |
140 | 6.87k | LLVM_DEBUG(dbgs() << "callIPDF size: " << CallIpdf.size() << "\n"); |
141 | 6.87k | Value *CommForCollective{}; |
142 | | |
143 | 6.87k | if (auto const *MPIColl = dyn_cast<MPICollective>(Coll)) { |
144 | 6.85k | CommForCollective = MPIColl->getCommunicator(CI); |
145 | 6.85k | } |
146 | | |
147 | 6.87k | Warning::ConditionalsContainerTy Conditionals; |
148 | 6.87k | for (BasicBlock const *BB : CallIpdf) { |
149 | 4.95k | LLVM_DEBUG({ |
150 | 4.95k | BB->printAsOperand(dbgs()); |
151 | 4.95k | dbgs() << " is on path\n"; |
152 | 4.95k | }); |
153 | 4.95k | Loop const *L = LI[BB]; |
154 | | // Is this node detected as potentially dangerous by parcoach? |
155 | 4.95k | bool HasNAVS = false; |
156 | 4.95k | for (auto const &[Comm, Lists] : CollListsPerComm) { |
157 | | // At this point: |
158 | | // - we have a non-null comm, we'll use it for colllists |
159 | | // - we have a null comm: either it's for non-mpi collectives, or |
160 | | // it's a mpi finalize, in both cases we want to check colllists for |
161 | | // all communicators. |
162 | 4.95k | if (!CommForCollective || Comm == CommForCollective) { |
163 | 4.95k | CollectiveList const &CL = |
164 | 4.95k | L ? Lists.find(L->getHeader())->second : Lists.find(BB)->second; |
165 | 4.95k | LLVM_DEBUG(dbgs() << "CL for BB on IPDF: " << CL.toString() << "\n"); |
166 | 4.95k | HasNAVS |= CL.navs(); |
167 | 4.95k | } |
168 | 4.95k | } |
169 | | |
170 | 4.95k | if (!HasNAVS) { |
171 | 2.37k | continue; |
172 | 2.37k | } |
173 | | |
174 | | // Is this condition tainted? |
175 | 2.57k | Value const *Cond = getBasicBlockCond(BB); |
176 | | |
177 | 2.57k | if (!Cond || !DG.isTaintedValue(Cond)) { |
178 | 96 | LLVM_DEBUG(dbgs() << "Not tainted\n"); |
179 | 96 | continue; |
180 | 96 | } |
181 | | |
182 | 2.47k | DebugLoc BDLoc = (BB->getTerminator())->getDebugLoc(); |
183 | 2.47k | Instruction const *Inst = BB->getTerminator(); |
184 | 2.47k | DebugLoc Loc = Inst->getDebugLoc(); |
185 | 2.47k | Conditionals.push_back(Loc); |
186 | | |
187 | 2.47k | if (EmitDotDG) { |
188 | 1 | std::string Dotfilename("taintedpath-"); |
189 | 1 | std::string Filename = Loc->getFilename().str(); |
190 | 1 | size_t LastposSlash = Filename.find_last_of('/'); |
191 | 1 | if (LastposSlash != std::string::npos) { |
192 | 1 | Filename = Filename.substr(LastposSlash + 1, Filename.size()); |
193 | 1 | } |
194 | 1 | Dotfilename.append(Filename).append("-"); |
195 | 1 | Dotfilename.append(std::to_string(Loc.getLine())).append(".dot"); |
196 | 1 | DG.dotTaintPath(Cond, Dotfilename, &CI); |
197 | 1 | } |
198 | 2.47k | } // END FOR |
199 | | |
200 | 6.87k | if (Conditionals.empty()) { |
201 | 4.45k | continue; |
202 | 4.45k | } |
203 | 2.41k | Warnings.insert( |
204 | 2.41k | {&CI, Warning(F, CI.getDebugLoc(), std::move(Conditionals))}); |
205 | 2.41k | } |
206 | 1.82k | } |
207 | | } // namespace |
208 | | |
209 | | llvm::AnalysisKey CollListFunctionAnalysis::Key; |
210 | | llvm::AnalysisKey CollectiveAnalysis::Key; |
211 | | |
212 | | CollectiveAnalysis::Result |
213 | | CollectiveAnalysis::run(llvm::Module &M, |
214 | 1.76k | llvm::ModuleAnalysisManager &AM) const { |
215 | 1.76k | TimeTraceScope TTS("ParcoachCollectiveAnalysis"); |
216 | 1.76k | PTACallGraph const &PTACG = *AM.getResult<PTACallGraphAnalysis>(M); |
217 | 1.76k | auto &DG = AM.getResult<DepGraphDCFAnalysis>(M); |
218 | 1.76k | auto &BBToCollList = AM.getResult<CollListFunctionAnalysis>(M); |
219 | 1.76k | auto &FAM = AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager(); |
220 | 1.76k | WarningCollection Result; |
221 | 1.76k | scc_iterator<PTACallGraph const *> CgSccIter = scc_begin(&PTACG); |
222 | 25.1k | while (!CgSccIter.isAtEnd()) { |
223 | 23.3k | auto const &NodeVec = *CgSccIter; |
224 | 23.3k | for (PTACallGraphNode const *Node : NodeVec) { |
225 | 23.3k | Function *F = Node->getFunction(); |
226 | 23.3k | if (!F || F->isDeclaration() || !PTACG.isReachableFromEntry(*F)) { |
227 | 21.5k | continue; |
228 | 21.5k | } |
229 | 1.82k | checkWarnings(*F, *BBToCollList, *DG, Result, FAM, EmitDotDG_); |
230 | 1.82k | } |
231 | 23.3k | ++CgSccIter; |
232 | 23.3k | } |
233 | 1.76k | return std::make_unique<WarningCollection>(std::move(Result)); |
234 | 1.76k | } |
235 | | |
236 | | CollListFunctionAnalysis::Result |
237 | | CollListFunctionAnalysis::run(llvm::Module &M, |
238 | 1.76k | llvm::ModuleAnalysisManager &AM) { |
239 | 1.76k | TimeTraceScope TTS("CollListFunctionAnalysis"); |
240 | 1.76k | auto const &Res = AM.getResult<PTACallGraphAnalysis>(M); |
241 | 1.76k | PTACallGraph const &PTACG = *Res; |
242 | 1.76k | auto &FAM = AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager(); |
243 | 1.76k | scc_iterator<PTACallGraph const *> CgSccIter = scc_begin(&PTACG); |
244 | 1.76k | auto Comms = AM.getResult<MPICommAnalysis>(M); |
245 | 1.76k | if (Comms.empty()) { |
246 | | // We're likely checking collectives other than MPI, insert a null comm. |
247 | 246 | Comms.insert(nullptr); |
248 | 246 | } |
249 | 1.76k | CollListCFGVisitor Visitor(AM, PTACG, Comms); |
250 | | // This loop "analysis" actually uses the PTACG to build collective list |
251 | | // for indirect calls! |
252 | 1.76k | CollListLoopAnalysis LoopAnalysis(PTACG, Comms); |
253 | 25.1k | while (!CgSccIter.isAtEnd()) { |
254 | 23.3k | auto const &NodeVec = *CgSccIter; |
255 | 23.3k | for (PTACallGraphNode const *Node : NodeVec) { |
256 | 23.3k | Function *F = Node->getFunction(); |
257 | 23.3k | if (!F || F->isDeclaration() || !PTACG.isReachableFromEntry(*F)) { |
258 | 21.5k | continue; |
259 | 21.5k | } |
260 | | // FIXME: we should definitely share the visitor's BBToCollList with the |
261 | | // loop analysis! |
262 | 1.82k | LoopCFGInfo Info = LoopAnalysis.run(*F, FAM); |
263 | 1.82k | LLVM_DEBUG({ |
264 | 1.82k | dbgs() << "LoopCFGInfo for " << F->getName() << ":\n"; |
265 | 1.82k | Info.dump(); |
266 | 1.82k | }); |
267 | 1.82k | Visitor.Visit(*F, Info); |
268 | 1.82k | } |
269 | 23.3k | ++CgSccIter; |
270 | 23.3k | } |
271 | 1.76k | return std::make_unique<CollectiveList::CommToBBToCollListMap>( |
272 | 1.76k | std::move(Visitor.CollListsPerComm)); |
273 | 1.76k | } |
274 | | } // namespace parcoach |