koops updated this revision to Diff 527127.
koops added a comment.

1. Addition of extra test case loop_bind_enclosed.cpp.
2. Changing of name from Map1D to MappedDirective
3. Printing "omp loop bind" instead of the mapped Directives (e.g. "omp simd") 
when -ast-print option is used.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D144634/new/

https://reviews.llvm.org/D144634

Files:
  clang/include/clang/AST/StmtOpenMP.h
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Sema/Sema.h
  clang/lib/AST/StmtPrinter.cpp
  clang/lib/Sema/SemaOpenMP.cpp
  clang/test/OpenMP/loop_bind_codegen.cpp
  clang/test/OpenMP/loop_bind_enclosed.cpp
  clang/test/OpenMP/loop_bind_messages.cpp
  clang/test/OpenMP/nested_loop_codegen.cpp

Index: clang/test/OpenMP/nested_loop_codegen.cpp
===================================================================
--- clang/test/OpenMP/nested_loop_codegen.cpp
+++ clang/test/OpenMP/nested_loop_codegen.cpp
@@ -58,6 +58,11 @@
 // CHECK1-NEXT:    [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
 // CHECK1-NEXT:    [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
 // CHECK1-NEXT:    [[I_ADDR:%.*]] = alloca ptr, align 8
+// CHECK1-NEXT:    [[DOTOMP_IV:%.*]] = alloca i32, align 4
+// CHECK1-NEXT:    [[DOTOMP_LB:%.*]] = alloca i32, align 4
+// CHECK1-NEXT:    [[DOTOMP_UB:%.*]] = alloca i32, align 4
+// CHECK1-NEXT:    [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
+// CHECK1-NEXT:    [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
 // CHECK1-NEXT:    [[K:%.*]] = alloca i32, align 4
 // CHECK1-NEXT:    store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
 // CHECK1-NEXT:    store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
@@ -71,6 +76,9 @@
 // CHECK1-NEXT:    br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_END7:%.*]]
 // CHECK1:       for.body:
 // CHECK1-NEXT:    store i32 0, ptr [[K]], align 4
+// CHECK:          [[TMP2:%.*]] = load ptr, ptr [[DOTGLOBSL_TID__ADDR]], align 8
+// CHECK1-NEXT:    [[TMP3:%.*]] = load i32, ptr [[TMP2]], align 4
+// CHECK1-NEXT:    call void @__kmpc_for_static_init_4(ptr @1, i32 [[TMP3]], i32 34, ptr %.omp.is_last, ptr %.omp.lb, ptr %.omp.ub, ptr %.omp.stride, i32 1, i32 1)
 // CHECK1-NEXT:    br label [[FOR_COND1:%.*]]
 // CHECK1:       for.cond1:
 // CHECK1-NEXT:    [[TMP2:%.*]] = load i32, ptr [[K]], align 4
