| //===- unittests/AST/OMPStructuredBlockTest.cpp ---------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // Fine-grained tests for IsOMPStructuredBlock bit of Stmt. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "ASTPrint.h" |
| #include "clang/AST/ASTContext.h" |
| #include "clang/AST/StmtOpenMP.h" |
| #include "clang/ASTMatchers/ASTMatchFinder.h" |
| #include "clang/ASTMatchers/ASTMatchers.h" |
| #include "clang/Tooling/Tooling.h" |
| #include "llvm/ADT/SmallString.h" |
| #include "gmock/gmock.h" |
| #include "gtest/gtest.h" |
| |
| using namespace clang; |
| using namespace ast_matchers; |
| using namespace tooling; |
| |
| namespace { |
| |
| const ast_matchers::internal::VariadicDynCastAllOfMatcher< |
| OMPExecutableDirective, OMPTargetDirective> |
| ompTargetDirective; |
| |
| StatementMatcher OMPInnermostStructuredBlockMatcher() { |
| return stmt(isOMPStructuredBlock(), |
| unless(hasDescendant(stmt(isOMPStructuredBlock())))) |
| .bind("id"); |
| } |
| |
| StatementMatcher OMPStandaloneDirectiveMatcher() { |
| return stmt(ompExecutableDirective(isStandaloneDirective())).bind("id"); |
| } |
| |
| template <typename T> |
| ::testing::AssertionResult |
| PrintedOMPStmtMatches(StringRef Code, const T &NodeMatch, |
| StringRef ExpectedPrinted, |
| PolicyAdjusterType PolicyAdjuster = None) { |
| std::vector<std::string> Args = { |
| "-fopenmp=libomp", |
| }; |
| return PrintedStmtMatches(Code, Args, NodeMatch, ExpectedPrinted, |
| PolicyAdjuster); |
| } |
| |
| static testing::AssertionResult NoMatches(StringRef Code, |
| const StatementMatcher &StmtMatch) { |
| PrintMatch Printer((PolicyAdjusterType())); |
| MatchFinder Finder; |
| Finder.addMatcher(StmtMatch, &Printer); |
| std::unique_ptr<FrontendActionFactory> Factory( |
| newFrontendActionFactory(&Finder)); |
| if (!runToolOnCode(Factory->create(), Code)) |
| return testing::AssertionFailure() |
| << "Parsing error in \"" << Code.str() << "\""; |
| if (Printer.getNumFoundStmts() == 0) |
| return testing::AssertionSuccess(); |
| return testing::AssertionFailure() |
| << "Matcher should match only zero statements (found " |
| << Printer.getNumFoundStmts() << ")"; |
| } |
| |
| } // unnamed namespace |
| |
| TEST(OMPStructuredBlock, TestAtomic) { |
| const char *Source = |
| R"( |
| void test(int i) { |
| #pragma omp atomic |
| ++i; |
| })"; |
| ASSERT_TRUE(PrintedOMPStmtMatches( |
| Source, OMPInnermostStructuredBlockMatcher(), "++i")); |
| } |
| |
| TEST(OMPStructuredBlock, TestBarrier) { |
| const char *Source = |
| R"( |
| void test() { |
| #pragma omp barrier |
| })"; |
| ASSERT_TRUE(PrintedOMPStmtMatches(Source, OMPStandaloneDirectiveMatcher(), |
| "#pragma omp barrier\n")); |
| ASSERT_TRUE(NoMatches(Source, OMPInnermostStructuredBlockMatcher())); |
| } |
| |
| TEST(OMPStructuredBlock, TestCancel) { |
| const char *Source = |
| R"( |
| void test() { |
| #pragma omp parallel |
| { |
| #pragma omp cancel parallel |
| } |
| })"; |
| const char *Expected = R"({ |
| #pragma omp cancel parallel |
| } |
| )"; |
| ASSERT_TRUE(PrintedOMPStmtMatches( |
| Source, OMPInnermostStructuredBlockMatcher(), Expected)); |
| ASSERT_TRUE(PrintedOMPStmtMatches(Source, OMPStandaloneDirectiveMatcher(), |
| "#pragma omp cancel parallel\n")); |
| } |
| |
| TEST(OMPStructuredBlock, TestCancellationPoint) { |
| const char *Source = |
| R"( |
| void test() { |
| #pragma omp parallel |
| { |
| #pragma omp cancellation point parallel |
| } |
| })"; |
| const char *Expected = R"({ |
| #pragma omp cancellation point parallel |
| } |
| )"; |
| ASSERT_TRUE(PrintedOMPStmtMatches( |
| Source, OMPInnermostStructuredBlockMatcher(), Expected)); |
| ASSERT_TRUE( |
| PrintedOMPStmtMatches(Source, OMPStandaloneDirectiveMatcher(), |
| "#pragma omp cancellation point parallel\n")); |
| } |
| |
| TEST(OMPStructuredBlock, TestCritical) { |
| const char *Source = |
| R"( |
| void test() { |
| #pragma omp critical |
| ; |
| })"; |
| ASSERT_TRUE(PrintedOMPStmtMatches( |
| Source, OMPInnermostStructuredBlockMatcher(), ";\n")); |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Loop tests |
| //----------------------------------------------------------------------------// |
| |
| class OMPStructuredBlockLoop : public ::testing::TestWithParam<const char *> {}; |
| |
| TEST_P(OMPStructuredBlockLoop, TestDirective0) { |
| const std::string Source = |
| R"( |
| void test(int x) { |
| #pragma omp )" + |
| std::string(GetParam()) + R"( |
| for (int i = 0; i < x; i++) |
| ; |
| })"; |
| ASSERT_TRUE(PrintedOMPStmtMatches( |
| Source, OMPInnermostStructuredBlockMatcher(), ";\n")); |
| } |
| |
| TEST_P(OMPStructuredBlockLoop, TestDirective1) { |
| const std::string Source = |
| R"( |
| void test(int x, int y) { |
| #pragma omp )" + |
| std::string(GetParam()) + R"( |
| for (int i = 0; i < x; i++) |
| for (int i = 0; i < y; i++) |
| ; |
| })"; |
| ASSERT_TRUE(PrintedOMPStmtMatches(Source, |
| OMPInnermostStructuredBlockMatcher(), |
| "for (int i = 0; i < y; i++)\n ;\n")); |
| } |
| |
| TEST_P(OMPStructuredBlockLoop, TestDirectiveCollapse1) { |
| const std::string Source = |
| R"( |
| void test(int x, int y) { |
| #pragma omp )" + |
| std::string(GetParam()) + R"( collapse(1) |
| for (int i = 0; i < x; i++) |
| for (int i = 0; i < y; i++) |
| ; |
| })"; |
| ASSERT_TRUE(PrintedOMPStmtMatches(Source, |
| OMPInnermostStructuredBlockMatcher(), |
| "for (int i = 0; i < y; i++)\n ;\n")); |
| } |
| |
| TEST_P(OMPStructuredBlockLoop, TestDirectiveCollapse2) { |
| const std::string Source = |
| R"( |
| void test(int x, int y) { |
| #pragma omp )" + |
| std::string(GetParam()) + R"( collapse(2) |
| for (int i = 0; i < x; i++) |
| for (int i = 0; i < y; i++) |
| ; |
| })"; |
| ASSERT_TRUE(PrintedOMPStmtMatches( |
| Source, OMPInnermostStructuredBlockMatcher(), ";\n")); |
| } |
| |
| TEST_P(OMPStructuredBlockLoop, TestDirectiveCollapse22) { |
| const std::string Source = |
| R"( |
| void test(int x, int y, int z) { |
| #pragma omp )" + |
| std::string(GetParam()) + R"( collapse(2) |
| for (int i = 0; i < x; i++) |
| for (int i = 0; i < y; i++) |
| for (int i = 0; i < z; i++) |
| ; |
| })"; |
| ASSERT_TRUE(PrintedOMPStmtMatches(Source, |
| OMPInnermostStructuredBlockMatcher(), |
| "for (int i = 0; i < z; i++)\n ;\n")); |
| } |
| |
| INSTANTIATE_TEST_CASE_P( |
| OMPStructuredBlockLoopDirectives, OMPStructuredBlockLoop, |
| ::testing::Values("simd", "for", "for simd", "parallel for", |
| "parallel for simd", "target parallel for", "taskloop", |
| "taskloop simd", "distribute", "distribute parallel for", |
| "distribute parallel for simd", "distribute simd", |
| "target parallel for simd", "target simd", |
| "target\n#pragma omp teams distribute", |
| "target\n#pragma omp teams distribute simd", |
| "target\n#pragma omp teams distribute parallel for simd", |
| "target\n#pragma omp teams distribute parallel for", |
| "target teams distribute", |
| "target teams distribute parallel for", |
| "target teams distribute parallel for simd", |
| "target teams distribute simd"), ); |
| |
| //----------------------------------------------------------------------------// |
| // End Loop tests |
| //----------------------------------------------------------------------------// |
| |
| TEST(OMPStructuredBlock, TestFlush) { |
| const char *Source = |
| R"( |
| void test() { |
| #pragma omp flush |
| })"; |
| ASSERT_TRUE(PrintedOMPStmtMatches(Source, OMPStandaloneDirectiveMatcher(), |
| "#pragma omp flush\n")); |
| ASSERT_TRUE(NoMatches(Source, OMPInnermostStructuredBlockMatcher())); |
| } |
| |
| TEST(OMPStructuredBlock, TestMaster) { |
| const char *Source = |
| R"( |
| void test() { |
| #pragma omp master |
| ; |
| })"; |
| ASSERT_TRUE(PrintedOMPStmtMatches( |
| Source, OMPInnermostStructuredBlockMatcher(), ";\n")); |
| } |
| |
| TEST(OMPStructuredBlock, TestOrdered0) { |
| const char *Source = |
| R"( |
| void test() { |
| #pragma omp ordered |
| ; |
| })"; |
| ASSERT_TRUE(PrintedOMPStmtMatches( |
| Source, OMPInnermostStructuredBlockMatcher(), ";\n")); |
| } |
| |
| TEST(OMPStructuredBlock, TestOrdered1) { |
| const char *Source = |
| R"( |
| void test(int x) { |
| #pragma omp for ordered |
| for (int i = 0; i < x; i++) |
| ; |
| })"; |
| ASSERT_TRUE(PrintedOMPStmtMatches( |
| Source, OMPInnermostStructuredBlockMatcher(), ";\n")); |
| } |
| |
| TEST(OMPStructuredBlock, TestOrdered2) { |
| const char *Source = |
| R"( |
| void test(int x) { |
| #pragma omp for ordered(1) |
| for (int i = 0; i < x; i++) { |
| #pragma omp ordered depend(source) |
| } |
| })"; |
| ASSERT_TRUE( |
| PrintedOMPStmtMatches(Source, OMPInnermostStructuredBlockMatcher(), |
| "{\n #pragma omp ordered depend(source)\n}\n")); |
| ASSERT_TRUE(PrintedOMPStmtMatches(Source, OMPStandaloneDirectiveMatcher(), |
| "#pragma omp ordered depend(source)\n")); |
| } |
| |
| TEST(OMPStructuredBlock, DISABLED_TestParallelMaster0XFAIL) { |
| const char *Source = |
| R"( |
| void test() { |
| #pragma omp parallel master |
| ; |
| })"; |
| ASSERT_TRUE(PrintedOMPStmtMatches( |
| Source, OMPInnermostStructuredBlockMatcher(), ";\n")); |
| } |
| |
| TEST(OMPStructuredBlock, DISABLED_TestParallelMaster1XFAIL) { |
| const char *Source = |
| R"( |
| void test() { |
| #pragma omp parallel master |
| { ; } |
| })"; |
| ASSERT_TRUE(PrintedOMPStmtMatches( |
| Source, OMPInnermostStructuredBlockMatcher(), "{\n ;\n}\n")); |
| } |
| |
| TEST(OMPStructuredBlock, TestParallelSections) { |
| const char *Source = |
| R"( |
| void test() { |
| #pragma omp parallel sections |
| { ; } |
| })"; |
| ASSERT_TRUE(PrintedOMPStmtMatches( |
| Source, OMPInnermostStructuredBlockMatcher(), "{\n ;\n}\n")); |
| } |
| |
| TEST(OMPStructuredBlock, TestParallelDirective) { |
| const char *Source = |
| R"( |
| void test() { |
| #pragma omp parallel |
| ; |
| })"; |
| ASSERT_TRUE(PrintedOMPStmtMatches( |
| Source, OMPInnermostStructuredBlockMatcher(), ";\n")); |
| } |
| |
| const ast_matchers::internal::VariadicDynCastAllOfMatcher< |
| OMPExecutableDirective, OMPSectionsDirective> |
| ompSectionsDirective; |
| |
| const ast_matchers::internal::VariadicDynCastAllOfMatcher< |
| OMPExecutableDirective, OMPSectionDirective> |
| ompSectionDirective; |
| |
| StatementMatcher OMPSectionsDirectiveMatcher() { |
| return stmt( |
| isOMPStructuredBlock(), |
| hasAncestor(ompExecutableDirective(ompSectionsDirective())), |
| unless(hasAncestor(ompExecutableDirective(ompSectionDirective())))) |
| .bind("id"); |
| } |
| |
| TEST(OMPStructuredBlock, TestSectionDirective) { |
| const char *Source = |
| R"( |
| void test() { |
| #pragma omp sections |
| { |
| #pragma omp section |
| ; |
| } |
| })"; |
| ASSERT_TRUE(PrintedOMPStmtMatches(Source, OMPSectionsDirectiveMatcher(), |
| "{\n" |
| " #pragma omp section\n" |
| " ;\n" |
| "}\n")); |
| ASSERT_TRUE(PrintedOMPStmtMatches( |
| Source, OMPInnermostStructuredBlockMatcher(), ";\n")); |
| } |
| |
| TEST(OMPStructuredBlock, TestSections) { |
| const char *Source = |
| R"( |
| void test() { |
| #pragma omp sections |
| { ; } |
| })"; |
| ASSERT_TRUE(PrintedOMPStmtMatches( |
| Source, OMPInnermostStructuredBlockMatcher(), "{\n ;\n}\n")); |
| } |
| |
| TEST(OMPStructuredBlock, TestSingleDirective) { |
| const char *Source = |
| R"( |
| void test() { |
| #pragma omp single |
| ; |
| })"; |
| ASSERT_TRUE(PrintedOMPStmtMatches( |
| Source, OMPInnermostStructuredBlockMatcher(), ";\n")); |
| } |
| |
| TEST(OMPStructuredBlock, TesTargetDataDirective) { |
| const char *Source = |
| R"( |
| void test(int x) { |
| #pragma omp target data map(x) |
| ; |
| })"; |
| ASSERT_TRUE(PrintedOMPStmtMatches( |
| Source, OMPInnermostStructuredBlockMatcher(), ";\n")); |
| } |
| |
| TEST(OMPStructuredBlock, TesTargetEnterDataDirective) { |
| const char *Source = |
| R"( |
| void test(int x) { |
| #pragma omp target enter data map(to : x) |
| })"; |
| ASSERT_TRUE( |
| PrintedOMPStmtMatches(Source, OMPStandaloneDirectiveMatcher(), |
| "#pragma omp target enter data map(to: x)\n")); |
| ASSERT_TRUE(NoMatches(Source, OMPInnermostStructuredBlockMatcher())); |
| } |
| |
| TEST(OMPStructuredBlock, TesTargetExitDataDirective) { |
| const char *Source = |
| R"( |
| void test(int x) { |
| #pragma omp target exit data map(from : x) |
| })"; |
| ASSERT_TRUE( |
| PrintedOMPStmtMatches(Source, OMPStandaloneDirectiveMatcher(), |
| "#pragma omp target exit data map(from: x)\n")); |
| ASSERT_TRUE(NoMatches(Source, OMPInnermostStructuredBlockMatcher())); |
| } |
| |
| TEST(OMPStructuredBlock, TestTargetParallelDirective) { |
| const char *Source = |
| R"( |
| void test() { |
| #pragma omp target parallel |
| ; |
| })"; |
| ASSERT_TRUE(PrintedOMPStmtMatches( |
| Source, OMPInnermostStructuredBlockMatcher(), ";\n")); |
| } |
| |
| TEST(OMPStructuredBlock, TestTargetTeams) { |
| const char *Source = |
| R"( |
| void test() { |
| #pragma omp target teams |
| ; |
| })"; |
| ASSERT_TRUE(PrintedOMPStmtMatches( |
| Source, OMPInnermostStructuredBlockMatcher(), ";\n")); |
| } |
| |
| TEST(OMPStructuredBlock, TestTargetUpdateDirective) { |
| const char *Source = |
| R"( |
| void test(int x) { |
| #pragma omp target update to(x) |
| })"; |
| ASSERT_TRUE(PrintedOMPStmtMatches(Source, OMPStandaloneDirectiveMatcher(), |
| "#pragma omp target update to(x)\n")); |
| ASSERT_TRUE(NoMatches(Source, OMPInnermostStructuredBlockMatcher())); |
| } |
| |
| TEST(OMPStructuredBlock, TestTarget) { |
| const char *Source = |
| R"( |
| void test() { |
| #pragma omp target |
| ; |
| })"; |
| ASSERT_TRUE(PrintedOMPStmtMatches( |
| Source, OMPInnermostStructuredBlockMatcher(), ";\n")); |
| } |
| |
| TEST(OMPStructuredBlock, TestTask) { |
| const char *Source = |
| R"( |
| void test() { |
| #pragma omp task |
| ; |
| })"; |
| ASSERT_TRUE(PrintedOMPStmtMatches( |
| Source, OMPInnermostStructuredBlockMatcher(), ";\n")); |
| } |
| |
| TEST(OMPStructuredBlock, TestTaskgroup) { |
| const char *Source = |
| R"( |
| void test() { |
| #pragma omp taskgroup |
| ; |
| })"; |
| ASSERT_TRUE(PrintedOMPStmtMatches( |
| Source, OMPInnermostStructuredBlockMatcher(), ";\n")); |
| } |
| |
| TEST(OMPStructuredBlock, TestTaskwaitDirective) { |
| const char *Source = |
| R"( |
| void test() { |
| #pragma omp taskwait |
| })"; |
| ASSERT_TRUE(PrintedOMPStmtMatches(Source, OMPStandaloneDirectiveMatcher(), |
| "#pragma omp taskwait\n")); |
| ASSERT_TRUE(NoMatches(Source, OMPInnermostStructuredBlockMatcher())); |
| } |
| |
| TEST(OMPStructuredBlock, TestTaskyieldDirective) { |
| const char *Source = |
| R"( |
| void test() { |
| #pragma omp taskyield |
| })"; |
| ASSERT_TRUE(PrintedOMPStmtMatches(Source, OMPStandaloneDirectiveMatcher(), |
| "#pragma omp taskyield\n")); |
| ASSERT_TRUE(NoMatches(Source, OMPInnermostStructuredBlockMatcher())); |
| } |
| |
| TEST(OMPStructuredBlock, TestTeams) { |
| const char *Source = |
| R"( |
| void test() { |
| #pragma omp target |
| #pragma omp teams |
| ; |
| })"; |
| ASSERT_TRUE(PrintedOMPStmtMatches( |
| Source, OMPInnermostStructuredBlockMatcher(), ";\n")); |
| } |