[clang] 8bbf2e3 - [OPENMP50]Support for imperfectly nested loops.

Alexey Bataev via cfe-commits cfe-commits at lists.llvm.org
Mon Nov 4 13:26:08 PST 2019


Author: Alexey Bataev
Date: 2019-11-04T16:09:25-05:00
New Revision: 8bbf2e37167d9ac08fa9d3c772d48ca7d9a6f8f6

URL: https://github.com/llvm/llvm-project/commit/8bbf2e37167d9ac08fa9d3c772d48ca7d9a6f8f6
DIFF: https://github.com/llvm/llvm-project/commit/8bbf2e37167d9ac08fa9d3c772d48ca7d9a6f8f6.diff

LOG: [OPENMP50]Support for imperfectly nested loops.

Added support for imperfectly nested loops introduced in OpenMP 5.0.

Added: 
    

Modified: 
    clang/include/clang/AST/StmtOpenMP.h
    clang/lib/AST/StmtOpenMP.cpp
    clang/lib/CodeGen/CGStmtOpenMP.cpp
    clang/lib/Sema/SemaOpenMP.cpp
    clang/test/OpenMP/for_ast_print.cpp
    clang/test/OpenMP/for_codegen.cpp
    clang/test/OpenMP/for_collapse_messages.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/AST/StmtOpenMP.h b/clang/include/clang/AST/StmtOpenMP.h
index 722aa509b132..9807b3c8f680 100644
--- a/clang/include/clang/AST/StmtOpenMP.h
+++ b/clang/include/clang/AST/StmtOpenMP.h
@@ -1084,28 +1084,20 @@ class OMPLoopDirective : public OMPExecutableDirective {
     return const_cast<Expr *>(reinterpret_cast<const Expr *>(
         *std::next(child_begin(), CombinedParForInDistConditionOffset)));
   }
+  /// Try to find the next loop sub-statement in the specified statement \p
+  /// CurStmt.
+  /// \param TryImperfectlyNestedLoops true, if we need to try to look for the
+  /// imperfectly nested loop.
+  static Stmt *tryToFindNextInnerLoop(Stmt *CurStmt,
+                                      bool TryImperfectlyNestedLoops);
+  static const Stmt *tryToFindNextInnerLoop(const Stmt *CurStmt,
+                                            bool TryImperfectlyNestedLoops) {
+    return tryToFindNextInnerLoop(const_cast<Stmt *>(CurStmt),
+                                  TryImperfectlyNestedLoops);
+  }
+  Stmt *getBody();
   const Stmt *getBody() const {
-    // This relies on the loop form is already checked by Sema.
-    const Stmt *Body =
-        getInnermostCapturedStmt()->getCapturedStmt()->IgnoreContainers();
-    if (auto *For = dyn_cast<ForStmt>(Body)) {
-      Body = For->getBody();
-    } else {
-      assert(isa<CXXForRangeStmt>(Body) &&
-             "Expected canonical for loop or range-based for loop.");
-      Body = cast<CXXForRangeStmt>(Body)->getBody();
-    }
-    for (unsigned Cnt = 1; Cnt < CollapsedNum; ++Cnt) {
-      Body = Body->IgnoreContainers();
-      if (auto *For = dyn_cast<ForStmt>(Body)) {
-        Body = For->getBody();
-      } else {
-        assert(isa<CXXForRangeStmt>(Body) &&
-               "Expected canonical for loop or range-based for loop.");
-        Body = cast<CXXForRangeStmt>(Body)->getBody();
-      }
-    }
-    return Body;
+    return const_cast<OMPLoopDirective *>(this)->getBody();
   }
 
   ArrayRef<Expr *> counters() { return getCounters(); }

diff  --git a/clang/lib/AST/StmtOpenMP.cpp b/clang/lib/AST/StmtOpenMP.cpp
index a93192b4857f..12201ef9ec28 100644
--- a/clang/lib/AST/StmtOpenMP.cpp
+++ b/clang/lib/AST/StmtOpenMP.cpp
@@ -41,6 +41,74 @@ const Stmt *OMPExecutableDirective::getStructuredBlock() const {
   return getInnermostCapturedStmt()->getCapturedStmt();
 }
 