Index: clang/test/OpenMP/loop_bind_messages.cpp
===================================================================
--- /dev/null
+++ clang/test/OpenMP/loop_bind_messages.cpp
@@ -0,0 +1,76 @@
+#ifndef HEADER
+#define HEADER
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=50 -verify %s
+
+#define NNN 50
+int aaa[NNN];
+
+void parallel_loop() {
+  #pragma omp parallel
+  {
+     #pragma omp loop
+     for (int j = 0 ; j < NNN ; j++) {
+       aaa[j] = j*NNN;
+     }
+   }
+}
+
+void teams_loop() {
+  int var1, var2;
+
+  #pragma omp teams
+  {
+     #pragma omp loop bind(teams)
+     for (int j = 0 ; j < NNN ; j++) {
+       aaa[j] = j*NNN;
+     }
+
+     #pragma omp loop bind(teams) collapse(2) private(var1)
+     for (int i = 0 ; i < 3 ; i++) {
+       for (int j = 0 ; j < NNN ; j++) {
+         var1 += aaa[j];
+       }
+     }
+   }
+}
+
+void orphan_loop_with_bind() {
+  #pragma omp loop bind(parallel) 
+  for (int j = 0 ; j < NNN ; j++) {
+    aaa[j] = j*NNN;
+  }
+}
+
+void orphan_loop_no_bind() {
+  #pragma omp loop  // expected-error{{expected 'bind' clause for loop construct without an enclosing OpenMP construct}}
+  for (int j = 0 ; j < NNN ; j++) {
+    aaa[j] = j*NNN;
+  }
+}
+
+void teams_loop_reduction() {
+  int total = 0;
+
+  #pragma omp teams
+  {
+     #pragma omp loop bind(teams)
+     for (int j = 0 ; j < NNN ; j++) {
+       aaa[j] = j*NNN;
+     }
+
+     #pragma omp loop bind(teams) reduction(+:total) // expected-error{{reduction clause not handled with '#pragma omp loop bind(teams)'}}
+     for (int j = 0 ; j < NNN ; j++) {
+       total+=aaa[j];
+     }
+   }
+}
+
+int main(int argc, char *argv[]) {
+  parallel_loop();
+  teams_loop();
+  orphan_loop_with_bind();
+  orphan_loop_no_bind();
+  teams_loop_reduction();
+}
+
+#endif
Index: clang/test/OpenMP/loop_bind_enclosed.cpp
===================================================================
--- /dev/null
+++ clang/test/OpenMP/loop_bind_enclosed.cpp
@@ -0,0 +1,140 @@
+// expected-no-diagnostics
+// RUN: %clang_cc1 -DCK1 -verify -fopenmp -x c++ %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple x86_64-unknown-unknown -emit-llvm %s -o - | FileCheck %s
+
+#define NNN 50
+int aaa[NNN];
+
+void parallel_taskgroup_loop() {
+  #pragma omp parallel
+  {
+    #pragma omp taskgroup
+    for (int i = 0 ; i < 2 ; i++) {
+      #pragma omp loop
+      for (int j = 0 ; j < NNN ; j++) {
+        aaa[j] = j*NNN;
+      }
+    }
+  }
+}
+// CHECK-LABEL: define {{[^@]+}}@_Z23parallel_taskgroup_loopv
+// CHECK-NEXT: entry:
+// CHECK-NEXT:     call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @1, i32 0, ptr @{{[_A-Za-z0-9]*}}.omp_outlined{{[.]*}})
+// CHECK-NEXT:     ret void
+// CHECK-LABEL: define {{[^@]+}}@{{[_A-Za-z0-9]*}}.omp_outlined
+// CHECK-NEXT: entry:
+// CHECK:          call void @__kmpc_taskgroup(ptr @1, i32 %1)
+// CHECK-LABEL: omp.inner.for.end:
+// CHECK-LABEL: for.end:
+// CHECK-NEXT:     call void @__kmpc_end_taskgroup(ptr @1, i32 %1)
+// CHECK-NEXT:     ret void
+
+void parallel_taskwait_loop() {
+  #pragma omp parallel
+  {
+    #pragma omp taskwait
+    for (int i = 0 ; i < 2 ; i++) {
+      #pragma omp loop
+      for (int j = 0 ; j < NNN ; j++) {
+        aaa[j] = j*NNN;
+      }
+    }
+  }
+}
+// CHECK-LABEL: define {{[^@]+}}@_Z22parallel_taskwait_loopv
+// CHECK-NEXT: entry:
+// CHECK-NEXT:     call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @1, i32 0, ptr @{{[_A-Za-z0-9]*}}.omp_outlined{{[.]*}})
+// CHECK-NEXT:     ret void
+// CHECK-LABEL: define {{[^@]+}}@{{[_A-Za-z0-9]*}}.omp_outlined
+// CHECK:          call i32 @__kmpc_omp_taskwait(ptr @1, i32 %1)
+// CHECK-LABEL: omp.loop.exit:
+// CHECK-NEXT:     call void @__kmpc_for_static_fini(ptr @2, i32 %1)
+// CHECK-NEXT:     call void @__kmpc_barrier(ptr @3, i32 %1)
+// CHECK-LABEL: for.end:
+// CHECK-NEXT:     ret void
+
+void parallel_single_loop() {
+  #pragma omp parallel
+  {
+    for (int i = 0 ; i < 2 ; i++) {
+      #pragma omp single
+      #pragma omp loop
+      for (int j = 0 ; j < NNN ; j++) {
+        aaa[j] = j*NNN;
+      }
+    }
+  }
+}
+// CHECK-LABEL: define {{[^@]+}}@_Z20parallel_single_loopv
+// CHECK-NEXT: entry:
+// CHECK-NEXT:     call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @1, i32 0, ptr @{{[_A-Za-z0-9]*}}.omp_outlined{{[.]*}})
+// CHECK-NEXT:     ret void
+// CHECK-LABEL: define {{[^@]+}}@{{[_A-Za-z0-9]*}}.omp_outlined
+// CHECK-NEXT: entry:
+// CHECK:          [[TMP:%.*]] = call i32 @__kmpc_single(ptr @1, i32 %2)
+// CHECK-LABEL: omp.inner.for.end:
+// CHECK:          call void @__kmpc_end_single(ptr @1, i32 %2)
+// CHECK-LABEL: for.end:
+// CHECK-NEXT:     ret void
+
+void parallel_order_loop() {
+  #pragma omp parallel
+  {
+    #pragma omp for order(concurrent)
+    {
+      for (int i = 0 ; i < 2 ; i++) {
+        #pragma omp loop
+        for (int j = 0 ; j < NNN ; j++) {
+          aaa[j] = j*NNN;
+        }
+      }
+    }
+  }
+}
+// CHECK-LABEL: define {{[^@]+}}@_Z19parallel_order_loopv
+// CHECK-NEXT: entry:
+// CHECK-NEXT:     call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @1, i32 0, ptr @{{[_A-Za-z0-9]*}}.omp_outlined{{[.]*}})
+// CHECK-NEXT:     ret void
+// CHECK-LABEL: define {{[^@]+}}@{{[_A-Za-z0-9]*}}.omp_outlined
+// CHECK-NEXT: entry:
+// CHECK:          call void @__kmpc_for_static_fini(ptr @2, i32 %1)
+// CHECK-NEXT:     call void @__kmpc_barrier(ptr @3, i32 %1)
+// CHECK-NEXT:     ret void
+
+
+void parallel_cancel_loop(bool flag) {
+  #pragma omp ordered
+  for (int i = 0 ; i < 2 ; i++) {
+    #pragma omp parallel
+    {
+      #pragma omp cancel parallel if(flag)
+      aaa[0] = 0;
+      #pragma omp loop bind(parallel)
+      for (int j = 0 ; j < NNN ; j++) {
+        aaa[j] = j*NNN;
+      }
+    }
+  }
+}
+// CHECK-LABEL: define {{[^@]+}}@_Z20parallel_cancel_loopb
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[FLAG_DOTADDR:%.*]] = alloca i8, align 1
+// CHECK-NEXT:    [[I:%.*]] = alloca i32, align 4
+// CHECK:         call void @__kmpc_ordered(ptr @1, i32 %0)
+// CHECK-LABEL: for.body:
+// CHECK-NEXT:    call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @1, i32 1, ptr @_Z20parallel_cancel_loopb.omp_outlined, ptr [[FLAG_DOTADDR]])
+// CHECK-LABEL: for.end:
+// CHECK-NEXT:    call void @__kmpc_end_ordered(ptr @1, i32 %0)
+// CHECK-NEXT:    ret void
+
+int
+main(int argc, char *argv[]) {
+  parallel_taskgroup_loop();
+  parallel_taskwait_loop();
+  parallel_single_loop();
+  parallel_order_loop();
+  parallel_cancel_loop(true);
+  parallel_cancel_loop(false);
+
+  return 0;
+}
Index: clang/test/OpenMP/loop_bind_codegen.cpp
===================================================================
--- /dev/null
+++ clang/test/OpenMP/loop_bind_codegen.cpp
@@ -0,0 +1,141 @@
+// expected-no-diagnostics
+// RUN: %clang_cc1 -DCK1 -verify -fopenmp -x c++ %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple x86_64-unknown-unknown -emit-llvm %s -o - | FileCheck %s
+
+
+#define NNN 50
+int aaa[NNN];
+
+void parallel_loop() {
+  #pragma omp parallel
+  {
+    #pragma omp loop bind(parallel)
+    for (int j = 0 ; j < NNN ; j++) {
+      aaa[j] = j*NNN;
+    }
+  }
+}
+
+void parallel_loop_orphan() {
+  #pragma omp loop bind(parallel)
+  for (int j = 0 ; j < NNN ; j++) {
+     aaa[j] = j*NNN;
+  }
+}
+
+
+void teams_loop() {
+  #pragma omp teams
+  {
+     #pragma omp loop bind(teams)
+     for (int j = 0 ; j < NNN ; j++) {
+       aaa[j] = j*NNN;
+     }
+   }
+}
+
+void thread_loop() {
+  #pragma omp parallel
+  {
+     #pragma omp loop bind(thread)
+     for (int j = 0 ; j < NNN ; j++) {
+       aaa[j] = j*NNN;
+     }
+   }
+}
+
+void thread_loop_orphan() {
+  #pragma omp loop bind(thread)
+  for (int j = 0 ; j < NNN ; j++) {
+    aaa[j] = j*NNN;
+  }
+}
+
+int main() {
+  parallel_loop();
+  parallel_loop_orphan();
+  teams_loop();
+  thread_loop();
+  thread_loop_orphan();
+
+  return 0;
+}
+// CHECK-LABEL: define {{[^@]+}}@_Z13parallel_loopv
+// CHECK-NEXT: entry:
+// CHECK-NEXT:     call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @3, i32 0, ptr @{{[_A-Za-z0-9]*}}.omp_outlined{{[.]*}})
+// CHECK-LABEL: define {{[^@]+}}@{{[_A-Za-z0-9]*}}.omp_outlined
+// CHECK-NEXT: entry:
+// CHECK-NEXT:    [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
+// CHECK-NEXT:    [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
+// CHECK-NEXT:    [[DOTOMP_IV:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[TMP:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[DOTOMP_LB:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[DOTOMP_UB:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[J:%.*]] = alloca i32, align 4
+// CHECK:       call void @__kmpc_for_static_init_4(ptr @1, i32 %1, i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
+// CHECK-LABEL: cond.true:
+// CHECK-NEXT:    br label [[COND_END:%.*]]
+// CHECK-LABEL: cond.false:
+// CHECK-NEXT:    [[TMP11:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
+// CHECK-NEXT:    br label [[COND_END]]
+// CHECK:       omp.inner.for.cond:
+// CHECK-NEXT:    [[TMP13:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK:       omp.inner.for.body:
+// CHECK:       omp.loop.exit:
+// CHECK-NEXT:    call void @__kmpc_for_static_fini(ptr @1, i32 %1)
+// CHECK-NEXT:    call void @__kmpc_barrier(ptr @2, i32 %1)
+// CHECK-NEXT:    ret void
+//
+// CHECK-LABEL: define {{[^@]+}}@_Z20parallel_loop_orphanv
+// CHECK-NEXT: entry:
+// CHECK-NEXT:    [[DOTOMP_IV:%.*]] = alloca i32, align 4
+// CHECK:       call void @__kmpc_for_static_init_4(ptr @1, i32 %0, i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
+// CHECK-LABEL: cond.true:
+// CHECK:       omp.inner.for.cond:
+// CHECK:       omp.loop.exit:
+//
+// CHECK-LABEL: define {{[^@]+}}@_Z10teams_loopv
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:     call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @3, i32 0, ptr @{{[_A-Za-z0-9]*}}.omp_outlined{{[.1]*}})
+// CHECK-NEXT:     ret void
+//
+// CHECK-LABEL: define {{[^@]+}}@{{[_A-Za-z0-9]*}}.omp_outlined
+// CHECK-NEXT: entry:
+// CHECK-NEXT:    [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
+// CHECK-NEXT:    [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
+// CHECK-NEXT:    [[DOTOMP_IV:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[TMP:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[DOTOMP_LB:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[DOTOMP_UB:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[J:%.*]] = alloca i32, align 4
+// CHECK:       call void @__kmpc_for_static_init_4(ptr @4, i32 %1, i32 92, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
+// CHECK-LABEL: cond.true:
+// CHECK-NEXT:    br label [[COND_END:%.*]]
+// CHECK-LABEL: cond.false:
+// CHECK-NEXT:    [[TMP11:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
+// CHECK-NEXT:    br label [[COND_END]]
+// CHECK:       omp.inner.for.cond:
+// CHECK-NEXT:    [[TMP13:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK:       omp.inner.for.body:
+// CHECK:       omp.loop.exit:
+// CHECK-NEXT:    call void @__kmpc_for_static_fini(ptr @4, i32 %1)
+// CHECK-NEXT:    ret void
+//
+// CHECK-LABEL: define {{[^@]+}}@_Z11thread_loopv
+// CHECK-NEXT: entry:
+// CHECK-NEXT:     call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @3, i32 0, ptr @{{[_A-Za-z0-9]*}}.omp_outlined{{[.2]*}})
+// CHECK-LABEL: define {{[^@]+}}@{{[_A-Za-z0-9]*}}.omp_outlined
+// CHECK:       omp.inner.for.cond:
+//
+// CHECK-LABEL: define {{[^@]+}}@_Z18thread_loop_orphanv
+// CHECK-NEXT: entry:
+// CHECK-NEXT:    [[TMP:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[DOTOMP_IV:%.*]] = alloca i32, align 4
+// CHECK:       omp.inner.for.cond:
+// CHECK-NEXT:    [[TMP13:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+//
+// CHECK-LABEL: @main{{.*}}
Index: clang/lib/Sema/SemaOpenMP.cpp
===================================================================
--- clang/lib/Sema/SemaOpenMP.cpp
+++ clang/lib/Sema/SemaOpenMP.cpp
@@ -337,6 +337,11 @@
   /// Vector of declare variant construct traits.
   SmallVector<llvm::omp::TraitProperty, 8> ConstructTraits;
 
