/builds/2mk6rsew/0/parcoach/parcoach/src/rma/LocalConcurrencyAnalysis.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | #include "parcoach/RMAPasses.h" |
2 | | |
3 | | #include "llvm/Analysis/AliasAnalysis.h" |
4 | | #include "llvm/IR/Function.h" |
5 | | #include "llvm/IR/InstIterator.h" |
6 | | |
7 | | #include <deque> |
8 | | |
9 | | using namespace llvm; |
10 | | |
11 | | namespace parcoach::rma { |
12 | | namespace { |
13 | | class LCDAnalysis { |
14 | | enum Color { WHITE, GREY, BLACK }; |
15 | | enum ACCESS { READ, WRITE }; |
16 | | static enum ACCESS getInstructionType(Instruction *I); |
17 | | using BBColorMap = DenseMap<BasicBlock const *, Color>; |
18 | | using BBMap = DenseMap<BasicBlock const *, bool>; |
19 | | using BBMemMap = std::map<BasicBlock *, ValueMap<Value *, Instruction *>>; |
20 | | BBColorMap ColorMap; |
21 | | BBMap LheaderMap; |
22 | | BBMap LlatchMap; |
23 | | BBMemMap BBToMemAccess; |
24 | | FunctionAnalysisManager &FAM; |
25 | | LocalConcurrencyVector Results; |
26 | | |
27 | | public: |
28 | 55 | LCDAnalysis(FunctionAnalysisManager &FAM) : FAM(FAM){}; |
29 | 55 | LocalConcurrencyVector takeResults() { |
30 | 55 | LocalConcurrencyVector Ret; |
31 | 55 | std::swap(Results, Ret); |
32 | 55 | return Ret; |
33 | 55 | } |
34 | | void analyze(Function *F); |
35 | | void analyzeBB(BasicBlock *B); |
36 | | void bfsLoop(Loop *L); |
37 | | bool mustWait(BasicBlock *BB); |
38 | | bool mustWaitLoop(llvm::BasicBlock *BB, Loop *L); |
39 | | }; |
40 | | |
41 | | // Get the memory access from the instruction |
42 | | // We consider only local accesses here |
43 | 66 | enum LCDAnalysis::ACCESS LCDAnalysis::getInstructionType(Instruction *I) { |
44 | 66 | if (CallBase *CI = dyn_cast<CallBase>(I)) { |
45 | 52 | if (Function *CalledFunction = CI->getCalledFunction()) { |
46 | 52 | StringRef CalledName = CalledFunction->getName(); |
47 | 52 | if (CalledName == "MPI_Get" || CalledName == "mpi_get_") { |
48 | 17 | return WRITE; |
49 | 17 | } |
50 | 35 | if (CalledName == "MPI_Put" || CalledName == "mpi_put_") { |
51 | 35 | return READ; |
52 | 35 | } |
53 | 35 | } |
54 | 52 | } else if (StoreInst *SI = dyn_cast<StoreInst>(I)) { |
55 | 6 | return WRITE; |
56 | 8 | } else if (LoadInst *LI = dyn_cast<LoadInst>(I)) { |
57 | 8 | return READ; |
58 | 8 | } |
59 | | // Default return |
60 | 0 | return READ; |
61 | 66 | } |
62 | | |
63 | | // Store the memory accesses - we keep the memory which is a value and the last |
64 | | // instruction accessing this memory address |
65 | | // Later: Check interprocedural information |
66 | | // Later: keep the accesses per window |
67 | 488 | void LCDAnalysis::analyzeBB(BasicBlock *BB) { |
68 | 488 | Function *F = BB->getParent(); |
69 | 488 | AAResults &AA = FAM.getResult<AAManager>(*F); |
70 | | |
71 | 4.68k | for (Instruction &Inst : *BB) { |
72 | 4.68k | DebugLoc Dbg = Inst.getDebugLoc(); // get debug infos |
73 | 4.68k | Value *Mem = NULL; |
74 | 4.68k | bool IsLoadOrStore = false; |
75 | | |
76 | | // (1) Get memory access |
77 | 4.68k | if (CallBase *CI = dyn_cast<CallBase>(&Inst)) { |
78 | | // ci->print(errs()); |
79 | | // errs() << "\n"; |
80 | 1.50k | if (Function *CalledFunction = CI->getCalledFunction()) { |
81 | 1.50k | StringRef CalledName = CalledFunction->getName(); |
82 | | // errs() << "Calledfunction = " << calledFunction->getName() << "\n"; |
83 | 1.50k | if ((CalledName == "MPI_Get") || (CalledName == "MPI_Put") || |
84 | 1.50k | (CalledName == "mpi_put_") || (CalledName == "mpi_get_")) { |
85 | 80 | Mem = CI->getArgOperand(0); |
86 | | // errs() << "!!!!!!!! Found a put / get -> store mem \n"; |
87 | 1.42k | } else if ((CalledName == "MPI_Win_flush") || |
88 | 1.42k | (CalledName == "MPI_Win_flush_all") || |
89 | 1.42k | (CalledName == "MPI_Win_fence") || |
90 | 1.42k | (CalledName == "MPI_Win_flush_local") || |
91 | 1.42k | (CalledName == "MPI_Win_unlock_all") || |
92 | 1.42k | (CalledName == "mpi_win_unlock_all_") || |
93 | 1.42k | (CalledName == "mpi_win_flush_") || |
94 | 1.42k | (CalledName == "mpi_win_flush_all_") || |
95 | 1.42k | (CalledName == "mpi_win_fence_")) { |
96 | | // GreenErr() << "---> Found a synchro\n"; |
97 | 55 | BBToMemAccess[BB].clear(); |
98 | 55 | } |
99 | 1.50k | } |
100 | 3.17k | } else if (StoreInst *SI = dyn_cast<StoreInst>(&Inst)) { |
101 | 483 | Mem = SI->getPointerOperand(); |
102 | 483 | IsLoadOrStore = true; |
103 | 2.69k | } else if (LoadInst *LI = dyn_cast<LoadInst>(&Inst)) { |
104 | 826 | Mem = LI->getPointerOperand(); |
105 | 826 | IsLoadOrStore = true; |
106 | 826 | } |
107 | | |
108 | 4.68k | if (Mem) { |
109 | 1.38k | auto PrevAccess = BBToMemAccess[BB].find(Mem); |
110 | | |
111 | | // (2) mem is stored in ValueMap |
112 | 1.38k | if (BBToMemAccess[BB].count(Mem) != 0) { |
113 | 23 | if (getInstructionType(PrevAccess->second) == WRITE || |
114 | 23 | getInstructionType(&Inst) == WRITE) { |
115 | | // Check if we already report this error |
116 | | // if(ConcurrentAccesses[F].count(inst) == 0 && |
117 | | // ConcurrentAccesses[F].count(PrevAccess->second) == 0){ |
118 | 13 | Results.insert({&Inst, PrevAccess->second}); |
119 | 13 | } else { |
120 | | /*MagentaErr() << "INFO: Memory address already in map - last access |
121 | | from instruction: "; PrevAccess->second->print(errs()); errs() << |
122 | | "\n";*/ |
123 | 10 | if (!IsLoadOrStore) { |
124 | 8 | PrevAccess->second = &Inst; |
125 | 8 | } |
126 | 10 | } |
127 | | // (2) mem is not stored in ValueMap - check if a memory stored in |
128 | | // ValueMap alias with mem |
129 | 1.36k | } else { |
130 | | // errs() << "(2) No memory access found in ValueMap: " << |
131 | | // PrevAccess->second << "\n"; |
132 | | /*GreenErr() << "DEBUG INFO: no PrevAccess found for instruction: "; |
133 | | inst->print(errs()); |
134 | | errs() << "\n";*/ |
135 | 1.36k | ValueMap<Value *, Instruction *>::iterator It; |
136 | | // iterate over the ValueMap to get the first write that alias with mem |
137 | 1.55k | for (It = BBToMemAccess[BB].begin(); It != BBToMemAccess[BB].end(); |
138 | 1.36k | It++) { |
139 | 185 | if (AA.alias(It->first, Mem) != AliasResult::NoAlias) { |
140 | | // if(AA.alias(it->first,mem) == AliasResult::MayAlias) |
141 | | // errs() << "(2) No memory access found in ValueMap: " << it->first |
142 | | //<< " but found a may alias!\n"; |
143 | | // errs() << "(2) No memory access found in ValueMap: " << it->first |
144 | | //<< " but found an alias!\n"; |
145 | 18 | if (getInstructionType(It->second) == WRITE || |
146 | 18 | getInstructionType(&Inst) == WRITE) { |
147 | 10 | Results.insert({&Inst, It->second}); |
148 | 10 | } |
149 | 18 | } |
150 | 185 | } |
151 | | // store mem if the instruction is a MPI-RMA |
152 | 1.36k | if (!IsLoadOrStore) { |
153 | 67 | BBToMemAccess[BB].insert({Mem, &Inst}); |
154 | | /*MagentaErr() << "DEBUG INFO: Add new memory access from instruction: |
155 | | "; inst->print(errs()); errs() << "\n";*/ |
156 | 67 | } |
157 | 1.36k | } |
158 | 1.38k | } |
159 | 4.68k | } |
160 | 488 | } |
161 | | |
162 | | // If all predecessors have not been set to black, return true otherwise return |
163 | | // false |
164 | 489 | bool LCDAnalysis::mustWait(BasicBlock *BB) { |
165 | 489 | if (LheaderMap[BB]) { |
166 | | // errs() << "is lopp header\n"; |
167 | 8 | return false; // ignore loop headers |
168 | 8 | } |
169 | 481 | pred_iterator PI = pred_begin(BB); |
170 | 481 | pred_iterator E = pred_end(BB); |
171 | 1.09k | for (; PI != E; ++PI) { |
172 | 629 | BasicBlock *Pred = *PI; |
173 | 629 | if (ColorMap[Pred] != BLACK) { |
174 | 17 | return true; |
175 | 17 | } |
176 | 629 | } |
177 | 464 | return false; |
178 | 481 | } |
179 | | |
180 | 16 | bool LCDAnalysis::mustWaitLoop(llvm::BasicBlock *BB, Loop *L) { |
181 | 16 | pred_iterator PI = pred_begin(BB); |
182 | 16 | pred_iterator E = pred_end(BB); |
183 | 24 | for (; PI != E; ++PI) { |
184 | 16 | BasicBlock *Pred = *PI; |
185 | | // BB is in the only bb in loop |
186 | 16 | if ((Pred == BB) || (LlatchMap[Pred])) { |
187 | 0 | continue; |
188 | 0 | } |
189 | 16 | if (ColorMap[Pred] != BLACK && L->contains(Pred)) { |
190 | | // printBB(Pred); |
191 | | // errs() << " is white \n"; |
192 | 8 | return true; |
193 | 8 | } |
194 | 16 | } |
195 | 8 | return false; |
196 | 16 | } |
197 | | |
198 | 8 | void LCDAnalysis::bfsLoop(Loop *L) { |
199 | 8 | std::deque<BasicBlock *> Unvisited; |
200 | 8 | BasicBlock *Lheader = L->getHeader(); |
201 | 8 | BasicBlock *Llatch = L->getLoopLatch(); |
202 | | |
203 | 8 | for (Loop *ChildLoop : *L) { |
204 | 0 | bfsLoop(ChildLoop); |
205 | 0 | } |
206 | | /*errs() << ".. BFS on loop containing ..\n"; |
207 | | |
208 | | for (BasicBlock *BB : L->blocks()) { |
209 | | printBB(BB); |
210 | | } |
211 | | errs() << "....\n"; |
212 | | */ |
213 | 8 | Unvisited.push_back(Lheader); |
214 | 8 | LheaderMap[L->getHeader()] = true; |
215 | | |
216 | 24 | while (!Unvisited.empty()) { |
217 | 16 | BasicBlock *Header = *Unvisited.begin(); |
218 | | // printBB(header); |
219 | 16 | Unvisited.pop_front(); |
220 | | |
221 | 16 | if (ColorMap[Header] == BLACK) { |
222 | 0 | continue; |
223 | 0 | } |
224 | 16 | if (mustWaitLoop(Header, L) && |
225 | 16 | Header != L->getHeader()) { // all predecessors have not been seen |
226 | | // errs() << "must wait..\n"; |
227 | 0 | Unvisited.push_back(Header); |
228 | 0 | continue; |
229 | 0 | } |
230 | | |
231 | 16 | analyzeBB(Header); |
232 | 16 | ColorMap[Header] = GREY; |
233 | | |
234 | 16 | succ_iterator SI = succ_begin(Header); |
235 | 16 | succ_iterator E = succ_end(Header); |
236 | 40 | for (; SI != E; ++SI) { |
237 | 24 | BasicBlock *Succ = *SI; |
238 | | // Ignore successor not in loop |
239 | 24 | if (!(L->contains(Succ))) { |
240 | 8 | continue; |
241 | 8 | } |
242 | | // ignore back edge when the loop has already been checked |
243 | 16 | if (LlatchMap[Header] && LheaderMap[Succ]) { |
244 | 0 | continue; |
245 | 0 | } |
246 | | |
247 | | // Succ not seen before |
248 | 16 | if (ColorMap[Succ] == WHITE) { |
249 | 8 | BBToMemAccess[Succ].insert(BBToMemAccess[Header].begin(), |
250 | 8 | BBToMemAccess[Header].end()); |
251 | 8 | ColorMap[Succ] = GREY; |
252 | 8 | Unvisited.push_back(Succ); |
253 | | // Succ already seen |
254 | 8 | } else { |
255 | | // merge the memory accesses from the previous paths - only local errors |
256 | | // detection |
257 | | // For latter: report concurrent one-sided |
258 | 8 | BBToMemAccess[Succ].insert(BBToMemAccess[Header].begin(), |
259 | 8 | BBToMemAccess[Header].end()); |
260 | 8 | } |
261 | 16 | } |
262 | 16 | ColorMap[Header] = BLACK; |
263 | 16 | } |
264 | | // reset BB colors in loop and ignore backedge for the rest of the BFS |
265 | 16 | for (BasicBlock *BB : L->blocks()) { |
266 | 16 | ColorMap[BB] = WHITE; |
267 | 16 | } |
268 | 8 | LlatchMap[Llatch] = true; |
269 | 8 | } |
270 | | |
271 | 55 | void LCDAnalysis::analyze(Function *F) { |
272 | | // All BB must be white at the beginning |
273 | 472 | for (BasicBlock &BB : *F) { |
274 | 472 | ColorMap[&BB] = WHITE; |
275 | 472 | LheaderMap[&BB] = false; |
276 | 472 | LlatchMap[&BB] = false; |
277 | 472 | } |
278 | | |
279 | 55 | std::deque<BasicBlock *> Unvisited; |
280 | 55 | BasicBlock &Entry = F->getEntryBlock(); |
281 | 55 | Unvisited.push_back(&Entry); |
282 | | |
283 | | // errs() << ".. BFS on loops ..\n"; |
284 | 55 | auto &LI = FAM.getResult<LoopAnalysis>(*F); |
285 | 55 | for (Loop *L : LI) { |
286 | 8 | bfsLoop(L); |
287 | 8 | } |
288 | | |
289 | | // errs() << ".. BFS ..\n"; |
290 | | // BFS |
291 | 544 | while (!Unvisited.empty()) { |
292 | 489 | BasicBlock *Header = *Unvisited.begin(); |
293 | | // printBB(header); |
294 | | // errs() << "has color = " << ColorMap[header] << "\n"; |
295 | 489 | Unvisited.pop_front(); |
296 | | |
297 | 489 | if (ColorMap[Header] == BLACK) { |
298 | 0 | continue; |
299 | 0 | } |
300 | | |
301 | 489 | if (mustWait(Header)) { // all predecessors have not been seen |
302 | | // errs() << " must wait \n"; |
303 | 17 | Unvisited.push_back(Header); |
304 | 17 | continue; |
305 | 17 | } |
306 | | |
307 | 472 | analyzeBB(Header); |
308 | 472 | ColorMap[Header] = GREY; |
309 | | |
310 | 472 | succ_iterator SI = succ_begin(Header); |
311 | 472 | succ_iterator E = succ_end(Header); |
312 | 1.10k | for (; SI != E; ++SI) { |
313 | 628 | BasicBlock *Succ = *SI; |
314 | | // ignore back edge |
315 | 628 | if (LlatchMap[Header] && LheaderMap[Succ]) { |
316 | 8 | continue; |
317 | 8 | } |
318 | | // Succ not seen before |
319 | 620 | if (ColorMap[Succ] == WHITE) { |
320 | 417 | BBToMemAccess[Succ].insert(BBToMemAccess[Header].begin(), |
321 | 417 | BBToMemAccess[Header].end()); |
322 | | // analyzeBB(Succ, AA); |
323 | 417 | ColorMap[Succ] = GREY; |
324 | 417 | Unvisited.push_back(Succ); |
325 | | // Succ already seen |
326 | 417 | } else { |
327 | | // merge the memory accesses from the previous paths - only local errors |
328 | | // detection |
329 | | // For latter: report concurrent one-sided |
330 | 203 | BBToMemAccess[Succ].insert(BBToMemAccess[Header].begin(), |
331 | 203 | BBToMemAccess[Header].end()); |
332 | 203 | } |
333 | 620 | } |
334 | 472 | ColorMap[Header] = BLACK; |
335 | 472 | } |
336 | | // Lheaders.clear(); |
337 | 55 | } |
338 | | } // namespace |
339 | | |
340 | | AnalysisKey LocalConcurrencyAnalysis::Key; |
341 | | LocalConcurrencyVector |
342 | 55 | LocalConcurrencyAnalysis::run(Function &F, FunctionAnalysisManager &AM) { |
343 | 55 | TimeTraceScope TTS("LocalConcurrencyAnalysis"); |
344 | 55 | LCDAnalysis LCD(AM); |
345 | 55 | LCD.analyze(&F); |
346 | | |
347 | 55 | return LCD.takeResults(); |
348 | 55 | } |
349 | | |
350 | | } // namespace parcoach::rma |