+Stmt *OMPLoopDirective::tryToFindNextInnerLoop(Stmt *CurStmt,
+                                               bool TryImperfectlyNestedLoops) {
+  Stmt *OrigStmt = CurStmt;
+  CurStmt = CurStmt->IgnoreContainers();
+  // Additional work for imperfectly nested loops, introduced in OpenMP 5.0.
+  if (TryImperfectlyNestedLoops) {
+    if (auto *CS = dyn_cast<CompoundStmt>(CurStmt)) {
+      CurStmt = nullptr;
+      SmallVector<CompoundStmt *, 4> Statements(1, CS);
+      SmallVector<CompoundStmt *, 4> NextStatements;
+      while (!Statements.empty()) {
+        CS = Statements.pop_back_val();
+        if (!CS)
+          continue;
+        for (Stmt *S : CS->body()) {
+          if (!S)
+            continue;
+          if (isa<ForStmt>(S) || isa<CXXForRangeStmt>(S)) {
+            // Only single loop construct is allowed.
+            if (CurStmt) {
+              CurStmt = OrigStmt;
+              break;
+            }
+            CurStmt = S;
+            continue;
+          }
+          S = S->IgnoreContainers();
+          if (auto *InnerCS = dyn_cast_or_null<CompoundStmt>(S))
+            NextStatements.push_back(InnerCS);
+        }
+        if (Statements.empty()) {
+          // Found single inner loop or multiple loops - exit.
+          if (CurStmt)
+            break;
+          Statements.swap(NextStatements);
+        }
+      }
+      if (!CurStmt)
+        CurStmt = OrigStmt;
+    }
+  }
+  return CurStmt;
+}
+
+Stmt *OMPLoopDirective::getBody() {
+  // This relies on the loop form is already checked by Sema.
+  Stmt *Body =
+      getInnermostCapturedStmt()->getCapturedStmt()->IgnoreContainers();
+  if (auto *For = dyn_cast<ForStmt>(Body)) {
+    Body = For->getBody();
+  } else {
+    assert(isa<CXXForRangeStmt>(Body) &&
+           "Expected canonical for loop or range-based for loop.");
+    Body = cast<CXXForRangeStmt>(Body)->getBody();
+  }
+  for (unsigned Cnt = 1; Cnt < CollapsedNum; ++Cnt) {
+    Body = tryToFindNextInnerLoop(Body, /*TryImperfectlyNestedLoops=*/true);
+    if (auto *For = dyn_cast<ForStmt>(Body)) {
+      Body = For->getBody();
+    } else {
+      assert(isa<CXXForRangeStmt>(Body) &&
+             "Expected canonical for loop or range-based for loop.");
+      Body = cast<CXXForRangeStmt>(Body)->getBody();
+    }
+  }
+  return Body;
+}
+
 void OMPLoopDirective::setCounters(ArrayRef<Expr *> A) {
   assert(A.size() == getCollapsedNumber() &&
          "Number of loop counters is not the same as the collapsed number");

diff  --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp
index df4b69e49866..4406fbc4144b 100644
--- a/clang/lib/CodeGen/CGStmtOpenMP.cpp
+++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp
@@ -18,6 +18,7 @@
 #include "clang/AST/Stmt.h"
 #include "clang/AST/StmtOpenMP.h"
 #include "clang/AST/DeclOpenMP.h"
+#include "clang/Basic/PrettyStackTrace.h"
 using namespace clang;
 using namespace CodeGen;
 
@@ -146,7 +147,8 @@ class OMPLoopScope : public CodeGenFunction::RunCleanupsScope {
     const Stmt *Body =
         S.getInnermostCapturedStmt()->getCapturedStmt()->IgnoreContainers();
     for (unsigned Cnt = 0; Cnt < S.getCollapsedNumber(); ++Cnt) {
-      Body = Body->IgnoreContainers();
+      Body = OMPLoopDirective::tryToFindNextInnerLoop(
+          Body, /*TryImperfectlyNestedLoops=*/true);
       if (auto *For = dyn_cast<ForStmt>(Body)) {
         Body = For->getBody();
       } else {
@@ -1339,6 +1341,41 @@ void CodeGenFunction::EmitOMPParallelDirective(const OMPParallelDirective &S) {
                                    [](CodeGenFunction &) { return nullptr; });
 }
 
+static void emitBody(CodeGenFunction &CGF, const Stmt *S, const Stmt *NextLoop,
+                     int MaxLevel, int Level = 0) {
+  assert(Level < MaxLevel && "Too deep lookup during loop body codegen.");
+  const Stmt *SimplifiedS = S->IgnoreContainers();
+  if (const auto *CS = dyn_cast<CompoundStmt>(SimplifiedS)) {
+    PrettyStackTraceLoc CrashInfo(
+        CGF.getContext().getSourceManager(), CS->getLBracLoc(),
+        "LLVM IR generation of compound statement ('{}')");
+
+    // Keep track of the current cleanup stack depth, including debug scopes.
+    CodeGenFunction::LexicalScope Scope(CGF, S->getSourceRange());
+    for (const Stmt *CurStmt : CS->body())
+      emitBody(CGF, CurStmt, NextLoop, MaxLevel, Level);
+    return;
+  }
+  if (SimplifiedS == NextLoop) {
+    if (const auto *For = dyn_cast<ForStmt>(SimplifiedS)) {
+      S = For->getBody();
+    } else {
+      assert(isa<CXXForRangeStmt>(SimplifiedS) &&
+             "Expected canonical for loop or range-based for loop.");
+      const auto *CXXFor = cast<CXXForRangeStmt>(SimplifiedS);
+      CGF.EmitStmt(CXXFor->getLoopVarStmt());
+      S = CXXFor->getBody();
+    }
+    if (Level + 1 < MaxLevel) {
+      NextLoop = OMPLoopDirective::tryToFindNextInnerLoop(
+          S, /*TryImperfectlyNestedLoops=*/true);
+      emitBody(CGF, S, NextLoop, MaxLevel, Level + 1);
+      return;
+    }
+  }
+  CGF.EmitStmt(S);
+}
+
 void CodeGenFunction::EmitOMPLoopBody(const OMPLoopDirective &D,
                                       JumpDest LoopExit) {
   RunCleanupsScope BodyScope(*this);
@@ -1371,20 +1408,12 @@ void CodeGenFunction::EmitOMPLoopBody(const OMPLoopDirective &D,
   // Emit loop variables for C++ range loops.
   const Stmt *Body =
       D.getInnermostCapturedStmt()->getCapturedStmt()->IgnoreContainers();
-  for (unsigned Cnt = 0; Cnt < D.getCollapsedNumber(); ++Cnt) {
-    Body = Body->IgnoreContainers();
-    if (auto *For = dyn_cast<ForStmt>(Body)) {
-      Body = For->getBody();
-    } else {
-      assert(isa<CXXForRangeStmt>(Body) &&
-             "Expected canonical for loop or range-based for loop.");
-      auto *CXXFor = cast<CXXForRangeStmt>(Body);
-      EmitStmt(CXXFor->getLoopVarStmt());
-      Body = CXXFor->getBody();
-    }
-  }
   // Emit loop body.
-  EmitStmt(D.getBody());
+  emitBody(*this, Body,
+           OMPLoopDirective::tryToFindNextInnerLoop(
+               Body, /*TryImperfectlyNestedLoops=*/true),
+           D.getCollapsedNumber());
+
   // The end (updates/cleanups).
   EmitBlock(Continue.getBlock());
   BreakContinueStack.pop_back();

diff  --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 595281a7c372..9055eff872a3 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -6979,7 +6979,8 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
              "Expected canonical for or range-based for loops.");
       CurStmt = cast<CXXForRangeStmt>(CurStmt)->getBody();
     }
-    CurStmt = CurStmt->IgnoreContainers();
+    CurStmt = OMPLoopDirective::tryToFindNextInnerLoop(
+        CurStmt, SemaRef.LangOpts.OpenMP >= 50);
   }
   for (unsigned Cnt = NestedLoopCount; Cnt < OrderedLoopCount; ++Cnt) {
     if (checkOpenMPIterationSpace(
@@ -7006,7 +7007,8 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
              "Expected canonical for or range-based for loops.");
       CurStmt = cast<CXXForRangeStmt>(CurStmt)->getBody();
     }
-    CurStmt = CurStmt->IgnoreContainers();
+    CurStmt = OMPLoopDirective::tryToFindNextInnerLoop(
+        CurStmt, SemaRef.LangOpts.OpenMP >= 50);
   }
 
   Built.clear(/* size */ NestedLoopCount);

diff  --git a/clang/test/OpenMP/for_ast_print.cpp b/clang/test/OpenMP/for_ast_print.cpp
index edb4b9a7ac0e..f5b98c88a812 100644
--- a/clang/test/OpenMP/for_ast_print.cpp
+++ b/clang/test/OpenMP/for_ast_print.cpp
@@ -114,22 +114,30 @@ T tmain(T argc) {
 // CHECK-NEXT: a = 2;
 #pragma omp parallel
 #pragma omp for allocate(argc) private(argc, b), firstprivate(c, d), lastprivate(d, f) collapse(N) schedule(static, N) ordered(N) nowait
-  for (auto &x : arr)
-  for (int i = 0; i < 2; ++i)
-    for (int j = 0; j < 2; ++j)
+  for (auto &x : arr) {
+    int j, hhh = 0;
+    for (int i = 0; i < 2; ++i) {
+      int j, hhh = 0;
       for (int j = 0; j < 2; ++j)
         for (int j = 0; j < 2; ++j)
           for (int j = 0; j < 2; ++j)
-  for (int i = 0; i < 2; ++i)
-    for (int j = 0; j < 2; ++j)
-      for (int j = 0; j < 2; ++j)
-        for (int j = 0; j < 2; ++j)
-          for (int j = 0; j < 2; ++j)
-            foo();
+            for (int j = 0; j < 2; ++j)
+              for (int i = 0; i < 2; ++i)
+                for (int j = 0; j < 2; ++j)
+                  for (int j = 0; j < 2; ++j)
+                    for (int j = 0; j < 2; ++j)
+                      for (int j = 0; j < 2; ++j)
+                        foo();
+      ++hhh;
+    }
+    ++hhh;
+  }
   // CHECK-NEXT: #pragma omp parallel
   // CHECK-NEXT: #pragma omp for allocate(argc) private(argc,b) firstprivate(c,d) lastprivate(d,f) collapse(N) schedule(static, N) ordered(N) nowait
-  // CHECK-NEXT: for (auto &x : arr)
-  // CHECK-NEXT: for (int i = 0; i < 2; ++i)
+  // CHECK-NEXT: for (auto &x : arr) {
+  // CHECK-NEXT: int j, hhh = 0;
+  // CHECK-NEXT: for (int i = 0; i < 2; ++i) {
+  // CHECK-NEXT: int j, hhh = 0;
   // CHECK-NEXT: for (int j = 0; j < 2; ++j)
   // CHECK-NEXT: for (int j = 0; j < 2; ++j)
   // CHECK-NEXT: for (int j = 0; j < 2; ++j)
@@ -140,6 +148,10 @@ T tmain(T argc) {
   // CHECK-NEXT: for (int j = 0; j < 2; ++j)
   // CHECK-NEXT: for (int j = 0; j < 2; ++j)
   // CHECK-NEXT: foo();
+  // CHECK-NEXT: ++hhh;
+  // CHECK-NEXT: }
+  // CHECK-NEXT: ++hhh;
+  // CHECK-NEXT: }
   return T();
 }
 

diff  --git a/clang/test/OpenMP/for_codegen.cpp b/clang/test/OpenMP/for_codegen.cpp
index 925235ef960e..a837a4a04d7b 100644
--- a/clang/test/OpenMP/for_codegen.cpp
+++ b/clang/test/OpenMP/for_codegen.cpp
@@ -732,4 +732,50 @@ T ftemplate() {
 
 int fint(void) { return ftemplate<int>(); }
 
+// Check for imperfectly loop nests codegen.
+#if _OPENMP == 201811
+void first();
+void last();
+void inner_f();
+void inner_l();
+void body_f();
+
+// OMP5-LABEL: imperfectly_nested_loop
+void imperfectly_nested_loop() {
+  // OMP5: call void @__kmpc_for_static_init_4(
+#pragma omp for collapse(3)
+  for (int i = 0; i < 10; ++i) {
+    {
+      int a, d;
+      // OMP5: invoke void @{{.+}}first{{.+}}()
+      first();
+      // OMP5: load i32
+      // OMP5: store i32
+      a = d;
+      for (int j = 0; j < 10; ++j) {
+        int a, d;
+        // OMP5: invoke void @{{.+}}inner_f{{.+}}()
+        inner_f();
+        // OMP5: load i32
+        // OMP5: store i32
+        a = d;
+        for (int k = 0; k < 10; ++k) {
+          int a, d;
+          // OMP5: invoke void @{{.+}}body_f{{.+}}()
+          body_f();
+          // OMP5: load i32
+          // OMP5: store i32
+          a = d;
+        }
+        // OMP5: invoke void @{{.+}}inner_l{{.+}}()
+        inner_l();
+      }
+      // OMP5: invoke void @{{.+}}last{{.+}}()
+      last();
+    }
+  }
+  // OMP5: call void @__kmpc_for_static_fini(
+}
+#endif
+
 #endif // HEADER

diff  --git a/clang/test/OpenMP/for_collapse_messages.cpp b/clang/test/OpenMP/for_collapse_messages.cpp
index ce656515b1ef..2316ca6ba3f0 100644
--- a/clang/test/OpenMP/for_collapse_messages.cpp
+++ b/clang/test/OpenMP/for_collapse_messages.cpp
@@ -1,10 +1,16 @@
-// RUN: %clang_cc1 -verify -fopenmp %s -Wuninitialized
-// RUN: %clang_cc1 -verify -fopenmp -std=c++98 %s -Wuninitialized
-// RUN: %clang_cc1 -verify -fopenmp -std=c++11 %s -Wuninitialized
+// RUN: %clang_cc1 -verify=expected,omp45 -fopenmp %s -Wuninitialized
+// RUN: %clang_cc1 -verify=expected,omp45 -fopenmp -std=c++98 %s -Wuninitialized
+// RUN: %clang_cc1 -verify=expected,omp45 -fopenmp -std=c++11 %s -Wuninitialized
+// RUN: %clang_cc1 -verify=expected,omp50 -fopenmp -fopenmp-version=50 %s -Wuninitialized
+// RUN: %clang_cc1 -verify=expected,omp50 -fopenmp -fopenmp-version=50 -std=c++98 %s -Wuninitialized
+// RUN: %clang_cc1 -verify=expected,omp50 -fopenmp -fopenmp-version=50 -std=c++11 %s -Wuninitialized
 
-// RUN: %clang_cc1 -verify -fopenmp-simd %s -Wuninitialized
-// RUN: %clang_cc1 -verify -fopenmp-simd -std=c++98 %s -Wuninitialized
-// RUN: %clang_cc1 -verify -fopenmp-simd -std=c++11 %s -Wuninitialized
+// RUN: %clang_cc1 -verify=expected,omp45 -fopenmp-simd %s -Wuninitialized
+// RUN: %clang_cc1 -verify=expected,omp45 -fopenmp-simd -std=c++98 %s -Wuninitialized
+// RUN: %clang_cc1 -verify=expected,omp45 -fopenmp-simd -std=c++11 %s -Wuninitialized
+// RUN: %clang_cc1 -verify=expected,omp50 -fopenmp-simd -fopenmp-version=50 %s -Wuninitialized
+// RUN: %clang_cc1 -verify=expected,omp50 -fopenmp-simd -fopenmp-version=50 -std=c++98 %s -Wuninitialized
+// RUN: %clang_cc1 -verify=expected,omp50 -fopenmp-simd -fopenmp-version=50 -std=c++11 %s -Wuninitialized
 
 void foo() {
 }
@@ -87,7 +93,7 @@ int main(int argc, char **argv) {
 #endif
   // expected-error at +2 2 {{directive '#pragma omp for' cannot contain more than one 'collapse' clause}}
   // expected-error at +1 {{argument to 'collapse' clause must be a strictly positive integer value}}
-  #pragma omp for collapse (foobool(argc)), collapse (true), collapse (-5) 
+  #pragma omp for collapse (foobool(argc)), collapse (true), collapse (-5)
   for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
   #pragma omp for collapse (S1) // expected-error {{'S1' does not refer to a value}}
   for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
@@ -108,3 +114,39 @@ int main(int argc, char **argv) {
   return tmain<int, char, 1, 0>(argc, argv);
 }
 
+void imperfectlyNestedLoops() {
+#pragma omp for collapse(2)      // expected-note {{as specified in 'collapse' clause}}
+  for (int i = 0; i < 10; ++i) { // expected-error {{expected 2 for loops after '#pragma omp for', but found only 1}}
+    for (int j = 0; j < 10; ++j)
+      ;
+    for (int j = 0; j < 10; ++j)
+      ;
+  }
+#pragma omp for collapse(2)      // expected-note {{as specified in 'collapse' clause}}
+  for (int i = 0; i < 10; ++i) { // expected-error {{expected 2 for loops after '#pragma omp for', but found only 1}}
+    {
+      for (int j = 0; j < 10; ++j)
+        ;
+      for (int j = 0; j < 10; ++j)
+        ;
+    }
+    {
+      for (int j = 0; j < 10; ++j)
+        ;
+      for (int j = 0; j < 10; ++j)
+        ;
+    }
+  }
+#pragma omp for collapse(2)      // omp45-note {{as specified in 'collapse' clause}}
+  for (int i = 0; i < 10; ++i) { // omp45-error {{expected 2 for loops after '#pragma omp for', but found only 1}}
+    int a, b, c;
+    for (int j = 0; j < 10; ++j)
+      ;
+    {
+      for (int j = 0; j < 10; ++j)
+        ;
+      for (int j = 0; j < 10; ++j)
+        ;
+    }
+  }
+}


        


More information about the cfe-commits mailing list