[flang-commits] [flang] da5e966 - [Flang][OpenMP][Lower] Support PFT to MLIR lowering of loop-attached target constructs

Sergio Afonso via flang-commits flang-commits at lists.llvm.org
Tue Aug 15 04:56:54 PDT 2023


Author: Sergio Afonso
Date: 2023-08-15T12:56:35+01:00
New Revision: da5e96694d3c39f947f1b3d7957c8bbbf1f91383

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

LOG: [Flang][OpenMP][Lower] Support PFT to MLIR lowering of loop-attached target constructs

This patch adds support for lowering target-related combined constructs from
PFT to MLIR. The lowering of OpenMP loop constructs is generalized in
preparation for later supporting different combinations of target, teams,
distribute, parallel and simd directives.

Currently enabled by this patch are the following combined constructs:
- do simd
- parallel do simd
- target parallel do simd
- target parallel do
- target simd

Depends on D155981 and D157090.

Differential Revision: https://reviews.llvm.org/D156455

Added: 
    flang/test/Lower/OpenMP/if-clause.f90
    flang/test/Lower/OpenMP/loop-combined.f90

Modified: 
    flang/include/flang/Semantics/openmp-directive-sets.h
    flang/lib/Lower/OpenMP.cpp
    flang/test/Lower/OpenMP/target.f90

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Semantics/openmp-directive-sets.h b/flang/include/flang/Semantics/openmp-directive-sets.h
index 29bec4994a3d5b..a4f27b00152e26 100644
--- a/flang/include/flang/Semantics/openmp-directive-sets.h
+++ b/flang/include/flang/Semantics/openmp-directive-sets.h
@@ -181,6 +181,49 @@ static const OmpDirectiveSet nonPartialVarSet{
     Directive::OMPD_declare_target,
 };
 
+static const OmpDirectiveSet loopConstructSet{
+    Directive::OMPD_distribute_parallel_do_simd,
+    Directive::OMPD_distribute_parallel_do,
+    Directive::OMPD_distribute_simd,
+    Directive::OMPD_distribute,
+    Directive::OMPD_do_simd,
+    Directive::OMPD_do,
+    Directive::OMPD_parallel_do_simd,
+    Directive::OMPD_parallel_do,
+    Directive::OMPD_simd,
+    Directive::OMPD_target_parallel_do_simd,
+    Directive::OMPD_target_parallel_do,
+    Directive::OMPD_target_simd,
+    Directive::OMPD_target_teams_distribute_parallel_do_simd,
+    Directive::OMPD_target_teams_distribute_parallel_do,
+    Directive::OMPD_target_teams_distribute_simd,
+    Directive::OMPD_target_teams_distribute,
+    Directive::OMPD_taskloop_simd,
+    Directive::OMPD_taskloop,
+    Directive::OMPD_teams_distribute_parallel_do_simd,
+    Directive::OMPD_teams_distribute_parallel_do,
+    Directive::OMPD_teams_distribute_simd,
+    Directive::OMPD_teams_distribute,
+    Directive::OMPD_tile,
+    Directive::OMPD_unroll,
+};
+
+static const OmpDirectiveSet blockConstructSet{
+    Directive::OMPD_master,
+    Directive::OMPD_ordered,
+    Directive::OMPD_parallel_workshare,
+    Directive::OMPD_parallel,
+    Directive::OMPD_single,
+    Directive::OMPD_target_data,
+    Directive::OMPD_target_parallel,
+    Directive::OMPD_target_teams,
+    Directive::OMPD_target,
+    Directive::OMPD_task,
+    Directive::OMPD_taskgroup,
+    Directive::OMPD_teams,
+    Directive::OMPD_workshare,
+};
+
 //===----------------------------------------------------------------------===//
 // Directive sets for allowed/not allowed nested directives
 //===----------------------------------------------------------------------===//

diff  --git a/flang/lib/Lower/OpenMP.cpp b/flang/lib/Lower/OpenMP.cpp
index c2bdd3ec8bd604..a3323e8105b6fd 100644
--- a/flang/lib/Lower/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP.cpp
@@ -22,6 +22,7 @@
 #include "flang/Optimizer/Builder/Todo.h"
 #include "flang/Optimizer/HLFIR/HLFIROps.h"
 #include "flang/Parser/parse-tree.h"