+  /// GenericLoopDirective with bind clause is mapped to other directives,
+  /// like for, distribute and simd. Presently, set MappedDirective to OMPLoop.
+  /// This may also be used in a similar way for other constructs.
+  OpenMPDirectiveKind MappedDirective = OMPD_unknown;
+
 public:
   explicit DSAStackTy(Sema &S) : SemaRef(S) {}
 
@@ -636,6 +641,17 @@
     const SharingMapTy *Top = getTopOfStackOrNull();
     return Top ? Top->Directive : OMPD_unknown;
   }
+  OpenMPDirectiveKind getMappedDirective() const { return MappedDirective; }
+  void setCurrentDirective(OpenMPDirectiveKind NewDK) {
+    SharingMapTy *Top = (SharingMapTy *)getTopOfStackOrNull();
+    assert(Top != NULL &&
+           "Before calling setCurrentDirective Top of Stack not to be NULL.");
+    // Store the old into MappedDirective & assign argument NewDK to Directive.
+    Top->Directive = NewDK;
+  }
+  void setMappedDirective(OpenMPDirectiveKind NewDK) {
+    MappedDirective = NewDK;
+  }
   /// Returns directive kind at specified level.
   OpenMPDirectiveKind getDirective(unsigned Level) const {
     assert(!isStackEmpty() && "No directive at specified level.");
@@ -6121,10 +6137,78 @@
                             isOpenMPTargetDataManagementDirective(Kind)))
     Diag(StartLoc, diag::warn_hip_omp_target_directives);
 
