1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | #include "ASTPrint.h" |
14 | #include "clang/AST/ASTContext.h" |
15 | #include "clang/AST/StmtOpenMP.h" |
16 | #include "clang/ASTMatchers/ASTMatchFinder.h" |
17 | #include "clang/ASTMatchers/ASTMatchers.h" |
18 | #include "clang/Tooling/Tooling.h" |
19 | #include "llvm/ADT/SmallString.h" |
20 | #include "gmock/gmock.h" |
21 | #include "gtest/gtest.h" |
22 | |
23 | using namespace clang; |
24 | using namespace ast_matchers; |
25 | using namespace tooling; |
26 | |
27 | namespace { |
28 | |
29 | const ast_matchers::internal::VariadicDynCastAllOfMatcher< |
30 | OMPExecutableDirective, OMPTargetDirective> |
31 | ompTargetDirective; |
32 | |
33 | StatementMatcher OMPInnermostStructuredBlockMatcher() { |
34 | return stmt(isOMPStructuredBlock(), |
35 | unless(hasDescendant(stmt(isOMPStructuredBlock())))) |
36 | .bind("id"); |
37 | } |
38 | |
39 | StatementMatcher OMPStandaloneDirectiveMatcher() { |
40 | return stmt(ompExecutableDirective(isStandaloneDirective())).bind("id"); |
41 | } |
42 | |
43 | template <typename T> |
44 | ::testing::AssertionResult |
45 | PrintedOMPStmtMatches(StringRef Code, const T &NodeMatch, |
46 | StringRef ExpectedPrinted, |
47 | PolicyAdjusterType PolicyAdjuster = None) { |
48 | std::vector<std::string> Args = { |
49 | "-fopenmp=libomp", |
50 | }; |
51 | return PrintedStmtMatches(Code, Args, NodeMatch, ExpectedPrinted, |
52 | PolicyAdjuster); |
53 | } |
54 | |
55 | static testing::AssertionResult NoMatches(StringRef Code, |
56 | const StatementMatcher &StmtMatch) { |
57 | PrintMatch Printer((PolicyAdjusterType())); |
58 | MatchFinder Finder; |
59 | Finder.addMatcher(StmtMatch, &Printer); |
60 | std::unique_ptr<FrontendActionFactory> Factory( |
61 | newFrontendActionFactory(&Finder)); |
62 | if (!runToolOnCode(Factory->create(), Code)) |
63 | return testing::AssertionFailure() |
64 | << "Parsing error in \"" << Code.str() << "\""; |
65 | if (Printer.getNumFoundStmts() == 0) |
66 | return testing::AssertionSuccess(); |
67 | return testing::AssertionFailure() |
68 | << "Matcher should match only zero statements (found " |
69 | << Printer.getNumFoundStmts() << ")"; |
70 | } |
71 | |
72 | } |
73 | |
74 | TEST(OMPStructuredBlock, TestAtomic) { |
75 | const char *Source = |
76 | R"( |
77 | void test(int i) { |
78 | #pragma omp atomic |
79 | ++i; |
80 | })"; |
81 | ASSERT_TRUE(PrintedOMPStmtMatches( |
82 | Source, OMPInnermostStructuredBlockMatcher(), "++i")); |
83 | } |
84 | |
85 | TEST(OMPStructuredBlock, TestBarrier) { |
86 | const char *Source = |
87 | R"( |
88 | void test() { |
89 | #pragma omp barrier |
90 | })"; |
91 | ASSERT_TRUE(PrintedOMPStmtMatches(Source, OMPStandaloneDirectiveMatcher(), |
92 | "#pragma omp barrier\n")); |
93 | ASSERT_TRUE(NoMatches(Source, OMPInnermostStructuredBlockMatcher())); |
94 | } |
95 | |
96 | TEST(OMPStructuredBlock, TestCancel) { |
97 | const char *Source = |
98 | R"( |
99 | void test() { |
100 | #pragma omp parallel |
101 | { |
102 | #pragma omp cancel parallel |
103 | } |
104 | })"; |
105 | const char *Expected = R"({ |
106 | #pragma omp cancel parallel |
107 | } |
108 | )"; |
109 | ASSERT_TRUE(PrintedOMPStmtMatches( |
110 | Source, OMPInnermostStructuredBlockMatcher(), Expected)); |
111 | ASSERT_TRUE(PrintedOMPStmtMatches(Source, OMPStandaloneDirectiveMatcher(), |
112 | "#pragma omp cancel parallel\n")); |
113 | } |
114 | |
115 | TEST(OMPStructuredBlock, TestCancellationPoint) { |
116 | const char *Source = |
117 | R"( |
118 | void test() { |
119 | #pragma omp parallel |
120 | { |
121 | #pragma omp cancellation point parallel |
122 | } |
123 | })"; |
124 | const char *Expected = R"({ |
125 | #pragma omp cancellation point parallel |
126 | } |
127 | )"; |
128 | ASSERT_TRUE(PrintedOMPStmtMatches( |
129 | Source, OMPInnermostStructuredBlockMatcher(), Expected)); |
130 | ASSERT_TRUE( |
131 | PrintedOMPStmtMatches(Source, OMPStandaloneDirectiveMatcher(), |
132 | "#pragma omp cancellation point parallel\n")); |
133 | } |
134 | |
135 | TEST(OMPStructuredBlock, TestCritical) { |
136 | const char *Source = |
137 | R"( |
138 | void test() { |
139 | #pragma omp critical |
140 | ; |
141 | })"; |
142 | ASSERT_TRUE(PrintedOMPStmtMatches( |
143 | Source, OMPInnermostStructuredBlockMatcher(), ";\n")); |
144 | } |
145 | |
146 | |
147 | |
148 | |
149 | |
150 | class OMPStructuredBlockLoop : public ::testing::TestWithParam<const char *> {}; |
151 | |
152 | TEST_P(OMPStructuredBlockLoop, TestDirective0) { |
153 | const std::string Source = |
154 | R"( |
155 | void test(int x) { |
156 | #pragma omp )" + |
157 | std::string(GetParam()) + R"( |
158 | for (int i = 0; i < x; i++) |
159 | ; |
160 | })"; |
161 | ASSERT_TRUE(PrintedOMPStmtMatches( |
162 | Source, OMPInnermostStructuredBlockMatcher(), ";\n")); |
163 | } |
164 | |
165 | TEST_P(OMPStructuredBlockLoop, TestDirective1) { |
166 | const std::string Source = |
167 | R"( |
168 | void test(int x, int y) { |
169 | #pragma omp )" + |
170 | std::string(GetParam()) + R"( |
171 | for (int i = 0; i < x; i++) |
172 | for (int i = 0; i < y; i++) |
173 | ; |
174 | })"; |
175 | ASSERT_TRUE(PrintedOMPStmtMatches(Source, |
176 | OMPInnermostStructuredBlockMatcher(), |
177 | "for (int i = 0; i < y; i++)\n ;\n")); |
178 | } |
179 | |
180 | TEST_P(OMPStructuredBlockLoop, TestDirectiveCollapse1) { |
181 | const std::string Source = |
182 | R"( |
183 | void test(int x, int y) { |
184 | #pragma omp )" + |
185 | std::string(GetParam()) + R"( collapse(1) |
186 | for (int i = 0; i < x; i++) |
187 | for (int i = 0; i < y; i++) |
188 | ; |
189 | })"; |
190 | ASSERT_TRUE(PrintedOMPStmtMatches(Source, |
191 | OMPInnermostStructuredBlockMatcher(), |
192 | "for (int i = 0; i < y; i++)\n ;\n")); |
193 | } |
194 | |
195 | TEST_P(OMPStructuredBlockLoop, TestDirectiveCollapse2) { |
196 | const std::string Source = |
197 | R"( |
198 | void test(int x, int y) { |
199 | #pragma omp )" + |
200 | std::string(GetParam()) + R"( collapse(2) |
201 | for (int i = 0; i < x; i++) |
202 | for (int i = 0; i < y; i++) |
203 | ; |
204 | })"; |
205 | ASSERT_TRUE(PrintedOMPStmtMatches( |
206 | Source, OMPInnermostStructuredBlockMatcher(), ";\n")); |
207 | } |
208 | |
209 | TEST_P(OMPStructuredBlockLoop, TestDirectiveCollapse22) { |
210 | const std::string Source = |
211 | R"( |
212 | void test(int x, int y, int z) { |
213 | #pragma omp )" + |
214 | std::string(GetParam()) + R"( collapse(2) |
215 | for (int i = 0; i < x; i++) |
216 | for (int i = 0; i < y; i++) |
217 | for (int i = 0; i < z; i++) |
218 | ; |
219 | })"; |
220 | ASSERT_TRUE(PrintedOMPStmtMatches(Source, |
221 | OMPInnermostStructuredBlockMatcher(), |
222 | "for (int i = 0; i < z; i++)\n ;\n")); |
223 | } |
224 | |
225 | INSTANTIATE_TEST_CASE_P( |
226 | OMPStructuredBlockLoopDirectives, OMPStructuredBlockLoop, |
227 | ::testing::Values("simd", "for", "for simd", "parallel for", |
228 | "parallel for simd", "target parallel for", "taskloop", |
229 | "taskloop simd", "distribute", "distribute parallel for", |
230 | "distribute parallel for simd", "distribute simd", |
231 | "target parallel for simd", "target simd", |
232 | "target\n#pragma omp teams distribute", |
233 | "target\n#pragma omp teams distribute simd", |
234 | "target\n#pragma omp teams distribute parallel for simd", |
235 | "target\n#pragma omp teams distribute parallel for", |
236 | "target teams distribute", |
237 | "target teams distribute parallel for", |
238 | "target teams distribute parallel for simd", |
239 | "target teams distribute simd"), ); |
240 | |
241 | |
242 | |
243 | |
244 | |
245 | TEST(OMPStructuredBlock, TestFlush) { |
246 | const char *Source = |
247 | R"( |
248 | void test() { |
249 | #pragma omp flush |
250 | })"; |
251 | ASSERT_TRUE(PrintedOMPStmtMatches(Source, OMPStandaloneDirectiveMatcher(), |
252 | "#pragma omp flush\n")); |
253 | ASSERT_TRUE(NoMatches(Source, OMPInnermostStructuredBlockMatcher())); |
254 | } |
255 | |
256 | TEST(OMPStructuredBlock, TestMaster) { |
257 | const char *Source = |
258 | R"( |
259 | void test() { |
260 | #pragma omp master |
261 | ; |
262 | })"; |
263 | ASSERT_TRUE(PrintedOMPStmtMatches( |
264 | Source, OMPInnermostStructuredBlockMatcher(), ";\n")); |
265 | } |
266 | |
267 | TEST(OMPStructuredBlock, TestOrdered0) { |
268 | const char *Source = |
269 | R"( |
270 | void test() { |
271 | #pragma omp ordered |
272 | ; |
273 | })"; |
274 | ASSERT_TRUE(PrintedOMPStmtMatches( |
275 | Source, OMPInnermostStructuredBlockMatcher(), ";\n")); |
276 | } |
277 | |
278 | TEST(OMPStructuredBlock, TestOrdered1) { |
279 | const char *Source = |
280 | R"( |
281 | void test(int x) { |
282 | #pragma omp for ordered |
283 | for (int i = 0; i < x; i++) |
284 | ; |
285 | })"; |
286 | ASSERT_TRUE(PrintedOMPStmtMatches( |
287 | Source, OMPInnermostStructuredBlockMatcher(), ";\n")); |
288 | } |
289 | |
290 | TEST(OMPStructuredBlock, TestOrdered2) { |
291 | const char *Source = |
292 | R"( |
293 | void test(int x) { |
294 | #pragma omp for ordered(1) |
295 | for (int i = 0; i < x; i++) { |
296 | #pragma omp ordered depend(source) |
297 | } |
298 | })"; |
299 | ASSERT_TRUE( |
300 | PrintedOMPStmtMatches(Source, OMPInnermostStructuredBlockMatcher(), |
301 | "{\n #pragma omp ordered depend(source)\n}\n")); |
302 | ASSERT_TRUE(PrintedOMPStmtMatches(Source, OMPStandaloneDirectiveMatcher(), |
303 | "#pragma omp ordered depend(source)\n")); |
304 | } |
305 | |
306 | TEST(OMPStructuredBlock, DISABLED_TestParallelMaster0XFAIL) { |
307 | const char *Source = |
308 | R"( |
309 | void test() { |
310 | #pragma omp parallel master |
311 | ; |
312 | })"; |
313 | ASSERT_TRUE(PrintedOMPStmtMatches( |
314 | Source, OMPInnermostStructuredBlockMatcher(), ";\n")); |
315 | } |
316 | |
317 | TEST(OMPStructuredBlock, DISABLED_TestParallelMaster1XFAIL) { |
318 | const char *Source = |
319 | R"( |
320 | void test() { |
321 | #pragma omp parallel master |
322 | { ; } |
323 | })"; |
324 | ASSERT_TRUE(PrintedOMPStmtMatches( |
325 | Source, OMPInnermostStructuredBlockMatcher(), "{\n ;\n}\n")); |
326 | } |
327 | |
328 | TEST(OMPStructuredBlock, TestParallelSections) { |
329 | const char *Source = |
330 | R"( |
331 | void test() { |
332 | #pragma omp parallel sections |
333 | { ; } |
334 | })"; |
335 | ASSERT_TRUE(PrintedOMPStmtMatches( |
336 | Source, OMPInnermostStructuredBlockMatcher(), "{\n ;\n}\n")); |
337 | } |
338 | |
339 | TEST(OMPStructuredBlock, TestParallelDirective) { |
340 | const char *Source = |
341 | R"( |
342 | void test() { |
343 | #pragma omp parallel |
344 | ; |
345 | })"; |
346 | ASSERT_TRUE(PrintedOMPStmtMatches( |
347 | Source, OMPInnermostStructuredBlockMatcher(), ";\n")); |
348 | } |
349 | |
350 | const ast_matchers::internal::VariadicDynCastAllOfMatcher< |
351 | OMPExecutableDirective, OMPSectionsDirective> |
352 | ompSectionsDirective; |
353 | |
354 | const ast_matchers::internal::VariadicDynCastAllOfMatcher< |
355 | OMPExecutableDirective, OMPSectionDirective> |
356 | ompSectionDirective; |
357 | |
358 | StatementMatcher OMPSectionsDirectiveMatcher() { |
359 | return stmt( |
360 | isOMPStructuredBlock(), |
361 | hasAncestor(ompExecutableDirective(ompSectionsDirective())), |
362 | unless(hasAncestor(ompExecutableDirective(ompSectionDirective())))) |
363 | .bind("id"); |
364 | } |
365 | |
366 | TEST(OMPStructuredBlock, TestSectionDirective) { |
367 | const char *Source = |
368 | R"( |
369 | void test() { |
370 | #pragma omp sections |
371 | { |
372 | #pragma omp section |
373 | ; |
374 | } |
375 | })"; |
376 | ASSERT_TRUE(PrintedOMPStmtMatches(Source, OMPSectionsDirectiveMatcher(), |
377 | "{\n" |
378 | " #pragma omp section\n" |
379 | " ;\n" |
380 | "}\n")); |
381 | ASSERT_TRUE(PrintedOMPStmtMatches( |
382 | Source, OMPInnermostStructuredBlockMatcher(), ";\n")); |
383 | } |
384 | |
385 | TEST(OMPStructuredBlock, TestSections) { |
386 | const char *Source = |
387 | R"( |
388 | void test() { |
389 | #pragma omp sections |
390 | { ; } |
391 | })"; |
392 | ASSERT_TRUE(PrintedOMPStmtMatches( |
393 | Source, OMPInnermostStructuredBlockMatcher(), "{\n ;\n}\n")); |
394 | } |
395 | |
396 | TEST(OMPStructuredBlock, TestSingleDirective) { |
397 | const char *Source = |
398 | R"( |
399 | void test() { |
400 | #pragma omp single |
401 | ; |
402 | })"; |
403 | ASSERT_TRUE(PrintedOMPStmtMatches( |
404 | Source, OMPInnermostStructuredBlockMatcher(), ";\n")); |
405 | } |
406 | |
407 | TEST(OMPStructuredBlock, TesTargetDataDirective) { |
408 | const char *Source = |
409 | R"( |
410 | void test(int x) { |
411 | #pragma omp target data map(x) |
412 | ; |
413 | })"; |
414 | ASSERT_TRUE(PrintedOMPStmtMatches( |
415 | Source, OMPInnermostStructuredBlockMatcher(), ";\n")); |
416 | } |
417 | |
418 | TEST(OMPStructuredBlock, TesTargetEnterDataDirective) { |
419 | const char *Source = |
420 | R"( |
421 | void test(int x) { |
422 | #pragma omp target enter data map(to : x) |
423 | })"; |
424 | ASSERT_TRUE( |
425 | PrintedOMPStmtMatches(Source, OMPStandaloneDirectiveMatcher(), |
426 | "#pragma omp target enter data map(to: x)\n")); |
427 | ASSERT_TRUE(NoMatches(Source, OMPInnermostStructuredBlockMatcher())); |
428 | } |
429 | |
430 | TEST(OMPStructuredBlock, TesTargetExitDataDirective) { |
431 | const char *Source = |
432 | R"( |
433 | void test(int x) { |
434 | #pragma omp target exit data map(from : x) |
435 | })"; |
436 | ASSERT_TRUE( |
437 | PrintedOMPStmtMatches(Source, OMPStandaloneDirectiveMatcher(), |
438 | "#pragma omp target exit data map(from: x)\n")); |
439 | ASSERT_TRUE(NoMatches(Source, OMPInnermostStructuredBlockMatcher())); |
440 | } |
441 | |
442 | TEST(OMPStructuredBlock, TestTargetParallelDirective) { |
443 | const char *Source = |
444 | R"( |
445 | void test() { |
446 | #pragma omp target parallel |
447 | ; |
448 | })"; |
449 | ASSERT_TRUE(PrintedOMPStmtMatches( |
450 | Source, OMPInnermostStructuredBlockMatcher(), ";\n")); |
451 | } |
452 | |
453 | TEST(OMPStructuredBlock, TestTargetTeams) { |
454 | const char *Source = |
455 | R"( |
456 | void test() { |
457 | #pragma omp target teams |
458 | ; |
459 | })"; |
460 | ASSERT_TRUE(PrintedOMPStmtMatches( |
461 | Source, OMPInnermostStructuredBlockMatcher(), ";\n")); |
462 | } |
463 | |
464 | TEST(OMPStructuredBlock, TestTargetUpdateDirective) { |
465 | const char *Source = |
466 | R"( |
467 | void test(int x) { |
468 | #pragma omp target update to(x) |
469 | })"; |
470 | ASSERT_TRUE(PrintedOMPStmtMatches(Source, OMPStandaloneDirectiveMatcher(), |
471 | "#pragma omp target update to(x)\n")); |
472 | ASSERT_TRUE(NoMatches(Source, OMPInnermostStructuredBlockMatcher())); |
473 | } |
474 | |
475 | TEST(OMPStructuredBlock, TestTarget) { |
476 | const char *Source = |
477 | R"( |
478 | void test() { |
479 | #pragma omp target |
480 | ; |
481 | })"; |
482 | ASSERT_TRUE(PrintedOMPStmtMatches( |
483 | Source, OMPInnermostStructuredBlockMatcher(), ";\n")); |
484 | } |
485 | |
486 | TEST(OMPStructuredBlock, TestTask) { |
487 | const char *Source = |
488 | R"( |
489 | void test() { |
490 | #pragma omp task |
491 | ; |
492 | })"; |
493 | ASSERT_TRUE(PrintedOMPStmtMatches( |
494 | Source, OMPInnermostStructuredBlockMatcher(), ";\n")); |
495 | } |
496 | |
497 | TEST(OMPStructuredBlock, TestTaskgroup) { |
498 | const char *Source = |
499 | R"( |
500 | void test() { |
501 | #pragma omp taskgroup |
502 | ; |
503 | })"; |
504 | ASSERT_TRUE(PrintedOMPStmtMatches( |
505 | Source, OMPInnermostStructuredBlockMatcher(), ";\n")); |
506 | } |
507 | |
508 | TEST(OMPStructuredBlock, TestTaskwaitDirective) { |
509 | const char *Source = |
510 | R"( |
511 | void test() { |
512 | #pragma omp taskwait |
513 | })"; |
514 | ASSERT_TRUE(PrintedOMPStmtMatches(Source, OMPStandaloneDirectiveMatcher(), |
515 | "#pragma omp taskwait\n")); |
516 | ASSERT_TRUE(NoMatches(Source, OMPInnermostStructuredBlockMatcher())); |
517 | } |
518 | |
519 | TEST(OMPStructuredBlock, TestTaskyieldDirective) { |
520 | const char *Source = |
521 | R"( |
522 | void test() { |
523 | #pragma omp taskyield |
524 | })"; |
525 | ASSERT_TRUE(PrintedOMPStmtMatches(Source, OMPStandaloneDirectiveMatcher(), |
526 | "#pragma omp taskyield\n")); |
527 | ASSERT_TRUE(NoMatches(Source, OMPInnermostStructuredBlockMatcher())); |
528 | } |
529 | |
530 | TEST(OMPStructuredBlock, TestTeams) { |
531 | const char *Source = |
532 | R"( |
533 | void test() { |
534 | #pragma omp target |
535 | #pragma omp teams |
536 | ; |
537 | })"; |
538 | ASSERT_TRUE(PrintedOMPStmtMatches( |
539 | Source, OMPInnermostStructuredBlockMatcher(), ";\n")); |
540 | } |
541 | |