1// RUN: %clang_cc1 -analyze -analyzer-checker=optin.mpi.MPI-Checker -verify %s
2
3#include "MPIMock.h"
4
5void matchedWait1() {
6  int rank = 0;
7  double buf = 0;
8  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
9  if (rank >= 0) {
10    MPI_Request sendReq1, recvReq1;
11    MPI_Isend(&buf, 1, MPI_DOUBLE, rank + 1, 0, MPI_COMM_WORLD, &sendReq1);
12    MPI_Irecv(&buf, 1, MPI_DOUBLE, rank - 1, 0, MPI_COMM_WORLD, &recvReq1);
13
14    MPI_Wait(&sendReq1, MPI_STATUS_IGNORE);
15    MPI_Wait(&recvReq1, MPI_STATUS_IGNORE);
16  }
17} // no error
18
19void matchedWait2() {
20  int rank = 0;
21  double buf = 0;
22  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
23  if (rank >= 0) {
24    MPI_Request sendReq1, recvReq1;
25    MPI_Isend(&buf, 1, MPI_DOUBLE, rank + 1, 0, MPI_COMM_WORLD, &sendReq1);
26    MPI_Irecv(&buf, 1, MPI_DOUBLE, rank - 1, 0, MPI_COMM_WORLD, &recvReq1);
27    MPI_Wait(&sendReq1, MPI_STATUS_IGNORE);
28    MPI_Wait(&recvReq1, MPI_STATUS_IGNORE);
29  }
30} // no error
31
32void matchedWait3() {
33  int rank = 0;
34  double buf = 0;
35  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
36  if (rank >= 0) {
37    MPI_Request sendReq1, recvReq1;
38    MPI_Isend(&buf, 1, MPI_DOUBLE, rank + 1, 0, MPI_COMM_WORLD, &sendReq1);
39    MPI_Irecv(&buf, 1, MPI_DOUBLE, rank - 1, 0, MPI_COMM_WORLD, &recvReq1);
40
41    if (rank > 1000) {
42      MPI_Wait(&sendReq1, MPI_STATUS_IGNORE);
43      MPI_Wait(&recvReq1, MPI_STATUS_IGNORE);
44    } else {
45      MPI_Wait(&sendReq1, MPI_STATUS_IGNORE);
46      MPI_Wait(&recvReq1, MPI_STATUS_IGNORE);
47    }
48  }
49} // no error
50
51void missingWait1() { // Check missing wait for dead region.
52  double buf = 0;
53  MPI_Request sendReq1;
54  MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD, &sendReq1);
55} // expected-warning{{Request 'sendReq1' has no matching wait.}}
56
57void missingWait2() {
58  int rank = 0;
59  double buf = 0;
60  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
61  if (rank == 0) {
62  } else {
63    MPI_Request sendReq1, recvReq1;
64
65    MPI_Isend(&buf, 1, MPI_DOUBLE, rank + 1, 0, MPI_COMM_WORLD, &sendReq1);
66    MPI_Irecv(&buf, 1, MPI_DOUBLE, rank - 1, 0, MPI_COMM_WORLD, &recvReq1); // expected-warning{{Request 'sendReq1' has no matching wait.}}
67    MPI_Wait(&recvReq1, MPI_STATUS_IGNORE);
68  }
69}
70
71void doubleNonblocking() {
72  int rank = 0;
73  double buf = 0;
74  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
75  if (rank == 1) {
76  } else {
77    MPI_Request sendReq1;
78
79    MPI_Isend(&buf, 1, MPI_DOUBLE, rank + 1, 0, MPI_COMM_WORLD, &sendReq1);
80    MPI_Irecv(&buf, 1, MPI_DOUBLE, rank - 1, 0, MPI_COMM_WORLD, &sendReq1); // expected-warning{{Double nonblocking on request 'sendReq1'.}}
81    MPI_Wait(&sendReq1, MPI_STATUS_IGNORE);
82  }
83}
84
85void doubleNonblocking2() {
86  int rank = 0;
87  double buf = 0;
88  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
89
90  MPI_Request req;
91  MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD, &req);
92  MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD, &req); // expected-warning{{Double nonblocking on request 'req'.}}
93  MPI_Wait(&req, MPI_STATUS_IGNORE);
94}
95
96void doubleNonblocking3() {
97  typedef struct { MPI_Request req; } ReqStruct;
98
99  ReqStruct rs;
100  int rank = 0;
101  double buf = 0;
102  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
103
104  MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD, &rs.req);
105  MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD, &rs.req); // expected-warning{{Double nonblocking on request 'rs.req'.}}
106  MPI_Wait(&rs.req, MPI_STATUS_IGNORE);
107}
108
109void doubleNonblocking4() {
110  int rank = 0;
111  double buf = 0;
112  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
113
114  MPI_Request req;
115  for (int i = 0; i < 2; ++i) {
116    MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD, &req); // expected-warning{{Double nonblocking on request 'req'.}}
117  }
118  MPI_Wait(&req, MPI_STATUS_IGNORE);
119}
120
121void tripleNonblocking() {
122  double buf = 0;
123  MPI_Request sendReq;
124  MPI_Isend(&buf, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &sendReq);
125  MPI_Irecv(&buf, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &sendReq); // expected-warning{{Double nonblocking on request 'sendReq'.}}
126  MPI_Isend(&buf, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &sendReq); // expected-warning{{Double nonblocking on request 'sendReq'.}}
127  MPI_Wait(&sendReq, MPI_STATUS_IGNORE);
128}
129
130void missingNonBlocking() {
131  int rank = 0;
132  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
133  MPI_Request sendReq1[10][10][10];
134  MPI_Wait(&sendReq1[1][7][9], MPI_STATUS_IGNORE); // expected-warning{{Request 'sendReq1[1][7][9]' has no matching nonblocking call.}}
135}
136
137void missingNonBlocking2() {
138  int rank = 0;
139  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
140  typedef struct { MPI_Request req[2][2]; } ReqStruct;
141  ReqStruct rs;
142  MPI_Request *r = &rs.req[0][1];
143  MPI_Wait(r, MPI_STATUS_IGNORE); // expected-warning{{Request 'rs.req[0][1]' has no matching nonblocking call.}}
144}
145
146void missingNonBlocking3() {
147  int rank = 0;
148  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
149  MPI_Request sendReq;
150  MPI_Wait(&sendReq, MPI_STATUS_IGNORE); // expected-warning{{Request 'sendReq' has no matching nonblocking call.}}
151}
152
153void missingNonBlockingMultiple() {
154  int rank = 0;
155  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
156  MPI_Request sendReq[4];
157  for (int i = 0; i < 4; ++i) {
158    MPI_Wait(&sendReq[i], MPI_STATUS_IGNORE); // expected-warning-re 1+{{Request {{.*}} has no matching nonblocking call.}}
159  }
160}
161
162void missingNonBlockingWaitall() {
163  int rank = 0;
164  double buf = 0;
165  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
166  MPI_Request req[4];
167
168  MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD,
169      &req[0]);
170  MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD,
171      &req[1]);
172  MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD,
173      &req[3]);
174
175  MPI_Waitall(4, req, MPI_STATUSES_IGNORE); // expected-warning{{Request 'req[2]' has no matching nonblocking call.}}
176}
177
178void missingNonBlockingWaitall2() {
179  int rank = 0;
180  double buf = 0;
181  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
182  MPI_Request req[4];
183
184  MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD,
185      &req[0]);
186  MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD,
187      &req[3]);
188
189  MPI_Waitall(4, req, MPI_STATUSES_IGNORE); // expected-warning-re 2{{Request '{{(.*)[[1-2]](.*)}}' has no matching nonblocking call.}}
190}
191
192void missingNonBlockingWaitall3() {
193  int rank = 0;
194  double buf = 0;
195  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
196  MPI_Request req[4];
197
198  MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD,
199      &req[0]);
200  MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD,
201      &req[2]);
202
203  MPI_Waitall(4, req, MPI_STATUSES_IGNORE); // expected-warning-re 2{{Request '{{(.*)[[1,3]](.*)}}' has no matching nonblocking call.}}
204}
205
206void missingNonBlockingWaitall4() {
207  int rank = 0;
208  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
209  MPI_Request req[4];
210  MPI_Waitall(4, req, MPI_STATUSES_IGNORE); // expected-warning-re 4{{Request '{{(.*)[[0-3]](.*)}}' has no matching nonblocking call.}}
211}
212
213void noDoubleRequestUsage() {
214  typedef struct {
215    MPI_Request req;
216    MPI_Request req2;
217  } ReqStruct;
218
219  ReqStruct rs;
220  int rank = 0;
221  double buf = 0;
222  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
223
224  MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD,
225              &rs.req);
226  MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD,
227              &rs.req2);
228  MPI_Wait(&rs.req, MPI_STATUS_IGNORE);
229  MPI_Wait(&rs.req2, MPI_STATUS_IGNORE);
230} // no error
231
232void noDoubleRequestUsage2() {
233  typedef struct {
234    MPI_Request req[2];
235    MPI_Request req2;
236  } ReqStruct;
237
238  ReqStruct rs;
239  int rank = 0;
240  double buf = 0;
241  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
242
243  MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD,
244              &rs.req[0]);
245  MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD,
246              &rs.req[1]);
247  MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD,
248              &rs.req2);
249  MPI_Wait(&rs.req[0], MPI_STATUS_IGNORE);
250  MPI_Wait(&rs.req[1], MPI_STATUS_IGNORE);
251  MPI_Wait(&rs.req2, MPI_STATUS_IGNORE);
252} // no error
253
254void nestedRequest() {
255  typedef struct {
256    MPI_Request req[2];
257    MPI_Request req2;
258  } ReqStruct;
259
260  ReqStruct rs;
261  int rank = 0;
262  double buf = 0;
263  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
264
265  MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD,
266              &rs.req[0]);
267  MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD,
268              &rs.req[1]);
269  MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD,
270              &rs.req2);
271  MPI_Waitall(2, rs.req, MPI_STATUSES_IGNORE);
272  MPI_Wait(&rs.req2, MPI_STATUS_IGNORE);
273} // no error
274
275void singleRequestInWaitall() {
276  MPI_Request r;
277  int rank = 0;
278  double buf = 0;
279  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
280
281  MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD,
282              &r);
283  MPI_Waitall(1, &r, MPI_STATUSES_IGNORE);
284} // no error
285
286void multiRequestUsage() {
287  double buf = 0;
288  MPI_Request req;
289
290  MPI_Isend(&buf, 1, MPI_DOUBLE, 1, 0, MPI_COMM_WORLD, &req);
291  MPI_Wait(&req, MPI_STATUS_IGNORE);
292
293  MPI_Irecv(&buf, 1, MPI_DOUBLE, 1, 0, MPI_COMM_WORLD, &req);
294  MPI_Wait(&req, MPI_STATUS_IGNORE);
295} // no error
296
297void multiRequestUsage2() {
298  double buf = 0;
299  MPI_Request req;
300
301  MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD,
302              &req);
303  MPI_Wait(&req, MPI_STATUS_IGNORE);
304
305  MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD,
306              &req);
307  MPI_Wait(&req, MPI_STATUS_IGNORE);
308} // no error
309
310// wrapper function
311void callNonblocking(MPI_Request *req) {
312  double buf = 0;
313  MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD,
314             req);
315}
316
317// wrapper function
318void callWait(MPI_Request *req) {
319  MPI_Wait(req, MPI_STATUS_IGNORE);
320}
321
322// Call nonblocking, wait wrapper functions.
323void callWrapperFunctions() {
324  MPI_Request req;
325  callNonblocking(&req);
326  callWait(&req);
327} // no error
328
329void externFunctions1() {
330  double buf = 0;
331  MPI_Request req;
332  MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD,
333              &req);
334  void callWaitExtern(MPI_Request *req);
335  callWaitExtern(&req);
336} // expected-warning{{Request 'req' has no matching wait.}}
337
338void externFunctions2() {
339  MPI_Request req;
340  void callNonblockingExtern(MPI_Request *req);
341  callNonblockingExtern(&req);
342}
343