+  llvm::SmallVector<OMPClause *, 8> ClausesWithoutBind;
+  bool UseClausesWithoutBind = false;
+
+  // Restricting to "#pragma omp loop bind"
+  if (Kind == OMPD_loop) {
+    if (BindKind == OMPC_BIND_unknown) {
+      // Setting the enclosing teams or parallel construct for the loop
+      // directive without bind clause.
+      BindKind = OMPC_BIND_thread; // Default bind(thread) if binding is unknown
+
+      const OpenMPDirectiveKind ParentDirective =
+          DSAStack->getParentDirective();
+      if (ParentDirective == OMPD_unknown) {
+        Diag(DSAStack->getDefaultDSALocation(),
+             diag::err_omp_bind_required_on_loop);
+      } else if (ParentDirective == OMPD_parallel ||
+                 ParentDirective == OMPD_target_parallel) {
+        BindKind = OMPC_BIND_parallel;
+      } else if (ParentDirective == OMPD_teams ||
+                 ParentDirective == OMPD_target_teams) {
+        BindKind = OMPC_BIND_teams;
+      }
+    } else {
+      // bind clause is present, so we should set flag indicating to only
+      // use the clauses that aren't the bind clause for the new directive that
+      // loop is lowered to.
+      UseClausesWithoutBind = true;
+    }
+
+    for (OMPClause *C : Clauses) {
+      // Spec restriction : bind(teams) and reduction not permitted.
+      if (BindKind == OMPC_BIND_teams &&
+          C->getClauseKind() == llvm::omp::Clause::OMPC_reduction)
+        Diag(DSAStack->getDefaultDSALocation(),
+             diag::err_omp_loop_reduction_clause);
+
+      // A new Vector ClausesWithoutBind, which does not contain the bind
+      // clause, for passing to new directive.
+      if (C->getClauseKind() != llvm::omp::Clause::OMPC_bind)
+        ClausesWithoutBind.push_back(C);
+    }
+
+    switch (BindKind) {
+    case OMPC_BIND_parallel:
+      Kind = OMPD_for;
+      DSAStack->setCurrentDirective(OMPD_for);
+      DSAStack->setMappedDirective(OMPD_loop);
+      break;
+    case OMPC_BIND_teams:
+      Kind = OMPD_distribute;
+      DSAStack->setCurrentDirective(OMPD_distribute);
+      DSAStack->setMappedDirective(OMPD_loop);
+      break;
+    case OMPC_BIND_thread:
+      Kind = OMPD_simd;
+      DSAStack->setCurrentDirective(OMPD_simd);
+      DSAStack->setMappedDirective(OMPD_loop);
+      break;
+    case OMPC_BIND_unknown:
+      break;
+    }
+  }
+
   llvm::SmallVector<OMPClause *, 8> ClausesWithImplicit;
   VarsWithInheritedDSAType VarsWithInheritedDSA;
   bool ErrorFound = false;
