[flang] [OpenMP] Predetermined rules for loop index variables (flang-compiler/f18...
authorJinxin (Brian) Yang <jinxiny@nvidia.com>
Wed, 5 Feb 2020 18:13:43 +0000 (10:13 -0800)
committerGitHub <noreply@github.com>
Wed, 5 Feb 2020 18:13:43 +0000 (10:13 -0800)
This refers to three rules in OpenMP 4.5 Spec 2.15.1.1:
  * The loop iteration variable(s) in the associated do-loop(s) of a do,
    parallel do, taskloop, or distribute construct is (are) private.
  * The loop iteration variable in the associated do-loop of a simd
    construct with just one associated do-loop is linear with a linear-step
    that is the increment of the associated do-loop.
  * The loop iteration variables in the associated do-loops of a simd
    construct with multiple associated do-loops are lastprivate.

A simple example:
```
implicit none
  integer :: N = 1024
  integer i, j, k
  !$omp parallel do collapse(3)
  do i=1, N  <- i is private
     do j=1, N  <- j is private
        do k=1, N  <- k is private
        enddo
     enddo
  enddo
end
```

If `collapse` clause is not present, the associated do-loop for construct
`parallel do` is only `i` loop. With `collapse(n)`, `i`, `j`, and `k` are
all associated do-loops and the loop index variables are private to the
OpenMP construct:

```
implicit none
 !DEF: /MainProgram1/n ObjectEntity INTEGER(4)
 integer :: n = 1024
 !DEF: /MainProgram1/i ObjectEntity INTEGER(4)
 !DEF: /MainProgram1/j ObjectEntity INTEGER(4)
 !DEF: /MainProgram1/k ObjectEntity INTEGER(4)
 integer i, j, k
!$omp parallel do  collapse(3)
 !DEF: /MainProgram1/Block1/i (OmpPrivate) HostAssoc INTEGER(4)
 !REF: /MainProgram1/n
 do i=1,n
  !DEF: /MainProgram1/Block1/j (OmpPrivate) HostAssoc INTEGER(4)
  !REF: /MainProgram1/n
  do j=1,n
   !DEF: /MainProgram1/Block1/k (OmpPrivate) HostAssoc INTEGER(4)
   !REF: /MainProgram1/n
   do k=1,n
   end do
  end do
 end do
end program
```

This implementation assumes that the structural checks for do-loops
are done at this point, for example the `n` in `collapse(n)` should
be no more than the number of actual perfectly nested do-loops, etc..

Original-commit: flang-compiler/f18@572a57d3d0d785bb3f2aad9e890ef498c1214309
Reviewed-on: https://github.com/flang-compiler/f18/pull/962

flang/lib/semantics/check-omp-structure.cpp
flang/lib/semantics/check-omp-structure.h
flang/lib/semantics/resolve-names.cpp
flang/test/semantics/CMakeLists.txt
flang/test/semantics/omp-clause-validity01.f90
flang/test/semantics/omp-device-constructs.f90
flang/test/semantics/omp-symbol01.f90
flang/test/semantics/omp-symbol04.f90
flang/test/semantics/omp-symbol06.f90
flang/test/semantics/omp-symbol08.f90 [new file with mode: 0644]

index 8d22d42..c8493c0 100644 (file)
 
 namespace Fortran::semantics {
 
-static constexpr OmpDirectiveSet parallelSet{
-    OmpDirective::DISTRIBUTE_PARALLEL_DO,
-    OmpDirective::DISTRIBUTE_PARALLEL_DO_SIMD, OmpDirective::PARALLEL,
-    OmpDirective::PARALLEL_DO, OmpDirective::PARALLEL_DO_SIMD,
-    OmpDirective::PARALLEL_SECTIONS, OmpDirective::PARALLEL_WORKSHARE,
-    OmpDirective::TARGET_PARALLEL, OmpDirective::TARGET_PARALLEL_DO,
-    OmpDirective::TARGET_PARALLEL_DO_SIMD,
-    OmpDirective::TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO,
-    OmpDirective::TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD,
-    OmpDirective::TEAMS_DISTRIBUTE_PARALLEL_DO,
-    OmpDirective::TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD};
-static constexpr OmpDirectiveSet doSet{OmpDirective::DISTRIBUTE_PARALLEL_DO,
-    OmpDirective::DISTRIBUTE_PARALLEL_DO_SIMD, OmpDirective::PARALLEL_DO,
-    OmpDirective::PARALLEL_DO_SIMD, OmpDirective::DO, OmpDirective::DO_SIMD,
-    OmpDirective::TARGET_PARALLEL_DO, OmpDirective::TARGET_PARALLEL_DO_SIMD,
-    OmpDirective::TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO,
-    OmpDirective::TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD,
-    OmpDirective::TEAMS_DISTRIBUTE_PARALLEL_DO,
-    OmpDirective::TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD};
-static constexpr OmpDirectiveSet simdSet{
-    OmpDirective::DISTRIBUTE_PARALLEL_DO_SIMD, OmpDirective::DISTRIBUTE_SIMD,
-    OmpDirective::PARALLEL_DO_SIMD, OmpDirective::DO_SIMD, OmpDirective::SIMD,
-    OmpDirective::TARGET_PARALLEL_DO_SIMD,
-    OmpDirective::TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD,
-    OmpDirective::TARGET_TEAMS_DISTRIBUTE_SIMD, OmpDirective::TARGET_SIMD,
-    OmpDirective::TASKLOOP_SIMD,
-    OmpDirective::TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD,
-    OmpDirective::TEAMS_DISTRIBUTE_SIMD};
-static constexpr OmpDirectiveSet doSimdSet{
-    OmpDirective::DISTRIBUTE_PARALLEL_DO_SIMD, OmpDirective::PARALLEL_DO_SIMD,
-    OmpDirective::DO_SIMD, OmpDirective::TARGET_PARALLEL_DO_SIMD,
-    OmpDirective::TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD,
-    OmpDirective::TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD};
-static constexpr OmpDirectiveSet taskloopSet{
-    OmpDirective::TASKLOOP, OmpDirective::TASKLOOP_SIMD};
-static constexpr OmpDirectiveSet targetSet{OmpDirective::TARGET,
-    OmpDirective::TARGET_PARALLEL, OmpDirective::TARGET_PARALLEL_DO,
-    OmpDirective::TARGET_PARALLEL_DO_SIMD, OmpDirective::TARGET_SIMD,
-    OmpDirective::TARGET_TEAMS, OmpDirective::TARGET_TEAMS_DISTRIBUTE,
-    OmpDirective::TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO,
-    OmpDirective::TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD,
-    OmpDirective::TARGET_TEAMS_DISTRIBUTE_SIMD};
-
 std::string OmpStructureChecker::ContextDirectiveAsFortran() {
   auto dir{EnumToString(GetContext().directive)};
   std::replace(dir.begin(), dir.end(), '_', ' ');
index cfe4a2f..b20c325 100644 (file)
@@ -46,6 +46,49 @@ ENUM_CLASS(OmpClause, ALIGNED, COLLAPSE, COPYIN, COPYPRIVATE, DEFAULT,
 
 using OmpClauseSet = common::EnumSet<OmpClause, OmpClause_enumSize>;
 
+static constexpr OmpDirectiveSet parallelSet{
+    OmpDirective::DISTRIBUTE_PARALLEL_DO,
+    OmpDirective::DISTRIBUTE_PARALLEL_DO_SIMD, OmpDirective::PARALLEL,
+    OmpDirective::PARALLEL_DO, OmpDirective::PARALLEL_DO_SIMD,
+    OmpDirective::PARALLEL_SECTIONS, OmpDirective::PARALLEL_WORKSHARE,
+    OmpDirective::TARGET_PARALLEL, OmpDirective::TARGET_PARALLEL_DO,
+    OmpDirective::TARGET_PARALLEL_DO_SIMD,
+    OmpDirective::TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO,
+    OmpDirective::TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD,
+    OmpDirective::TEAMS_DISTRIBUTE_PARALLEL_DO,
+    OmpDirective::TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD};
+static constexpr OmpDirectiveSet doSet{OmpDirective::DISTRIBUTE_PARALLEL_DO,
+    OmpDirective::DISTRIBUTE_PARALLEL_DO_SIMD, OmpDirective::PARALLEL_DO,
+    OmpDirective::PARALLEL_DO_SIMD, OmpDirective::DO, OmpDirective::DO_SIMD,
+    OmpDirective::TARGET_PARALLEL_DO, OmpDirective::TARGET_PARALLEL_DO_SIMD,
+    OmpDirective::TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO,
+    OmpDirective::TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD,
+    OmpDirective::TEAMS_DISTRIBUTE_PARALLEL_DO,
+    OmpDirective::TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD};
+static constexpr OmpDirectiveSet doSimdSet{
+    OmpDirective::DISTRIBUTE_PARALLEL_DO_SIMD, OmpDirective::PARALLEL_DO_SIMD,
+    OmpDirective::DO_SIMD, OmpDirective::TARGET_PARALLEL_DO_SIMD,
+    OmpDirective::TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD,
+    OmpDirective::TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD};
+static constexpr OmpDirectiveSet taskloopSet{
+    OmpDirective::TASKLOOP, OmpDirective::TASKLOOP_SIMD};
+static constexpr OmpDirectiveSet targetSet{OmpDirective::TARGET,
+    OmpDirective::TARGET_PARALLEL, OmpDirective::TARGET_PARALLEL_DO,
+    OmpDirective::TARGET_PARALLEL_DO_SIMD, OmpDirective::TARGET_SIMD,
+    OmpDirective::TARGET_TEAMS, OmpDirective::TARGET_TEAMS_DISTRIBUTE,
+    OmpDirective::TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO,
+    OmpDirective::TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD,
+    OmpDirective::TARGET_TEAMS_DISTRIBUTE_SIMD};
+static constexpr OmpDirectiveSet simdSet{
+    OmpDirective::DISTRIBUTE_PARALLEL_DO_SIMD, OmpDirective::DISTRIBUTE_SIMD,
+    OmpDirective::PARALLEL_DO_SIMD, OmpDirective::DO_SIMD, OmpDirective::SIMD,
+    OmpDirective::TARGET_PARALLEL_DO_SIMD,
+    OmpDirective::TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD,
+    OmpDirective::TARGET_TEAMS_DISTRIBUTE_SIMD, OmpDirective::TARGET_SIMD,
+    OmpDirective::TASKLOOP_SIMD,
+    OmpDirective::TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD,
+    OmpDirective::TEAMS_DISTRIBUTE_SIMD};
+
 class OmpStructureChecker : public virtual BaseChecker {
 public:
   OmpStructureChecker(SemanticsContext &context) : context_{context} {}
index 5ab1424..a7b76d6 100644 (file)
@@ -1148,6 +1148,11 @@ public:
   template<typename A> bool Pre(const A &) { return true; }
   template<typename A> void Post(const A &) {}
 
+  bool Pre(const parser::SpecificationPart &x) {
+    Walk(std::get<std::list<parser::OpenMPDeclarativeConstruct>>(x.t));
+    return false;
+  }
+
   bool Pre(const parser::OpenMPBlockConstruct &);
   void Post(const parser::OpenMPBlockConstruct &) { PopContext(); }
   void Post(const parser::OmpBeginBlockDirective &) {
@@ -1199,6 +1204,7 @@ private:
     // variables on Data-sharing attribute clauses
     std::map<const Symbol *, Symbol::Flag> objectWithDSA;
     bool withinConstruct{false};
+    std::size_t associatedLoopLevel{0};
   };
   // back() is the top of the stack
   OmpContext &GetContext() {
@@ -1226,6 +1232,10 @@ private:
     auto it{GetContext().objectWithDSA.find(&symbol)};
     return it != GetContext().objectWithDSA.end();
   }
+  void SetContextAssociatedLoopLevel(std::size_t level) {
+    GetContext().associatedLoopLevel = level;
+  }
+  std::size_t GetAssociatedLoopLevelFromClauses(const parser::OmpClauseList &);
 
   Symbol &MakeAssocSymbol(const SourceName &name, Symbol &prev) {
     const auto pair{
@@ -1260,6 +1270,11 @@ private:
   }
   bool HasDataSharingAttributeObject(const Symbol &);
 
+  const parser::DoConstruct *GetDoConstructIf(
+      const parser::ExecutionPartConstruct &);
+  // Predetermined DSA rules
+  void PrivatizeAssociatedLoopIndex(const parser::OpenMPLoopConstruct &);
+
   void ResolveOmpObjectList(const parser::OmpObjectList &, Symbol::Flag);
   void ResolveOmpObject(const parser::OmpObject &, Symbol::Flag);
   Symbol *ResolveOmp(const parser::Name &, Symbol::Flag);
@@ -5935,10 +5950,20 @@ bool OmpAttributeVisitor::Pre(const parser::OpenMPBlockConstruct &x) {
 bool OmpAttributeVisitor::Pre(const parser::OpenMPLoopConstruct &x) {
   const auto &beginLoopDir{std::get<parser::OmpBeginLoopDirective>(x.t)};
   const auto &beginDir{std::get<parser::OmpLoopDirective>(beginLoopDir.t)};
+  const auto &clauseList{std::get<parser::OmpClauseList>(beginLoopDir.t)};
   switch (beginDir.v) {
   case parser::OmpLoopDirective::Directive::Distribute:
     PushContext(beginDir.source, OmpDirective::DISTRIBUTE);
     break;
+  case parser::OmpLoopDirective::Directive::DistributeParallelDo:
+    PushContext(beginDir.source, OmpDirective::DISTRIBUTE_PARALLEL_DO);
+    break;
+  case parser::OmpLoopDirective::Directive::DistributeParallelDoSimd:
+    PushContext(beginDir.source, OmpDirective::DISTRIBUTE_PARALLEL_DO_SIMD);
+    break;
+  case parser::OmpLoopDirective::Directive::DistributeSimd:
+    PushContext(beginDir.source, OmpDirective::DISTRIBUTE_SIMD);
+    break;
   case parser::OmpLoopDirective::Directive::Do:
     PushContext(beginDir.source, OmpDirective::DO);
     break;
@@ -5954,20 +5979,136 @@ bool OmpAttributeVisitor::Pre(const parser::OpenMPLoopConstruct &x) {
   case parser::OmpLoopDirective::Directive::Simd:
     PushContext(beginDir.source, OmpDirective::SIMD);
     break;
+  case parser::OmpLoopDirective::Directive::TargetParallelDo:
+    PushContext(beginDir.source, OmpDirective::TARGET_PARALLEL_DO);
+    break;
+  case parser::OmpLoopDirective::Directive::TargetParallelDoSimd:
+    PushContext(beginDir.source, OmpDirective::TARGET_PARALLEL_DO_SIMD);
+    break;
+  case parser::OmpLoopDirective::Directive::TargetTeamsDistribute:
+    PushContext(beginDir.source, OmpDirective::TARGET_TEAMS_DISTRIBUTE);
+    break;
+  case parser::OmpLoopDirective::Directive::TargetTeamsDistributeParallelDo:
+    PushContext(
+        beginDir.source, OmpDirective::TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO);
+    break;
+  case parser::OmpLoopDirective::Directive::TargetTeamsDistributeParallelDoSimd:
+    PushContext(beginDir.source,
+        OmpDirective::TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD);
+    break;
+  case parser::OmpLoopDirective::Directive::TargetTeamsDistributeSimd:
+    PushContext(beginDir.source, OmpDirective::TARGET_TEAMS_DISTRIBUTE_SIMD);
+    break;
+  case parser::OmpLoopDirective::Directive::TargetSimd:
+    PushContext(beginDir.source, OmpDirective::TARGET_SIMD);
+    break;
   case parser::OmpLoopDirective::Directive::Taskloop:
     PushContext(beginDir.source, OmpDirective::TASKLOOP);
     break;
   case parser::OmpLoopDirective::Directive::TaskloopSimd:
     PushContext(beginDir.source, OmpDirective::TASKLOOP_SIMD);
     break;
-  default:
-    // TODO others
+  case parser::OmpLoopDirective::Directive::TeamsDistribute:
+    PushContext(beginDir.source, OmpDirective::TEAMS_DISTRIBUTE);
+    break;
+  case parser::OmpLoopDirective::Directive::TeamsDistributeParallelDo:
+    PushContext(beginDir.source, OmpDirective::TEAMS_DISTRIBUTE_PARALLEL_DO);
+    break;
+  case parser::OmpLoopDirective::Directive::TeamsDistributeParallelDoSimd:
+    PushContext(
+        beginDir.source, OmpDirective::TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD);
+    break;
+  case parser::OmpLoopDirective::Directive::TeamsDistributeSimd:
+    PushContext(beginDir.source, OmpDirective::TEAMS_DISTRIBUTE_SIMD);
     break;
   }
   ClearDataSharingAttributeObjects();
+  SetContextAssociatedLoopLevel(GetAssociatedLoopLevelFromClauses(clauseList));
+  PrivatizeAssociatedLoopIndex(x);
   return true;
 }
 
+const parser::DoConstruct *OmpAttributeVisitor::GetDoConstructIf(
+    const parser::ExecutionPartConstruct &x) {
+  if (auto *y{std::get_if<parser::ExecutableConstruct>(&x.u)}) {
+    if (auto *z{std::get_if<Indirection<parser::DoConstruct>>(&y->u)}) {
+      return &z->value();
+    }
+  }
+  return nullptr;
+}
+
+std::size_t OmpAttributeVisitor::GetAssociatedLoopLevelFromClauses(
+    const parser::OmpClauseList &x) {
+  std::size_t orderedLevel{0};
+  std::size_t collapseLevel{0};
+  for (const auto &clause : x.v) {
+    if (const auto *orderedClause{
+            std::get_if<parser::OmpClause::Ordered>(&clause.u)}) {
+      if (const auto v{
+              evaluate::ToInt64(resolver_.EvaluateIntExpr(orderedClause->v))}) {
+        orderedLevel = *v;
+      }
+    }
+    if (const auto *collapseClause{
+            std::get_if<parser::OmpClause::Collapse>(&clause.u)}) {
+      if (const auto v{evaluate::ToInt64(
+              resolver_.EvaluateIntExpr(collapseClause->v))}) {
+        collapseLevel = *v;
+      }
+    }
+  }
+
+  if (orderedLevel && (!collapseLevel || orderedLevel >= collapseLevel)) {
+    return orderedLevel;
+  } else if (!orderedLevel && collapseLevel) {
+    return collapseLevel;
+  }  // orderedLevel < collapseLevel is an error handled in structural checks
+  return 1;  // default is outermost loop
+}
+
+// 2.15.1.1 Data-sharing Attribute Rules - Predetermined
+//   - The loop iteration variable(s) in the associated do-loop(s) of a do,
+//     parallel do, taskloop, or distribute construct is (are) private.
+//   - The loop iteration variable in the associated do-loop of a simd construct
+//     with just one associated do-loop is linear with a linear-step that is the
+//     increment of the associated do-loop.
+//   - The loop iteration variables in the associated do-loops of a simd
+//     construct with multiple associated do-loops are lastprivate.
+//
+// TODO: This assumes that the do-loops association for collapse/ordered
+//       clause has been performed (the number of nested do-loops >= n).
+void OmpAttributeVisitor::PrivatizeAssociatedLoopIndex(
+    const parser::OpenMPLoopConstruct &x) {
+  std::size_t level{GetContext().associatedLoopLevel};
+  Symbol::Flag ivDSA{Symbol::Flag::OmpPrivate};
+  if (simdSet.test(GetContext().directive)) {
+    if (level == 1) {
+      ivDSA = Symbol::Flag::OmpLinear;
+    } else {
+      ivDSA = Symbol::Flag::OmpLastPrivate;
+    }
+  }
+
+  auto &outer{std::get<std::optional<parser::DoConstruct>>(x.t)};
+  for (const parser::DoConstruct *loop{&*outer}; loop && level > 0; --level) {
+    // go through all the nested do-loops and resolve index variables
+    auto &loopControl{loop->GetLoopControl().value()};
+    using Bounds = parser::LoopControl::Bounds;
+    const Bounds &bounds{std::get<Bounds>(loopControl.u)};
+    const parser::Name &iv{bounds.name.thing};
+    if (auto *symbol{ResolveOmp(iv, ivDSA)}) {
+      iv.symbol = symbol;  // adjust the symbol within region
+      AddToContextObjectWithDSA(*symbol, ivDSA);
+    }
+
+    const auto &block{std::get<parser::Block>(loop->t)};
+    const auto it{block.begin()};
+    loop = it != block.end() ? GetDoConstructIf(*it) : nullptr;
+  }
+  CHECK(level == 0);
+}
+
 bool OmpAttributeVisitor::Pre(const parser::OpenMPSectionsConstruct &x) {
   const auto &beginSectionsDir{
       std::get<parser::OmpBeginSectionsDirective>(x.t)};
index 5dfbcb2..2dd1198 100644 (file)
@@ -229,6 +229,7 @@ set(SYMBOL_TESTS
   omp-symbol05.f90
   omp-symbol06.f90
   omp-symbol07.f90
+  omp-symbol08.f90
   kinds01.f90
   kinds03.f90
   procinterface01.f90
index 08abc1f..d624564 100644 (file)
@@ -43,7 +43,9 @@
   !ERROR: COLLAPSE clause is not allowed on the PARALLEL directive
   !$omp parallel collapse(2)
   do i = 1, N
-     a = 3.14
+     do j = 1, N
+        a = 3.14
+     enddo
   enddo
   !$omp end parallel
 
   enddo
 
   !ERROR: The parameter of the ORDERED clause must be greater than or equal to the parameter of the COLLAPSE clause
-  !$omp do collapse(num) ordered(1+2+3+4)
+  !$omp do collapse(num-14) ordered(1)
   do i = 1, N
      do j = 1, N
         do k = 1, N
   !ERROR: NOGROUP clause is not allowed on the DO SIMD directive
   !$omp do simd ordered(2) NOGROUP
   do i = 1, N
-     a = 3.14
+     do j = 1, N
+        a = 3.14
+     enddo
   enddo
   !$omp end parallel
 
index 118e49c..e87cb11 100644 (file)
@@ -149,7 +149,11 @@ program main
   !ERROR: At most one COLLAPSE clause can appear on the DISTRIBUTE directive
   !$omp distribute collapse(2) collapse(3)
   do i = 1, N
-     a = 3.14
+     do j = 1, N
+        do k = 1, N
+           a = 3.14
+        enddo
+     enddo
   enddo
   !$omp end distribute
   !$omp end target
index 2286bcc..eca8855 100644 (file)
@@ -45,21 +45,21 @@ program mm
  !DEF: /mm/c (Implicit) ObjectEntity REAL(4)
  c = 2.0
 !$omp parallel do  private(a,t,/c/) shared(c)
- !DEF: /mm/i (Implicit) ObjectEntity INTEGER(4)
+ !DEF: /mm/Block1/i (OmpPrivate) HostAssoc INTEGER(4)
  do i=1,10
   !DEF: /mm/Block1/a (OmpPrivate) HostAssoc REAL(4)
   !REF: /mm/b
-  !REF: /mm/i
+  !REF: /mm/Block1/i
   a = a+b(i)
   !DEF: /mm/Block1/t (OmpPrivate) HostAssoc TYPE(myty)
   !REF: /md/myty/a
-  !REF: /mm/i
+  !REF: /mm/Block1/i
   t%a = i
   !DEF: /mm/Block1/y (OmpPrivate) HostAssoc REAL(4)
   y = 0.
   !DEF: /mm/Block1/x (OmpPrivate) HostAssoc REAL(4)
   !REF: /mm/Block1/a
-  !REF: /mm/i
+  !REF: /mm/Block1/i
   !REF: /mm/Block1/y
   x = a+i+y
   !REF: /mm/c
index d97768d..9daacfb 100644 (file)
@@ -12,7 +12,7 @@
   !DEF: /MainProgram1/Block1/a (OmpPrivate) HostAssoc REAL(8)
   a = 2.
   !$omp do  private(a)
-  !DEF: /MainProgram1/i (Implicit) ObjectEntity INTEGER(4)
+  !DEF: /MainProgram1/Block1/Block1/i (OmpPrivate) HostAssoc INTEGER(4)
   do i=1,10
      !DEF: /MainProgram1/Block1/Block1/a (OmpPrivate) HostAssoc REAL(8)
      a = 1.
index d343d08..3b82fc8 100644 (file)
@@ -8,7 +8,7 @@
   !DEF: /MainProgram1/a (Implicit) ObjectEntity REAL(4)
   a = 1.
   !$omp parallel do  firstprivate(a) lastprivate(a)
-  !DEF: /MainProgram1/i (Implicit) ObjectEntity INTEGER(4)
+  !DEF: /MainProgram1/Block1/i (OmpPrivate) HostAssoc INTEGER(4)
   do i=1,10
      !DEF: /MainProgram1/Block1/a (OmpFirstPrivate, OmpLastPrivate) HostAssoc REAL(4)
      a = 2.
diff --git a/flang/test/semantics/omp-symbol08.f90 b/flang/test/semantics/omp-symbol08.f90
new file mode 100644 (file)
index 0000000..eaf8ff2
--- /dev/null
@@ -0,0 +1,209 @@
+!OPTIONS: -fopenmp
+
+! 2.15.1.1 Predetermined rules for associated do-loops index variable
+!   a) The loop iteration variable(s) in the associated do-loop(s) of a do,
+!      parallel do, taskloop, or distribute construct is (are) private.
+!   b) The loop iteration variable in the associated do-loop of a simd construct
+!      with just one associated do-loop is linear with a linear-step that is the
+!      increment of the associated do-loop.
+!   c) The loop iteration variables in the associated do-loops of a simd
+!      construct with multiple associated do-loops are lastprivate.
+!   - TBD
+
+! All the tests assume that the do-loops association for collapse/ordered
+! clause has been performed (the number of nested do-loops >= n).
+
+! Rule a)
+! TODO: nested constructs (k should be private too)
+!DEF: /test_do (Subroutine) Subprogram
+subroutine test_do
+ implicit none
+ !DEF: /test_do/a ObjectEntity REAL(4)
+ real a(20,20,20)
+ !DEF: /test_do/i ObjectEntity INTEGER(4)
+ !DEF: /test_do/j ObjectEntity INTEGER(4)
+ !DEF: /test_do/k ObjectEntity INTEGER(4)
+ integer i, j, k
+!$omp parallel
+ !REF: /test_do/i
+ i = 99
+!$omp do  collapse(2)
+ !DEF: /test_do/Block1/Block1/i (OmpPrivate) HostAssoc INTEGER(4)
+ do i=1,5
+  !DEF: /test_do/Block1/Block1/j (OmpPrivate) HostAssoc INTEGER(4)
+  do j=6,10
+   !REF: /test_do/a
+   a(1,1,1) = 0.
+   !REF: /test_do/k
+   do k=11,15
+    !REF: /test_do/a
+    !REF: /test_do/k
+    !REF: /test_do/Block1/Block1/j
+    !REF: /test_do/Block1/Block1/i
+    a(k,j,i) = 1.
+   end do
+  end do
+ end do
+!$omp end parallel
+end subroutine test_do
+
+! Rule a)
+!DEF: /test_pardo (Subroutine) Subprogram
+subroutine test_pardo
+ implicit none
+ !DEF: /test_pardo/a ObjectEntity REAL(4)
+ real a(20,20,20)
+ !DEF: /test_pardo/i ObjectEntity INTEGER(4)
+ !DEF: /test_pardo/j ObjectEntity INTEGER(4)
+ !DEF: /test_pardo/k ObjectEntity INTEGER(4)
+ integer i, j, k
+!$omp parallel do  collapse(2) private(k) ordered(2)
+ !DEF: /test_pardo/Block1/i (OmpPrivate) HostAssoc INTEGER(4)
+ do i=1,5
+  !DEF: /test_pardo/Block1/j (OmpPrivate) HostAssoc INTEGER(4)
+  do j=6,10
+   !REF: /test_pardo/a
+   a(1,1,1) = 0.
+   !DEF: /test_pardo/Block1/k (OmpPrivate) HostAssoc INTEGER(4)
+   do k=11,15
+    !REF: /test_pardo/a
+    !REF: /test_pardo/Block1/k
+    !REF: /test_pardo/Block1/j
+    !REF: /test_pardo/Block1/i
+    a(k,j,i) = 1.
+   end do
+  end do
+ end do
+end subroutine test_pardo
+
+! Rule a)
+!DEF: /test_taskloop (Subroutine) Subprogram
+subroutine test_taskloop
+ implicit none
+ !DEF: /test_taskloop/a ObjectEntity REAL(4)
+ real a(5,5)
+ !DEF: /test_taskloop/i ObjectEntity INTEGER(4)
+ !DEF: /test_taskloop/j ObjectEntity INTEGER(4)
+ integer i, j
+!$omp taskloop  private(j)
+ !DEF: /test_taskloop/Block1/i (OmpPrivate) HostAssoc INTEGER(4)
+ do i=1,5
+  !DEF: /test_taskloop/Block1/j (OmpPrivate) HostAssoc INTEGER(4)
+  !REF: /test_taskloop/Block1/i
+  do j=1,i
+   !REF: /test_taskloop/a
+   !REF: /test_taskloop/Block1/j
+   !REF: /test_taskloop/Block1/i
+   a(j,i) = 3.14
+  end do
+ end do
+!$omp end taskloop
+end subroutine test_taskloop
+
+! Rule a); OpenMP 4.5 Examples teams.2.f90
+! TODO: reduction; data-mapping attributes
+!DEF: /dotprod (Subroutine) Subprogram
+!DEF: /dotprod/b ObjectEntity REAL(4)
+!DEF: /dotprod/c ObjectEntity REAL(4)
+!DEF: /dotprod/n ObjectEntity INTEGER(4)
+!DEF: /dotprod/block_size ObjectEntity INTEGER(4)
+!DEF: /dotprod/num_teams ObjectEntity INTEGER(4)
+!DEF: /dotprod/block_threads ObjectEntity INTEGER(4)
+subroutine dotprod (b, c, n, block_size, num_teams, block_threads)
+ implicit none
+ !REF: /dotprod/n
+ integer n
+ !REF: /dotprod/b
+ !REF: /dotprod/n
+ !REF: /dotprod/c
+ !DEF: /dotprod/sum ObjectEntity REAL(4)
+ real b(n), c(n), sum
+ !REF: /dotprod/block_size
+ !REF: /dotprod/num_teams
+ !REF: /dotprod/block_threads
+ !DEF: /dotprod/i ObjectEntity INTEGER(4)
+ !DEF: /dotprod/i0 ObjectEntity INTEGER(4)
+ integer block_size, num_teams, block_threads, i, i0
+ !REF: /dotprod/sum
+ sum = 0.0e0
+!$omp target  map(to:b,c)  map(tofrom:sum)
+!$omp teams  num_teams(num_teams) thread_limit(block_threads) reduction(+:sum)
+!$omp distribute
+ !DEF: /dotprod/Block1/Block1/Block1/i0 (OmpPrivate) HostAssoc INTEGER(4)
+ !REF: /dotprod/n
+ !REF: /dotprod/block_size
+ do i0=1,n,block_size
+!$omp parallel do  reduction(+:sum)
+  !DEF: /dotprod/Block1/Block1/Block1/Block1/i (OmpPrivate) HostAssoc INTEGER(4)
+  !REF: /dotprod/i0
+  !DEF: /dotprod/min INTRINSIC (Function) ProcEntity
+  !REF: /dotprod/block_size
+  !REF: /dotprod/n
+  do i=i0,min(i0+block_size, n)
+   !REF: /dotprod/sum
+   !REF: /dotprod/b
+   !REF: /dotprod/Block1/Block1/Block1/Block1/i
+   !REF: /dotprod/c
+   sum = sum+b(i)*c(i)
+  end do
+ end do
+!$omp end teams
+!$omp end target
+ !REF: /dotprod/sum
+ print *, sum
+end subroutine dotprod
+
+! Rule b)
+! TODO: nested constructs (j, k should be private too)
+!DEF: /test_simd (Subroutine) Subprogram
+subroutine test_simd
+ implicit none
+ !DEF: /test_simd/a ObjectEntity REAL(4)
+ real a(20,20,20)
+ !DEF: /test_simd/i ObjectEntity INTEGER(4)
+ !DEF: /test_simd/j ObjectEntity INTEGER(4)
+ !DEF: /test_simd/k ObjectEntity INTEGER(4)
+ integer i, j, k
+!$omp parallel do simd
+ !DEF: /test_simd/Block1/i (OmpLinear) HostAssoc INTEGER(4)
+ do i=1,5
+  !REF: /test_simd/j
+  do j=6,10
+   !REF: /test_simd/k
+   do k=11,15
+    !REF: /test_simd/a
+    !REF: /test_simd/k
+    !REF: /test_simd/j
+    !REF: /test_simd/Block1/i
+    a(k,j,i) = 3.14
+   end do
+  end do
+ end do
+end subroutine test_simd
+
+! Rule c)
+!DEF: /test_simd_multi (Subroutine) Subprogram
+subroutine test_simd_multi
+ implicit none
+ !DEF: /test_simd_multi/a ObjectEntity REAL(4)
+ real a(20,20,20)
+ !DEF: /test_simd_multi/i ObjectEntity INTEGER(4)
+ !DEF: /test_simd_multi/j ObjectEntity INTEGER(4)
+ !DEF: /test_simd_multi/k ObjectEntity INTEGER(4)
+ integer i, j, k
+!$omp parallel do simd  collapse(3)
+ !DEF: /test_simd_multi/Block1/i (OmpLastPrivate) HostAssoc INTEGER(4)
+ do i=1,5
+  !DEF: /test_simd_multi/Block1/j (OmpLastPrivate) HostAssoc INTEGER(4)
+  do j=6,10
+   !DEF: /test_simd_multi/Block1/k (OmpLastPrivate) HostAssoc INTEGER(4)
+   do k=11,15
+    !REF: /test_simd_multi/a
+    !REF: /test_simd_multi/Block1/k
+    !REF: /test_simd_multi/Block1/j
+    !REF: /test_simd_multi/Block1/i
+    a(k,j,i) = 3.14
+   end do
+  end do
+ end do
+end subroutine test_simd_multi