+#include "flang/Semantics/openmp-directive-sets.h"
 #include "flang/Semantics/tools.h"
 #include "mlir/Dialect/OpenMP/OpenMPDialect.h"
 #include "llvm/Frontend/OpenMP/OMPConstants.h"
@@ -2315,6 +2316,49 @@ createCombinedParallelOp(Fortran::lower::AbstractConverter &converter,
                                         /*isCombined=*/true);
 }
 
+/* When target is used in a combined construct, then use this function to
+ * create the target operation. It handles the target specific clauses
+ * and leaves the rest for handling at the inner operations.
+ */
+template <typename Directive>
+static void createCombinedTargetOp(Fortran::lower::AbstractConverter &converter,
+                                   Fortran::lower::pft::Evaluation &eval,
+                                   const Directive &directive) {
+  fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
+  mlir::Location currentLocation = converter.getCurrentLocation();
+  Fortran::lower::StatementContext stmtCtx;
+  mlir::Value ifClauseOperand, deviceOperand, threadLimitOperand;
+  llvm::SmallVector<mlir::Value> mapOperands;
+  llvm::SmallVector<mlir::IntegerAttr> mapTypes;
+  mlir::UnitAttr nowaitAttr;
+  const auto &opClauseList =
+      std::get<Fortran::parser::OmpClauseList>(directive.t);
+
+  // Note: rest of the clauses are handled when the inner operation is created
+  ClauseProcessor cp(converter, opClauseList);
+  cp.processIf(stmtCtx,
+               Fortran::parser::OmpIfClause::DirectiveNameModifier::Target,
+               ifClauseOperand);
+  cp.processDevice(stmtCtx, deviceOperand);
+  cp.processThreadLimit(stmtCtx, threadLimitOperand);
+  cp.processNowait(nowaitAttr);
+  cp.processMap(mapOperands, mapTypes);
+
+  llvm::SmallVector<mlir::Attribute> mapTypesAttr(mapTypes.begin(),
+                                                  mapTypes.end());
+  mlir::ArrayAttr mapTypesArrayAttr =
+      mlir::ArrayAttr::get(firOpBuilder.getContext(), mapTypesAttr);
+
+  // Create and insert the operation.
+  auto targetOp = firOpBuilder.create<mlir::omp::TargetOp>(
+      currentLocation, ifClauseOperand, deviceOperand, threadLimitOperand,
+      nowaitAttr, mapOperands, mapTypesArrayAttr);
+
+  createBodyOfOp<mlir::omp::TargetOp>(targetOp, converter, currentLocation,
+                                      eval, &opClauseList,
+                                      /*iv=*/{}, /*isCombined=*/true);
+}
+
 static void genOMP(Fortran::lower::AbstractConverter &converter,
                    Fortran::lower::pft::Evaluation &eval,
                    const Fortran::parser::OpenMPLoopConstruct &loopConstruct) {
@@ -2342,13 +2386,41 @@ static void genOMP(Fortran::lower::AbstractConverter &converter,
   const auto ompDirective =
       std::get<Fortran::parser::OmpLoopDirective>(beginLoopDirective.t).v;
 
-  if (llvm::omp::OMPD_parallel_do == ompDirective) {
-    createCombinedParallelOp<Fortran::parser::OmpBeginLoopDirective>(
-        converter, eval,
-        std::get<Fortran::parser::OmpBeginLoopDirective>(loopConstruct.t));
-  } else if (llvm::omp::OMPD_do != ompDirective &&
-             llvm::omp::OMPD_simd != ompDirective) {
-    TODO(currentLocation, "Construct enclosing do loop");
+  bool validDirective = false;
+  if (llvm::omp::topTaskloopSet.test(ompDirective)) {
+    validDirective = true;
+    TODO(currentLocation, "Taskloop construct");
+  } else {
+    // Create omp.{target, teams, distribute, parallel} nested operations
+    if ((llvm::omp::allTargetSet & llvm::omp::loopConstructSet)
+            .test(ompDirective)) {
+      validDirective = true;
+      createCombinedTargetOp<Fortran::parser::OmpBeginLoopDirective>(
+          converter, eval, beginLoopDirective);
+    }
+    if ((llvm::omp::allTeamsSet & llvm::omp::loopConstructSet)
+            .test(ompDirective)) {
+      validDirective = true;
+      TODO(currentLocation, "Teams construct");
+    }
+    if (llvm::omp::allDistributeSet.test(ompDirective)) {
+      validDirective = true;
+      TODO(currentLocation, "Distribute construct");
+    }
+    if ((llvm::omp::allParallelSet & llvm::omp::loopConstructSet)
+            .test(ompDirective)) {
+      validDirective = true;
+      createCombinedParallelOp<Fortran::parser::OmpBeginLoopDirective>(
+          converter, eval, beginLoopDirective);
+    }
+  }
+  if ((llvm::omp::allDoSet | llvm::omp::allSimdSet).test(ompDirective))
+    validDirective = true;
+
+  if (!validDirective) {
+    TODO(currentLocation, "Unhandled loop directive (" +
+                              llvm::omp::getOpenMPDirectiveName(ompDirective) +
+                              ")");
   }
 
   DataSharingProcessor dsp(converter, loopOpClauseList, eval);
@@ -2379,7 +2451,7 @@ static void genOMP(Fortran::lower::AbstractConverter &converter,
 
   // 2.9.3.1 SIMD construct
   // TODO: Support all the clauses
-  if (llvm::omp::OMPD_simd == ompDirective) {
+  if (llvm::omp::allSimdSet.test(ompDirective)) {
     mlir::TypeRange resultType;
     auto simdLoopOp = firOpBuilder.create<mlir::omp::SimdLoopOp>(
         currentLocation, resultType, lowerBound, upperBound, step, alignedVars,

diff  --git a/flang/test/Lower/OpenMP/if-clause.f90 b/flang/test/Lower/OpenMP/if-clause.f90
new file mode 100644
index 00000000000000..9b8b5b7b439387
--- /dev/null
+++ b/flang/test/Lower/OpenMP/if-clause.f90
@@ -0,0 +1,437 @@
+! This test checks lowering of OpenMP IF clauses.
+
+! RUN: bbc -fopenmp -emit-fir %s -o - | FileCheck %s
+! RUN: %flang_fc1 -fopenmp -emit-fir %s -o - | FileCheck %s
+
+program main
+  integer :: i
+
+  ! TODO When they are supported, add tests for:
+  ! - DISTRIBUTE PARALLEL DO
+  ! - DISTRIBUTE PARALLEL DO SIMD
+  ! - DISTRIBUTE SIMD
+  ! - PARALLEL SECTIONS
+  ! - PARALLEL WORKSHARE
+  ! - TARGET PARALLEL
+  ! - TARGET TEAMS
+  ! - TARGET TEAMS DISTRIBUTE
+  ! - TARGET TEAMS DISTRIBUTE PARALLEL DO
+  ! - TARGET TEAMS DISTRIBUTE PARALLEL DO SIMD
+  ! - TARGET TEAMS DISTRIBUTE SIMD
+  ! - TARGET UPDATE
+  ! - TASKLOOP
+  ! - TASKLOOP SIMD
+  ! - TEAMS
+  ! - TEAMS DISTRIBUTE
+  ! - TEAMS DISTRIBUTE PARALLEL DO
+  ! - TEAMS DISTRIBUTE PARALLEL DO SIMD
+  ! - TEAMS DISTRIBUTE SIMD
+
+  ! ----------------------------------------------------------------------------
+  ! DO SIMD
+  ! ----------------------------------------------------------------------------
+  ! CHECK:      omp.simdloop
+  ! CHECK-NOT:  if({{.*}})
+  ! CHECK-SAME: {
+  !$omp do simd
+  do i = 1, 10
+  end do
+  !$omp end do simd
+
+  ! CHECK:      omp.simdloop
+  ! CHECK-SAME: if({{.*}})
+  !$omp do simd if(.true.)
+  do i = 1, 10
+  end do
+  !$omp end do simd
+
+  ! CHECK:      omp.simdloop
+  ! CHECK-SAME: if({{.*}})
+  !$omp do simd if(simd: .true.)
+  do i = 1, 10
+  end do
+  !$omp end do simd
+
+  ! ----------------------------------------------------------------------------
+  ! PARALLEL
+  ! ----------------------------------------------------------------------------
+  ! CHECK:      omp.parallel
+  ! CHECK-NOT:  if({{.*}})
+  ! CHECK-SAME: {
+  !$omp parallel
+  i = 10
+  !$omp end parallel
+
+  ! CHECK:      omp.parallel
+  ! CHECK-SAME: if({{.*}})
+  !$omp parallel if(.true.)
+  i = 10
+  !$omp end parallel
+
+  ! CHECK:      omp.parallel
+  ! CHECK-SAME: if({{.*}})
+  !$omp parallel if(parallel: .true.)
+  i = 10
+  !$omp end parallel
+
+  ! ----------------------------------------------------------------------------
+  ! PARALLEL DO
+  ! ----------------------------------------------------------------------------
+  ! CHECK:      omp.parallel
+  ! CHECK-NOT:  if({{.*}})
+  ! CHECK-SAME: {
+  !$omp parallel do
+  do i = 1, 10
+  end do
+  !$omp end parallel do
+
+  ! CHECK:      omp.parallel
+  ! CHECK-SAME: if({{.*}})
+  !$omp parallel do if(.true.)
+  do i = 1, 10
+  end do
+  !$omp end parallel do
+
+  ! CHECK:      omp.parallel
+  ! CHECK-SAME: if({{.*}})
+  !$omp parallel do if(parallel: .true.)
+  do i = 1, 10
+  end do
+  !$omp end parallel do
+
+  ! ----------------------------------------------------------------------------
+  ! PARALLEL DO SIMD
+  ! ----------------------------------------------------------------------------
+  ! CHECK:      omp.parallel
+  ! CHECK-NOT:  if({{.*}})
+  ! CHECK-SAME: {
+  ! CHECK:      omp.simdloop
+  ! CHECK-NOT:  if({{.*}})
+  ! CHECK-SAME: {
+  !$omp parallel do simd
+  do i = 1, 10
+  end do
+  !$omp end parallel do simd
+
+  ! CHECK:      omp.parallel
+  ! CHECK-SAME: if({{.*}})
+  ! CHECK:      omp.simdloop
+  ! CHECK-SAME: if({{.*}})
+  !$omp parallel do simd if(.true.)
+  do i = 1, 10
+  end do
+  !$omp end parallel do simd
+  
+  ! CHECK:      omp.parallel
+  ! CHECK-SAME: if({{.*}})
+  ! CHECK:      omp.simdloop
+  ! CHECK-SAME: if({{.*}})
+  !$omp parallel do simd if(parallel: .true.) if(simd: .false.)
+  do i = 1, 10
+  end do
+  !$omp end parallel do simd
+  
+  ! CHECK:      omp.parallel
+  ! CHECK-SAME: if({{.*}})
+  ! CHECK:      omp.simdloop
+  ! CHECK-NOT:  if({{.*}})
+  ! CHECK-SAME: {
+  !$omp parallel do simd if(parallel: .true.)
+  do i = 1, 10
+  end do
+  !$omp end parallel do simd
+  
+  ! CHECK:      omp.parallel
+  ! CHECK-NOT:  if({{.*}})
+  ! CHECK-SAME: {
+  ! CHECK:      omp.simdloop
+  ! CHECK-SAME: if({{.*}})
+  !$omp parallel do simd if(simd: .true.)
+  do i = 1, 10
+  end do
+  !$omp end parallel do simd
+
+  ! ----------------------------------------------------------------------------
+  ! SIMD
+  ! ----------------------------------------------------------------------------
+  ! CHECK:      omp.simdloop
+  ! CHECK-NOT:  if({{.*}})
+  ! CHECK-SAME: {
+  !$omp simd
+  do i = 1, 10
+  end do
+  !$omp end simd
+
+  ! CHECK:      omp.simdloop
+  ! CHECK-SAME: if({{.*}})
+  !$omp simd if(.true.)
+  do i = 1, 10
+  end do
+  !$omp end simd
+
+  ! CHECK:      omp.simdloop
+  ! CHECK-SAME: if({{.*}})
+  !$omp simd if(simd: .true.)
+  do i = 1, 10
+  end do
+  !$omp end simd
+
+  ! ----------------------------------------------------------------------------
+  ! TARGET
+  ! ----------------------------------------------------------------------------
+  ! CHECK:      omp.target
+  ! CHECK-NOT:  if({{.*}})
+  ! CHECK-SAME: {
+  !$omp target
+  !$omp end target
+
+  ! CHECK:      omp.target
+  ! CHECK-SAME: if({{.*}})
+  !$omp target if(.true.)
+  !$omp end target
+
+  ! CHECK:      omp.target
+  ! CHECK-SAME: if({{.*}})
+  !$omp target if(target: .true.)
+  !$omp end target
+
+  ! ----------------------------------------------------------------------------
+  ! TARGET DATA
+  ! ----------------------------------------------------------------------------
+  ! CHECK:      omp.target_data
+  ! CHECK-NOT:  if({{.*}})
+  ! CHECK-SAME: {
+  !$omp target data map(tofrom: i)
+  !$omp end target data
+
+  ! CHECK:      omp.target_data
+  ! CHECK-SAME: if({{.*}})
+  !$omp target data map(tofrom: i) if(.true.)
+  !$omp end target data
+
+  ! CHECK:      omp.target_data
+  ! CHECK-SAME: if({{.*}})
+  !$omp target data map(tofrom: i) if(target data: .true.)
+  !$omp end target data
+
+  ! ----------------------------------------------------------------------------
+  ! TARGET ENTER DATA
+  ! ----------------------------------------------------------------------------
+  ! CHECK:      omp.target_enter_data
+  ! CHECK-NOT:  if({{.*}})
+  ! CHECK-SAME: map
+  !$omp target enter data map(to: i)
+
+  ! CHECK:      omp.target_enter_data
+  ! CHECK-SAME: if({{.*}})
+  !$omp target enter data map(to: i) if(.true.)
+
+  ! CHECK:      omp.target_enter_data
+  ! CHECK-SAME: if({{.*}})
+  !$omp target enter data map(to: i) if(target enter data: .true.)
+
+  ! ----------------------------------------------------------------------------
+  ! TARGET EXIT DATA
+  ! ----------------------------------------------------------------------------
+  ! CHECK:      omp.target_exit_data
+  ! CHECK-NOT:  if({{.*}})
+  ! CHECK-SAME: map
+  !$omp target exit data map(from: i)
+
+  ! CHECK:      omp.target_exit_data
+  ! CHECK-SAME: if({{.*}})
+  !$omp target exit data map(from: i) if(.true.)
+
+  ! CHECK:      omp.target_exit_data
+  ! CHECK-SAME: if({{.*}})
+  !$omp target exit data map(from: i) if(target exit data: .true.)
+
+  ! ----------------------------------------------------------------------------
+  ! TARGET PARALLEL DO
+  ! ----------------------------------------------------------------------------
+  ! CHECK:      omp.target
+  ! CHECK-NOT:  if({{.*}})
+  ! CHECK-SAME: {
+  ! CHECK:      omp.parallel
+  ! CHECK-NOT:  if({{.*}})
+  ! CHECK-SAME: {
+  !$omp target parallel do
+  do i = 1, 10
+  end do
+  !$omp end target parallel do
+
+  ! CHECK:      omp.target
+  ! CHECK-SAME: if({{.*}})
+  ! CHECK:      omp.parallel
+  ! CHECK-SAME: if({{.*}})
+  !$omp target parallel do if(.true.)
+  do i = 1, 10
+  end do
+  !$omp end target parallel do
+
+  ! CHECK:      omp.target
+  ! CHECK-SAME: if({{.*}})
+  ! CHECK:      omp.parallel
+  ! CHECK-SAME: if({{.*}})
+  !$omp target parallel do if(target: .true.) if(parallel: .false.)
+  do i = 1, 10
+  end do
+  !$omp end target parallel do
+
+  ! CHECK:      omp.target
+  ! CHECK-SAME: if({{.*}})
+  ! CHECK:      omp.parallel
+  ! CHECK-NOT:  if({{.*}})
+  ! CHECK-SAME: {
+  !$omp target parallel do if(target: .true.)
+  do i = 1, 10
+  end do
+  !$omp end target parallel do
+
+  
+  ! CHECK:      omp.target
+  ! CHECK-NOT:  if({{.*}})
+  ! CHECK-SAME: {
+  ! CHECK:      omp.parallel
+  ! CHECK-SAME: if({{.*}})
+  !$omp target parallel do if(parallel: .true.)
+  do i = 1, 10
+  end do
+  !$omp end target parallel do
+
+  ! ----------------------------------------------------------------------------
+  ! TARGET PARALLEL DO SIMD
+  ! ----------------------------------------------------------------------------
+  ! CHECK:      omp.target
+  ! CHECK-NOT:  if({{.*}})
+  ! CHECK-SAME: {
+  ! CHECK:      omp.parallel
+  ! CHECK-NOT:  if({{.*}})
+  ! CHECK-SAME: {
+  ! CHECK:      omp.simdloop
+  ! CHECK-NOT:  if({{.*}})
+  ! CHECK-SAME: {
+  !$omp target parallel do simd
+  do i = 1, 10
+  end do
+  !$omp end target parallel do simd
+
+  ! CHECK:      omp.target
+  ! CHECK-SAME: if({{.*}})
+  ! CHECK:      omp.parallel
+  ! CHECK-SAME: if({{.*}})
+  ! CHECK:      omp.simdloop
+  ! CHECK-SAME: if({{.*}})
+  !$omp target parallel do simd if(.true.)
+  do i = 1, 10
+  end do
+  !$omp end target parallel do simd
+
+  ! CHECK:      omp.target
+  ! CHECK-SAME: if({{.*}})
+  ! CHECK:      omp.parallel
+  ! CHECK-SAME: if({{.*}})
+  ! CHECK:      omp.simdloop
+  ! CHECK-SAME: if({{.*}})
+  !$omp target parallel do simd if(target: .true.) if(parallel: .false.) &
+  !$omp&                        if(simd: .true.)
+  do i = 1, 10
+  end do
+  !$omp end target parallel do simd
+
+  ! CHECK:      omp.target
+  ! CHECK-SAME: if({{.*}})
+  ! CHECK:      omp.parallel
+  ! CHECK-NOT:  if({{.*}})
+  ! CHECK-SAME: {
+  ! CHECK:      omp.simdloop
+  ! CHECK-NOT:  if({{.*}})
+  ! CHECK-SAME: {
+  !$omp target parallel do simd if(target: .true.)
+  do i = 1, 10
+  end do
+  !$omp end target parallel do simd
+
+  ! CHECK:      omp.target
+  ! CHECK-NOT:  if({{.*}})
+  ! CHECK-SAME: {
+  ! CHECK:      omp.parallel
+  ! CHECK-SAME: if({{.*}})
+  ! CHECK:      omp.simdloop
+  ! CHECK-SAME: if({{.*}})
+  !$omp target parallel do simd if(parallel: .true.) if(simd: .false.)
+  do i = 1, 10
+  end do
+  !$omp end target parallel do simd
+
+  ! ----------------------------------------------------------------------------
+  ! TARGET SIMD
+  ! ----------------------------------------------------------------------------
+  ! CHECK:      omp.target
+  ! CHECK-NOT:  if({{.*}})
+  ! CHECK-SAME: {
+  ! CHECK:      omp.simdloop
+  ! CHECK-NOT:  if({{.*}})
+  ! CHECK-SAME: {
+  !$omp target simd
+  do i = 1, 10
+  end do
+  !$omp end target simd
+
+  ! CHECK:      omp.target
+  ! CHECK-SAME: if({{.*}})
+  ! CHECK:      omp.simdloop
+  ! CHECK-SAME: if({{.*}})
+  !$omp target simd if(.true.)
+  do i = 1, 10
+  end do
+  !$omp end target simd
+
+  ! CHECK:      omp.target
+  ! CHECK-SAME: if({{.*}})
+  ! CHECK:      omp.simdloop
+  ! CHECK-SAME: if({{.*}})
+  !$omp target simd if(target: .true.) if(simd: .false.)
+  do i = 1, 10
+  end do
+  !$omp end target simd
+
+  ! CHECK:      omp.target
+  ! CHECK-SAME: if({{.*}})
+  ! CHECK:      omp.simdloop
+  ! CHECK-NOT:  if({{.*}})
+  ! CHECK-SAME: {
+  !$omp target simd if(target: .true.)
+  do i = 1, 10
+  end do
+  !$omp end target simd
+
+  ! CHECK:      omp.target
+  ! CHECK-NOT:  if({{.*}})
+  ! CHECK-SAME: {
+  ! CHECK:      omp.simdloop
+  ! CHECK-SAME: if({{.*}})
+  !$omp target simd if(simd: .true.)
+  do i = 1, 10
+  end do
+  !$omp end target simd
+
+  ! ----------------------------------------------------------------------------
+  ! TASK
+  ! ----------------------------------------------------------------------------
+  ! CHECK:      omp.task
+  ! CHECK-NOT:  if({{.*}})
+  ! CHECK-SAME: {
+  !$omp task
+  !$omp end task
+
+  ! CHECK:      omp.task
+  ! CHECK-SAME: if({{.*}})
+  !$omp task if(.true.)
+  !$omp end task
+
+  ! CHECK:      omp.task
+  ! CHECK-SAME: if({{.*}})
+  !$omp task if(task: .true.)
+  !$omp end task
+end program main

diff  --git a/flang/test/Lower/OpenMP/loop-combined.f90 b/flang/test/Lower/OpenMP/loop-combined.f90
new file mode 100644
index 00000000000000..117f7d625270ec
--- /dev/null
+++ b/flang/test/Lower/OpenMP/loop-combined.f90
@@ -0,0 +1,83 @@
+! This test checks lowering of OpenMP combined loop constructs.
+
+! RUN: bbc -fopenmp -emit-fir %s -o - | FileCheck %s
+! RUN: %flang_fc1 -fopenmp -emit-fir %s -o - | FileCheck %s
+
+program main
+  integer :: i
+
+  ! TODO When DISTRIBUTE, TASKLOOP and TEAMS are supported add:
+  ! - DISTRIBUTE PARALLEL DO SIMD
+  ! - DISTRIBUTE PARALLEL DO
+  ! - DISTRIBUTE SIMD
+  ! - TARGET TEAMS DISTRIBUTE PARALLEL DO SIMD
+  ! - TARGET TEAMS DISTRIBUTE PARALLEL DO
+  ! - TARGET TEAMS DISTRIBUTE SIMD
+  ! - TARGET TEAMS DISTRIBUTE
+  ! - TASKLOOP SIMD
+  ! - TEAMS DISTRIBUTE PARALLEL DO SIMD
+  ! - TEAMS DISTRIBUTE PARALLEL DO
+  ! - TEAMS DISTRIBUTE SIMD
+  ! - TEAMS DISTRIBUTE
+
+  ! ----------------------------------------------------------------------------
+  ! DO SIMD
+  ! ----------------------------------------------------------------------------
+  ! CHECK: omp.simdloop
+  !$omp do simd
+  do i = 1, 10
+  end do
+  !$omp end do simd
+
+  ! ----------------------------------------------------------------------------
+  ! PARALLEL DO SIMD
+  ! ----------------------------------------------------------------------------
+  ! CHECK: omp.parallel
+  ! CHECK: omp.simdloop
+  !$omp parallel do simd
+  do i = 1, 10
+  end do
+  !$omp end parallel do simd
+
+  ! ----------------------------------------------------------------------------
+  ! PARALLEL DO
+  ! ----------------------------------------------------------------------------
+  ! CHECK: omp.parallel
+  ! CHECK: omp.wsloop
+  !$omp parallel do
+  do i = 1, 10
+  end do
+  !$omp end parallel do
+
+  ! ----------------------------------------------------------------------------
+  ! TARGET PARALLEL DO SIMD
+  ! ----------------------------------------------------------------------------
+  ! CHECK: omp.target
+  ! CHECK: omp.parallel
+  ! CHECK: omp.simdloop
+  !$omp target parallel do simd
+  do i = 1, 10
+  end do
+  !$omp end target parallel do simd
+
+  ! ----------------------------------------------------------------------------
+  ! TARGET PARALLEL DO
+  ! ----------------------------------------------------------------------------
+  ! CHECK: omp.target
+  ! CHECK: omp.parallel
+  ! CHECK: omp.wsloop
+  !$omp target parallel do
+  do i = 1, 10
+  end do
+  !$omp end target parallel do
+
+  ! ----------------------------------------------------------------------------
+  ! TARGET SIMD
+  ! ----------------------------------------------------------------------------
+  ! CHECK: omp.target
+  ! CHECK: omp.simdloop
+  !$omp target simd
+  do i = 1, 10
+  end do
+  !$omp end target simd
+end program main

diff  --git a/flang/test/Lower/OpenMP/target.f90 b/flang/test/Lower/OpenMP/target.f90
index 858e66d061c7d8..19618c98913d79 100644
--- a/flang/test/Lower/OpenMP/target.f90
+++ b/flang/test/Lower/OpenMP/target.f90
@@ -216,3 +216,41 @@ subroutine omp_target_device_addr
    !$omp end target data
    !CHECK: }
 end subroutine omp_target_device_addr
+
+!===============================================================================
+! Target with parallel loop
+!===============================================================================
+
+!CHECK-LABEL: func.func @_QPomp_target_parallel_do() {
+subroutine omp_target_parallel_do
+   !CHECK: %[[VAL_0:.*]] = fir.alloca !fir.array<1024xi32> {bindc_name = "a", uniq_name = "_QFomp_target_parallel_doEa"}
+   integer :: a(1024)
+   !CHECK: %[[VAL_1:.*]] = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFomp_target_parallel_doEi"}
+   integer :: i
+   !CHECK: omp.target   map((tofrom -> %[[VAL_0]] : !fir.ref<!fir.array<1024xi32>>)) {
+      !CHECK-NEXT: omp.parallel
+      !$omp target parallel do map(tofrom: a)
+         !CHECK: %[[VAL_2:.*]] = fir.alloca i32 {adapt.valuebyref, pinned}
+         !CHECK: %[[VAL_3:.*]] = arith.constant 1 : i32
+         !CHECK: %[[VAL_4:.*]] = arith.constant 1024 : i32
+         !CHECK: %[[VAL_5:.*]] = arith.constant 1 : i32
+         !CHECK: omp.wsloop   for  (%[[VAL_6:.*]]) : i32 = (%[[VAL_3]]) to (%[[VAL_4]]) inclusive step (%[[VAL_5]]) {
+         !CHECK: fir.store %[[VAL_6]] to %[[VAL_2]] : !fir.ref<i32>
+         !CHECK: %[[VAL_7:.*]] = arith.constant 10 : i32
+         !CHECK: %[[VAL_8:.*]] = fir.load %2 : !fir.ref<i32>
+         !CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_8]] : (i32) -> i64
+         !CHECK: %[[VAL_10:.*]] = arith.constant 1 : i64
+         !CHECK: %[[VAL_11:.*]] = arith.subi %[[VAL_9]], %[[VAL_10]] : i64
+         !CHECK: %[[VAL_12:.*]] = fir.coordinate_of %[[VAL_0]], %[[VAL_11]] : (!fir.ref<!fir.array<1024xi32>>, i64) -> !fir.ref<i32>
+         !CHECK: fir.store %[[VAL_7]] to %[[VAL_12]] : !fir.ref<i32>
+         do i = 1, 1024
+            a(i) = 10
+         end do
+         !CHECK: omp.yield
+         !CHECK: }
+      !CHECK: omp.terminator
+      !CHECK: }
+   !CHECK: omp.terminator
+   !CHECK: }
+   !$omp end target parallel do
+end subroutine omp_target_parallel_do


        


More information about the flang-commits mailing list