-  ClausesWithImplicit.append(Clauses.begin(), Clauses.end());
+  if (UseClausesWithoutBind) {
+    ClausesWithImplicit.append(ClausesWithoutBind.begin(),
+                               ClausesWithoutBind.end());
+  } else {
+    ClausesWithImplicit.append(Clauses.begin(), Clauses.end());
+  }
   if (AStmt && !CurContext->isDependentContext() && Kind != OMPD_atomic &&
       Kind != OMPD_critical && Kind != OMPD_section && Kind != OMPD_master &&
       Kind != OMPD_masked && !isOpenMPLoopTransformationDirective(Kind)) {
@@ -9201,9 +9285,12 @@
   auto *CXXFor = dyn_cast_or_null<CXXForRangeStmt>(S);
   // Ranged for is supported only in OpenMP 5.0.
   if (!For && (SemaRef.LangOpts.OpenMP <= 45 || !CXXFor)) {
+    OpenMPDirectiveKind DK = (DSA.getMappedDirective() == OMPD_unknown)
+                                 ? DKind
+                                 : DSA.getMappedDirective();
     SemaRef.Diag(S->getBeginLoc(), diag::err_omp_not_for)
         << (CollapseLoopCountExpr != nullptr || OrderedLoopCountExpr != nullptr)
-        << getOpenMPDirectiveName(DKind) << TotalNestedLoopCount
+        << getOpenMPDirectiveName(DK) << TotalNestedLoopCount
         << (CurrentNestedLoopCount > 0) << CurrentNestedLoopCount;
     if (TotalNestedLoopCount > 1) {
       if (CollapseLoopCountExpr && OrderedLoopCountExpr)
@@ -10287,6 +10374,10 @@
   return false;
 }
 
+static bool checkGenericLoopLastprivate(Sema &S, ArrayRef<OMPClause *> Clauses,
+                                        OpenMPDirectiveKind K,
+                                        DSAStackTy *Stack);
+
 StmtResult
 Sema::ActOnOpenMPSimdDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt,
                                SourceLocation StartLoc, SourceLocation EndLoc,
@@ -10294,6 +10385,9 @@
   if (!AStmt)
     return StmtError();
 
+  if (!CheckLastPrivateForMappedDirectives(Clauses))
+    return StmtError();
+
   assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
   OMPLoopBasedDirective::HelperExprs B;
   // In presence of clause 'collapse' or 'ordered' with number of loops, it will
@@ -10322,8 +10416,10 @@
     return StmtError();
 
   setFunctionHasBranchProtectedScope();
-  return OMPSimdDirective::Create(Context, StartLoc, EndLoc, NestedLoopCount,
-                                  Clauses, AStmt, B);
+  OMPSimdDirective *tmp = OMPSimdDirective::Create(
+      Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B);
+  tmp->setMappedDirective(DSAStack->getMappedDirective());
+  return tmp;
 }
 
 StmtResult
@@ -10334,6 +10430,10 @@
     return StmtError();
 
   assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
+
+  if (!CheckLastPrivateForMappedDirectives(Clauses))
+    return StmtError();
+
   OMPLoopBasedDirective::HelperExprs B;
   // In presence of clause 'collapse' or 'ordered' with number of loops, it will
   // define the nested loops number.
@@ -10358,9 +10458,11 @@
   }
 
   setFunctionHasBranchProtectedScope();
-  return OMPForDirective::Create(
+  OMPForDirective *tmp = OMPForDirective::Create(
       Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B,
       DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion());
+  tmp->setMappedDirective(DSAStack->getMappedDirective());
+  return tmp;
 }
 
 StmtResult Sema::ActOnOpenMPForSimdDirective(
@@ -10369,6 +10471,12 @@
   if (!AStmt)
     return StmtError();
 
+  /* Check for syntax of lastprivate */
+  if (DSAStack->getMappedDirective() == OMPD_loop) {
+    if (checkGenericLoopLastprivate(*this, Clauses, OMPD_loop, DSAStack))
+      return StmtError();
+  }
+
   assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
   OMPLoopBasedDirective::HelperExprs B;
   // In presence of clause 'collapse' or 'ordered' with number of loops, it will
@@ -13880,12 +13988,31 @@
       Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B);
 }
 
+bool Sema::CheckLastPrivateForMappedDirectives(ArrayRef<OMPClause *> Clauses) {
+
+  /* Check for syntax of lastprivate */
+  if (DSAStack->getMappedDirective() == OMPD_loop) {
+    if (checkGenericLoopLastprivate(*this, Clauses, OMPD_loop, DSAStack))
+      return false;
+  }
+  return true;
+}
+
 StmtResult Sema::ActOnOpenMPDistributeDirective(
     ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
     SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
   if (!AStmt)
     return StmtError();
 
+  if (!CheckLastPrivateForMappedDirectives(Clauses))
+    return StmtError();
+
+  /* Check for syntax of lastprivate */
+  if (DSAStack->getMappedDirective() == OMPD_loop) {
+    if (checkGenericLoopLastprivate(*this, Clauses, OMPD_loop, DSAStack))
+      return StmtError();
+  }
+
   assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
   OMPLoopBasedDirective::HelperExprs B;
   // In presence of clause 'collapse' with number of loops, it will
@@ -13901,8 +14028,10 @@
          "omp for loop exprs were not built");
 
   setFunctionHasBranchProtectedScope();
-  return OMPDistributeDirective::Create(Context, StartLoc, EndLoc,
-                                        NestedLoopCount, Clauses, AStmt, B);
+  OMPDistributeDirective *tmp = OMPDistributeDirective::Create(
+      Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B);
+  tmp->setMappedDirective(DSAStack->getMappedDirective());
+  return tmp;
 }
 
 StmtResult Sema::ActOnOpenMPDistributeParallelForDirective(
Index: clang/lib/AST/StmtPrinter.cpp
===================================================================
--- clang/lib/AST/StmtPrinter.cpp
+++ clang/lib/AST/StmtPrinter.cpp
@@ -741,7 +741,12 @@
 }
 
 void StmtPrinter::VisitOMPSimdDirective(OMPSimdDirective *Node) {
-  Indent() << "#pragma omp simd";
+  OpenMPDirectiveKind MappedDirective = Node->getMappedDirective();
+  if (MappedDirective != llvm::omp::OMPD_unknown &&
+      MappedDirective == llvm::omp::OMPD_loop) {
+    Indent() << "#pragma omp loop bind(thread)";
+  } else
+    Indent() << "#pragma omp simd";
   PrintOMPExecutableDirective(Node);
 }
 
@@ -756,7 +761,12 @@
 }
 
 void StmtPrinter::VisitOMPForDirective(OMPForDirective *Node) {
-  Indent() << "#pragma omp for";
+  OpenMPDirectiveKind MappedDirective = Node->getMappedDirective();
+  if (MappedDirective != llvm::omp::OMPD_unknown &&
+      MappedDirective == llvm::omp::OMPD_loop) {
+    Indent() << "#pragma omp loop bind(parallel)";
+  } else
+    Indent() << "#pragma omp for";
   PrintOMPExecutableDirective(Node);
 }
 
@@ -991,7 +1001,12 @@
 }
 
 void StmtPrinter::VisitOMPDistributeDirective(OMPDistributeDirective *Node) {
-  Indent() << "#pragma omp distribute";
+  OpenMPDirectiveKind MappedDirective = Node->getMappedDirective();
+  if (MappedDirective != llvm::omp::OMPD_unknown &&
+      MappedDirective == llvm::omp::OMPD_loop) {
+    Indent() << "#pragma omp loop bind(teams)";
+  } else
+    Indent() << "#pragma omp distribute";
   PrintOMPExecutableDirective(Node);
 }
 
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -11080,6 +11080,8 @@
   /// All `omp assumes` we encountered so far.
   SmallVector<AssumptionAttr *, 4> OMPAssumeGlobal;
 
+  bool CheckLastPrivateForMappedDirectives(ArrayRef<OMPClause *> Clauses);
+
 public:
   /// The declarator \p D defines a function in the scope \p S which is nested
   /// in an `omp begin/end declare variant` scope. In this method we create a
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -9813,6 +9813,11 @@
 def warn_loop_ctrl_binds_to_inner : Warning<
   "'%0' is bound to current loop, GCC binds it to the enclosing loop">,
   InGroup<GccCompat>;
+def err_omp_bind_required_on_loop : Error<
+  "expected 'bind' clause for loop construct without an enclosing OpenMP "
+  "construct">;
+def err_omp_loop_reduction_clause : Error<
+  "reduction clause not handled with '#pragma omp loop bind(teams)'">;
 def warn_break_binds_to_switch : Warning<
   "'break' is bound to loop, GCC binds it to switch">,
   InGroup<GccCompat>;
Index: clang/include/clang/AST/StmtOpenMP.h
===================================================================
--- clang/include/clang/AST/StmtOpenMP.h
+++ clang/include/clang/AST/StmtOpenMP.h
@@ -1126,6 +1126,9 @@
     return llvm::MutableArrayRef(Storage, getLoopsNumber());
   }
 
+  // This is copied over from Sema::DSAStackTy
+  OpenMPDirectiveKind MappedDirective = llvm::omp::OMPD_unknown;
+
 protected:
   /// Build instance of loop directive of class \a Kind.
   ///
@@ -1556,6 +1559,12 @@
            T->getStmtClass() == OMPTargetTeamsDistributeDirectiveClass ||
            T->getStmtClass() == OMPTargetTeamsDistributeSimdDirectiveClass;
   }
+
+  // The following two are copied over from Sema::DSAStackTy for -ast-print
+  void setMappedDirective(OpenMPDirectiveKind NewDK) {
+    MappedDirective = NewDK;
+  }
+  OpenMPDirectiveKind getMappedDirective() const { return MappedDirective; }
 };
 
 /// This represents '#pragma omp simd' directive.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to