[flang][openacc] Lower serial and serial loop construct
authorValentin Clement <clementval@gmail.com>
Thu, 13 Apr 2023 22:35:45 +0000 (15:35 -0700)
committerValentin Clement <clementval@gmail.com>
Thu, 13 Apr 2023 22:36:11 +0000 (15:36 -0700)
Lower the parse tree to acc dialects operations. Make use
of the parallel construct lowering and make it suitable
for all compute constructs lowering.

Reviewed By: PeteSteinfeld

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

flang/lib/Lower/OpenACC.cpp
flang/test/Lower/OpenACC/acc-serial-loop.f90 [new file with mode: 0644]
flang/test/Lower/OpenACC/acc-serial.f90 [new file with mode: 0644]

index 0b8b2e2..8c5f119 100644 (file)
@@ -397,12 +397,13 @@ static void genACC(Fortran::lower::AbstractConverter &converter,
   }
 }
 
-static mlir::acc::ParallelOp
-createParallelOp(Fortran::lower::AbstractConverter &converter,
-                 mlir::Location currentLocation,
-                 Fortran::semantics::SemanticsContext &semanticsContext,
-                 Fortran::lower::StatementContext &stmtCtx,
-                 const Fortran::parser::AccClauseList &accClauseList) {
+template <typename Op>
+static Op
+createComputeOp(Fortran::lower::AbstractConverter &converter,
+                mlir::Location currentLocation,
+                Fortran::semantics::SemanticsContext &semanticsContext,
+                Fortran::lower::StatementContext &stmtCtx,
+                const Fortran::parser::AccClauseList &accClauseList) {
 
   // Parallel operation operands
   mlir::Value async;
@@ -550,9 +551,11 @@ createParallelOp(Fortran::lower::AbstractConverter &converter,
   llvm::SmallVector<int32_t, 8> operandSegments;
   addOperand(operands, operandSegments, async);
   addOperands(operands, operandSegments, waitOperands);
-  addOperand(operands, operandSegments, numGangs);
-  addOperand(operands, operandSegments, numWorkers);
-  addOperand(operands, operandSegments, vectorLength);
+  if constexpr (std::is_same_v<Op, mlir::acc::ParallelOp>) {
+    addOperand(operands, operandSegments, numGangs);
+    addOperand(operands, operandSegments, numWorkers);
+    addOperand(operands, operandSegments, vectorLength);
+  }
   addOperand(operands, operandSegments, ifCond);
   addOperand(operands, operandSegments, selfCond);
   addOperands(operands, operandSegments, reductionOperands);
@@ -570,28 +573,17 @@ createParallelOp(Fortran::lower::AbstractConverter &converter,
   addOperands(operands, operandSegments, privateOperands);
   addOperands(operands, operandSegments, firstprivateOperands);
 
-  mlir::acc::ParallelOp parallelOp =
-      createRegionOp<mlir::acc::ParallelOp, mlir::acc::YieldOp>(
-          firOpBuilder, currentLocation, operands, operandSegments);
+  Op computeOp = createRegionOp<Op, mlir::acc::YieldOp>(
+      firOpBuilder, currentLocation, operands, operandSegments);
 
   if (addAsyncAttr)
-    parallelOp.setAsyncAttrAttr(firOpBuilder.getUnitAttr());
+    computeOp.setAsyncAttrAttr(firOpBuilder.getUnitAttr());
   if (addWaitAttr)
-    parallelOp.setWaitAttrAttr(firOpBuilder.getUnitAttr());
+    computeOp.setWaitAttrAttr(firOpBuilder.getUnitAttr());
   if (addSelfAttr)
-    parallelOp.setSelfAttrAttr(firOpBuilder.getUnitAttr());
+    computeOp.setSelfAttrAttr(firOpBuilder.getUnitAttr());
 
-  return parallelOp;
-}
-
-static void
-genACCParallelOp(Fortran::lower::AbstractConverter &converter,
-                 mlir::Location currentLocation,
-                 Fortran::semantics::SemanticsContext &semanticsContext,
-                 Fortran::lower::StatementContext &stmtCtx,
-                 const Fortran::parser::AccClauseList &accClauseList) {
-  createParallelOp(converter, currentLocation, semanticsContext, stmtCtx,
-                   accClauseList);
+  return computeOp;
 }
 
 static void genACCDataOp(Fortran::lower::AbstractConverter &converter,
@@ -696,13 +688,14 @@ genACC(Fortran::lower::AbstractConverter &converter,
   Fortran::lower::StatementContext stmtCtx;
 
   if (blockDirective.v == llvm::acc::ACCD_parallel) {
-    genACCParallelOp(converter, currentLocation, semanticsContext, stmtCtx,
-                     accClauseList);
+    createComputeOp<mlir::acc::ParallelOp>(
+        converter, currentLocation, semanticsContext, stmtCtx, accClauseList);
   } else if (blockDirective.v == llvm::acc::ACCD_data) {
     genACCDataOp(converter, currentLocation, semanticsContext, stmtCtx,
                  accClauseList);
   } else if (blockDirective.v == llvm::acc::ACCD_serial) {
-    TODO(currentLocation, "serial construct lowering");
+    createComputeOp<mlir::acc::SerialOp>(
+        converter, currentLocation, semanticsContext, stmtCtx, accClauseList);
   } else if (blockDirective.v == llvm::acc::ACCD_kernels) {
     TODO(currentLocation, "kernels construct lowering");
   } else if (blockDirective.v == llvm::acc::ACCD_host_data) {
@@ -711,18 +704,6 @@ genACC(Fortran::lower::AbstractConverter &converter,
 }
 
 static void
-genACCParallelLoopOps(Fortran::lower::AbstractConverter &converter,
-                      mlir::Location currentLocation,
-                      Fortran::semantics::SemanticsContext &semanticsContext,
-                      Fortran::lower::StatementContext &stmtCtx,
-                      const Fortran::parser::AccClauseList &accClauseList) {
-  createParallelOp(converter, currentLocation, semanticsContext, stmtCtx,
-                   accClauseList);
-  createLoopOp(converter, currentLocation, semanticsContext, stmtCtx,
-               accClauseList);
-}
-
-static void
 genACC(Fortran::lower::AbstractConverter &converter,
        Fortran::semantics::SemanticsContext &semanticsContext,
        Fortran::lower::pft::Evaluation &eval,
@@ -741,10 +722,15 @@ genACC(Fortran::lower::AbstractConverter &converter,
   if (combinedDirective.v == llvm::acc::ACCD_kernels_loop) {
     TODO(currentLocation, "OpenACC Kernels Loop construct not lowered yet!");
   } else if (combinedDirective.v == llvm::acc::ACCD_parallel_loop) {
-    genACCParallelLoopOps(converter, currentLocation, semanticsContext, stmtCtx,
-                          accClauseList);
+    createComputeOp<mlir::acc::ParallelOp>(
+        converter, currentLocation, semanticsContext, stmtCtx, accClauseList);
+    createLoopOp(converter, currentLocation, semanticsContext, stmtCtx,
+                 accClauseList);
   } else if (combinedDirective.v == llvm::acc::ACCD_serial_loop) {
-    TODO(currentLocation, "OpenACC Serial Loop construct not lowered yet!");
+    createComputeOp<mlir::acc::SerialOp>(
+        converter, currentLocation, semanticsContext, stmtCtx, accClauseList);
+    createLoopOp(converter, currentLocation, semanticsContext, stmtCtx,
+                 accClauseList);
   } else {
     llvm::report_fatal_error("Unknown combined construct encountered");
   }
diff --git a/flang/test/Lower/OpenACC/acc-serial-loop.f90 b/flang/test/Lower/OpenACC/acc-serial-loop.f90
new file mode 100644 (file)
index 0000000..e952554
--- /dev/null
@@ -0,0 +1,613 @@
+! This test checks lowering of Openacc serial loop combined directive.
+
+! RUN: bbc -fopenacc -emit-fir %s -o - | FileCheck %s
+
+subroutine acc_serial_loop
+  integer :: i, j
+
+  integer :: async = 1
+  integer :: wait1 = 1
+  integer :: wait2 = 2
+  integer :: numGangs = 1
+  integer :: numWorkers = 10
+  integer :: vectorLength = 128
+  logical :: ifCondition = .TRUE.
+  integer, parameter :: n = 10
+  real, dimension(n) :: a, b, c
+  real, dimension(n, n) :: d, e
+  real, pointer :: f, g
+
+  integer :: gangNum = 8
+  integer :: gangStatic = 8
+  integer :: vectorNum = 128
+  integer, parameter :: tileSize = 2
+
+!CHECK: [[A:%.*]] = fir.alloca !fir.array<10xf32> {{{.*}}uniq_name = "{{.*}}Ea"}
+!CHECK: [[B:%.*]] = fir.alloca !fir.array<10xf32> {{{.*}}uniq_name = "{{.*}}Eb"}
+!CHECK: [[C:%.*]] = fir.alloca !fir.array<10xf32> {{{.*}}uniq_name = "{{.*}}Ec"}
+!CHECK: [[F:%.*]] = fir.alloca !fir.box<!fir.ptr<f32>> {bindc_name = "f", uniq_name = "{{.*}}Ef"}
+!CHECK: [[G:%.*]] = fir.alloca !fir.box<!fir.ptr<f32>> {bindc_name = "g", uniq_name = "{{.*}}Eg"}
+!CHECK: [[IFCONDITION:%.*]] = fir.address_of(@{{.*}}ifcondition) : !fir.ref<!fir.logical<4>>
+
+  !$acc serial loop
+  DO i = 1, n
+    a(i) = b(i)
+  END DO
+
+!CHECK:      acc.serial {
+!CHECK:        acc.loop {
+!CHECK:          fir.do_loop
+!CHECK:          acc.yield
+!CHECK-NEXT:   }{{$}}
+!CHECK:        acc.yield
+!CHECK-NEXT: }{{$}}
+
+  !$acc serial loop async
+  DO i = 1, n
+    a(i) = b(i)
+  END DO
+  !$acc end serial loop
+
+!CHECK:      acc.serial {
+!CHECK:        acc.loop {
+!CHECK:          fir.do_loop
+!CHECK:          acc.yield
+!CHECK-NEXT:   }{{$}}
+!CHECK:        acc.yield
+!CHECK-NEXT: } attributes {asyncAttr}
+
+  !$acc serial loop async(1)
+  DO i = 1, n
+    a(i) = b(i)
+  END DO
+
+!CHECK:      [[ASYNC1:%.*]] = arith.constant 1 : i32
+!CHECK:      acc.serial async([[ASYNC1]] : i32) {
+!CHECK:        acc.loop {
+!CHECK:          fir.do_loop
+!CHECK:          acc.yield
+!CHECK-NEXT:   }{{$}}
+!CHECK:        acc.yield
+!CHECK-NEXT: }{{$}}
+
+  !$acc serial loop async(async)
+  DO i = 1, n
+    a(i) = b(i)
+  END DO
+
+!CHECK:      [[ASYNC2:%.*]] = fir.load %{{.*}} : !fir.ref<i32>
+!CHECK:      acc.serial async([[ASYNC2]] : i32) {
+!CHECK:        acc.loop {
+!CHECK:          fir.do_loop
+!CHECK:          acc.yield
+!CHECK-NEXT:   }{{$}}
+!CHECK:        acc.yield
+!CHECK-NEXT: }{{$}}
+
+  !$acc serial loop wait
+  DO i = 1, n
+    a(i) = b(i)
+  END DO
+
+!CHECK:      acc.serial {
+!CHECK:        acc.loop {
+!CHECK:          fir.do_loop
+!CHECK:          acc.yield
+!CHECK-NEXT:   }{{$}}
+!CHECK:        acc.yield
+!CHECK-NEXT: } attributes {waitAttr}
+
+  !$acc serial loop wait(1)
+  DO i = 1, n
+    a(i) = b(i)
+  END DO
+
+!CHECK:      [[WAIT1:%.*]] = arith.constant 1 : i32
+!CHECK:      acc.serial wait([[WAIT1]] : i32) {
+!CHECK:        acc.loop {
+!CHECK:          fir.do_loop
+!CHECK:          acc.yield
+!CHECK-NEXT:   }{{$}}
+!CHECK:        acc.yield
+!CHECK-NEXT: }{{$}}
+
+  !$acc serial loop wait(1, 2)
+  DO i = 1, n
+    a(i) = b(i)
+  END DO
+
+!CHECK:      [[WAIT2:%.*]] = arith.constant 1 : i32
+!CHECK:      [[WAIT3:%.*]] = arith.constant 2 : i32
+!CHECK:      acc.serial wait([[WAIT2]], [[WAIT3]] : i32, i32) {
+!CHECK:        acc.loop {
+!CHECK:          fir.do_loop
+!CHECK:          acc.yield
+!CHECK-NEXT:   }{{$}}
+!CHECK:        acc.yield
+!CHECK-NEXT: }{{$}}
+
+  !$acc serial loop wait(wait1, wait2)
+  DO i = 1, n
+    a(i) = b(i)
+  END DO
+
+!CHECK:      [[WAIT4:%.*]] = fir.load %{{.*}} : !fir.ref<i32>
+!CHECK:      [[WAIT5:%.*]] = fir.load %{{.*}} : !fir.ref<i32>
+!CHECK:      acc.serial wait([[WAIT4]], [[WAIT5]] : i32, i32) {
+!CHECK:        acc.loop {
+!CHECK:          fir.do_loop
+!CHECK:          acc.yield
+!CHECK-NEXT:   }{{$}}
+!CHECK:        acc.yield
+!CHECK-NEXT: }{{$}}
+
+  !$acc serial loop if(.TRUE.)
+  DO i = 1, n
+    a(i) = b(i)
+  END DO
+
+!CHECK:      [[IF1:%.*]] = arith.constant true
+!CHECK:      acc.serial if([[IF1]]) {
+!CHECK:        acc.loop {
+!CHECK:          fir.do_loop
+!CHECK:          acc.yield
+!CHECK-NEXT:   }{{$}}
+!CHECK:        acc.yield
+!CHECK-NEXT: }{{$}}
+
+  !$acc serial loop if(ifCondition)
+  DO i = 1, n
+    a(i) = b(i)
+  END DO
+
+!CHECK:      [[IFCOND:%.*]] = fir.load %{{.*}} : !fir.ref<!fir.logical<4>>
+!CHECK:      [[IF2:%.*]] = fir.convert [[IFCOND]] : (!fir.logical<4>) -> i1
+!CHECK:      acc.serial if([[IF2]]) {
+!CHECK:        acc.loop {
+!CHECK:          fir.do_loop
+!CHECK:          acc.yield
+!CHECK-NEXT:   }{{$}}
+!CHECK:        acc.yield
+!CHECK-NEXT: }{{$}}
+
+  !$acc serial loop self(.TRUE.)
+  DO i = 1, n
+    a(i) = b(i)
+  END DO
+
+!CHECK:      [[SELF1:%.*]] = arith.constant true
+!CHECK:      acc.serial self([[SELF1]]) {
+!CHECK:        acc.loop {
+!CHECK:          fir.do_loop
+!CHECK:          acc.yield
+!CHECK-NEXT:   }{{$}}
+!CHECK:        acc.yield
+!CHECK-NEXT: }{{$}}
+
+  !$acc serial loop self
+  DO i = 1, n
+    a(i) = b(i)
+  END DO
+
+!CHECK:      acc.serial {
+!CHECK:        acc.loop {
+!CHECK:          fir.do_loop
+!CHECK:          acc.yield
+!CHECK-NEXT:   }{{$}}
+!CHECK:        acc.yield
+!CHECK-NEXT: } attributes {selfAttr}
+
+  !$acc serial loop self(ifCondition)
+  DO i = 1, n
+    a(i) = b(i)
+  END DO
+
+!CHECK:      [[SELF2:%.*]] = fir.convert [[IFCONDITION]] : (!fir.ref<!fir.logical<4>>) -> i1
+!CHECK:      acc.serial self([[SELF2]]) {
+!CHECK:        acc.loop {
+!CHECK:          fir.do_loop
+!CHECK:          acc.yield
+!CHECK-NEXT:   }{{$}}
+!CHECK:        acc.yield
+!CHECK-NEXT: }{{$}}
+
+  !$acc serial loop copy(a, b)
+  DO i = 1, n
+    a(i) = b(i)
+  END DO
+
+!CHECK:      acc.serial copy([[A]], [[B]] : !fir.ref<!fir.array<10xf32>>, !fir.ref<!fir.array<10xf32>>) {
+!CHECK:        acc.loop {
+!CHECK:          fir.do_loop
+!CHECK:          acc.yield
+!CHECK-NEXT:   }{{$}}
+!CHECK:        acc.yield
+!CHECK-NEXT: }{{$}}
+
+  !$acc serial loop copy(a) copy(b)
+  DO i = 1, n
+    a(i) = b(i)
+  END DO
+
+!CHECK:      acc.serial copy([[A]], [[B]] : !fir.ref<!fir.array<10xf32>>, !fir.ref<!fir.array<10xf32>>) {
+!CHECK:        acc.loop {
+!CHECK:          fir.do_loop
+!CHECK:          acc.yield
+!CHECK-NEXT:   }{{$}}
+!CHECK:        acc.yield
+!CHECK-NEXT: }{{$}}
+
+  !$acc serial loop copyin(a) copyin(readonly: b)
+  DO i = 1, n
+    a(i) = b(i)
+  END DO
+
+!CHECK:      acc.serial copyin([[A]] : !fir.ref<!fir.array<10xf32>>) copyin_readonly([[B]] : !fir.ref<!fir.array<10xf32>>) {
+!CHECK:        acc.loop {
+!CHECK:          fir.do_loop
+!CHECK:          acc.yield
+!CHECK-NEXT:   }{{$}}
+!CHECK:        acc.yield
+!CHECK-NEXT: }{{$}}
+
+  !$acc serial loop copyout(a) copyout(zero: b)
+  DO i = 1, n
+    a(i) = b(i)
+  END DO
+
+!CHECK:      acc.serial copyout([[A]] : !fir.ref<!fir.array<10xf32>>) copyout_zero([[B]] : !fir.ref<!fir.array<10xf32>>) {
+!CHECK:        acc.loop {
+!CHECK:          fir.do_loop
+!CHECK:          acc.yield
+!CHECK-NEXT:   }{{$}}
+!CHECK:        acc.yield
+!CHECK-NEXT: }{{$}}
+
+  !$acc serial loop create(b) create(zero: a)
+  DO i = 1, n
+    a(i) = b(i)
+  END DO
+
+!CHECK:      acc.serial create([[B]] : !fir.ref<!fir.array<10xf32>>) create_zero([[A]] : !fir.ref<!fir.array<10xf32>>) {
+!CHECK:        acc.loop {
+!CHECK:          fir.do_loop
+!CHECK:          acc.yield
+!CHECK-NEXT:   }{{$}}
+!CHECK:        acc.yield
+!CHECK-NEXT: }{{$}}
+
+  !$acc serial loop no_create(a, b)
+  DO i = 1, n
+    a(i) = b(i)
+  END DO
+
+!CHECK:      acc.serial no_create([[A]], [[B]] : !fir.ref<!fir.array<10xf32>>, !fir.ref<!fir.array<10xf32>>) {
+!CHECK:        acc.loop {
+!CHECK:          fir.do_loop
+!CHECK:          acc.yield
+!CHECK-NEXT:   }{{$}}
+!CHECK:        acc.yield
+!CHECK-NEXT: }{{$}}
+
+  !$acc serial loop present(a, b)
+  DO i = 1, n
+    a(i) = b(i)
+  END DO
+
+!CHECK:      acc.serial present([[A]], [[B]] : !fir.ref<!fir.array<10xf32>>, !fir.ref<!fir.array<10xf32>>) {
+!CHECK:        acc.loop {
+!CHECK:          fir.do_loop
+!CHECK:          acc.yield
+!CHECK-NEXT:   }{{$}}
+!CHECK:        acc.yield
+!CHECK-NEXT: }{{$}}
+
+  !$acc serial loop deviceptr(a) deviceptr(b)
+  DO i = 1, n
+    a(i) = b(i)
+  END DO
+
+!CHECK:      acc.serial deviceptr([[A]], [[B]] : !fir.ref<!fir.array<10xf32>>, !fir.ref<!fir.array<10xf32>>) {
+!CHECK:        acc.loop {
+!CHECK:          fir.do_loop
+!CHECK:          acc.yield
+!CHECK-NEXT:   }{{$}}
+!CHECK:        acc.yield
+!CHECK-NEXT: }{{$}}
+
+  !$acc serial loop attach(f, g)
+  DO i = 1, n
+    a(i) = b(i)
+  END DO
+
+!CHECK:      acc.serial attach([[F]], [[G]] : !fir.ref<!fir.box<!fir.ptr<f32>>>, !fir.ref<!fir.box<!fir.ptr<f32>>>) {
+!CHECK:        acc.loop {
+!CHECK:          fir.do_loop
+!CHECK:          acc.yield
+!CHECK-NEXT:   }{{$}}
+!CHECK:        acc.yield
+!CHECK-NEXT: }{{$}}
+
+  !$acc serial loop private(a) firstprivate(b)
+  DO i = 1, n
+    a(i) = b(i)
+  END DO
+
+!CHECK:      acc.serial firstprivate([[B]] : !fir.ref<!fir.array<10xf32>>) private([[A]] : !fir.ref<!fir.array<10xf32>>) {
+!CHECK:        acc.loop private([[A]]: !fir.ref<!fir.array<10xf32>>) {
+!CHECK:          fir.do_loop
+!CHECK:          acc.yield
+!CHECK-NEXT:   }{{$}}
+!CHECK:        acc.yield
+!CHECK-NEXT: }{{$}}
+
+  !$acc serial loop seq
+  DO i = 1, n
+    a(i) = b(i)
+  END DO
+
+!CHECK:      acc.serial {
+!CHECK:        acc.loop {
+!CHECK:          fir.do_loop
+!CHECK:          acc.yield
+!CHECK-NEXT:   } attributes {seq}
+!CHECK:        acc.yield
+!CHECK-NEXT: }{{$}}
+
+  !$acc serial loop auto
+  DO i = 1, n
+    a(i) = b(i)
+  END DO
+
+!CHECK:      acc.serial {
+!CHECK:        acc.loop {
+!CHECK:          fir.do_loop
+!CHECK:          acc.yield
+!CHECK-NEXT:   } attributes {auto}
+!CHECK:        acc.yield
+!CHECK-NEXT: }{{$}}
+
+  !$acc serial loop independent
+  DO i = 1, n
+    a(i) = b(i)
+  END DO
+
+!CHECK:      acc.serial {
+!CHECK:        acc.loop {
+!CHECK:          fir.do_loop
+!CHECK:          acc.yield
+!CHECK-NEXT:   } attributes {independent}
+!CHECK:        acc.yield
+!CHECK-NEXT: }{{$}}
+
+  !$acc serial loop gang
+  DO i = 1, n
+    a(i) = b(i)
+  END DO
+
+!CHECK:      acc.serial {
+!CHECK:        acc.loop gang {
+!CHECK:          fir.do_loop
+!CHECK:          acc.yield
+!CHECK-NEXT:   }{{$}}
+!CHECK:        acc.yield
+!CHECK-NEXT: }{{$}}
+
+  !$acc serial loop gang(num: 8)
+  DO i = 1, n
+    a(i) = b(i)
+  END DO
+
+!CHECK:      acc.serial {
+!CHECK:        [[GANGNUM1:%.*]] = arith.constant 8 : i32
+!CHECK-NEXT:   acc.loop gang(num=[[GANGNUM1]]: i32) {
+!CHECK:          fir.do_loop
+!CHECK:          acc.yield
+!CHECK-NEXT:   }{{$}}
+!CHECK:        acc.yield
+!CHECK-NEXT: }{{$}}
+
+  !$acc serial loop gang(num: gangNum)
+  DO i = 1, n
+    a(i) = b(i)
+  END DO
+
+!CHECK:      acc.serial {
+!CHECK:        [[GANGNUM2:%.*]] = fir.load %{{.*}} : !fir.ref<i32>
+!CHECK-NEXT:   acc.loop gang(num=[[GANGNUM2]]: i32) {
+!CHECK:          fir.do_loop
+!CHECK:          acc.yield
+!CHECK-NEXT:   }{{$}}
+!CHECK:        acc.yield
+!CHECK-NEXT: }{{$}}
+
+ !$acc serial loop gang(num: gangNum, static: gangStatic)
+  DO i = 1, n
+    a(i) = b(i)
+  END DO
+
+!CHECK:      acc.serial {
+!CHECK:        acc.loop gang(num=%{{.*}}: i32, static=%{{.*}}: i32) {
+!CHECK:          fir.do_loop
+!CHECK:          acc.yield
+!CHECK-NEXT:   }{{$}}
+!CHECK:        acc.yield
+!CHECK-NEXT: }{{$}}
+
+  !$acc serial loop vector
+  DO i = 1, n
+    a(i) = b(i)
+  END DO
+!CHECK:      acc.serial {
+!CHECK:        acc.loop vector {
+!CHECK:          fir.do_loop
+!CHECK:          acc.yield
+!CHECK-NEXT:   }{{$}}
+!CHECK:        acc.yield
+!CHECK-NEXT: }{{$}}
+
+  !$acc serial loop vector(128)
+  DO i = 1, n
+    a(i) = b(i)
+  END DO
+
+!CHECK:      acc.serial {
+!CHECK:        [[CONSTANT128:%.*]] = arith.constant 128 : i32
+!CHECK:        acc.loop vector([[CONSTANT128]]: i32) {
+!CHECK:          fir.do_loop
+!CHECK:          acc.yield
+!CHECK-NEXT:   }{{$}}
+!CHECK:        acc.yield
+!CHECK-NEXT: }{{$}}
+
+  !$acc serial loop vector(vectorLength)
+  DO i = 1, n
+    a(i) = b(i)
+  END DO
+
+!CHECK:      acc.serial {
+!CHECK:        [[VECTORLENGTH:%.*]] = fir.load %{{.*}} : !fir.ref<i32>
+!CHECK:        acc.loop vector([[VECTORLENGTH]]: i32) {
+!CHECK:          fir.do_loop
+!CHECK:          acc.yield
+!CHECK-NEXT:   }{{$}}
+!CHECK:        acc.yield
+!CHECK-NEXT: }{{$}}
+
+  !$acc serial loop worker
+  DO i = 1, n
+    a(i) = b(i)
+  END DO
+
+!CHECK:      acc.serial {
+!CHECK:        acc.loop worker {
+!CHECK:          fir.do_loop
+!CHECK:          acc.yield
+!CHECK-NEXT:   }{{$}}
+!CHECK:        acc.yield
+!CHECK-NEXT: }{{$}}
+
+  !$acc serial loop worker(128)
+  DO i = 1, n
+    a(i) = b(i)
+  END DO
+
+!CHECK:      acc.serial {
+!CHECK:        [[WORKER128:%.*]] = arith.constant 128 : i32
+!CHECK:        acc.loop worker([[WORKER128]]: i32) {
+!CHECK:          fir.do_loop
+!CHECK:          acc.yield
+!CHECK-NEXT:   }{{$}}
+!CHECK:        acc.yield
+!CHECK-NEXT: }{{$}}
+
+  !$acc serial loop collapse(2)
+  DO i = 1, n
+    DO j = 1, n
+      d(i, j) = e(i, j)
+    END DO
+  END DO
+
+!CHECK:      acc.serial {
+!CHECK:        acc.loop {
+!CHECK:          fir.do_loop
+!CHECK:            fir.do_loop
+!CHECK:          acc.yield
+!CHECK-NEXT:   } attributes {collapse = 2 : i64}
+!CHECK:        acc.yield
+!CHECK-NEXT: }{{$}}
+
+  !$acc serial loop
+  DO i = 1, n
+    !$acc loop
+    DO j = 1, n
+      d(i, j) = e(i, j)
+    END DO
+  END DO
+
+!CHECK:      acc.serial {
+!CHECK:        acc.loop {
+!CHECK:          fir.do_loop
+!CHECK:            acc.loop {
+!CHECK:              fir.do_loop
+!CHECK:              acc.yield
+!CHECK-NEXT:     }{{$}}
+!CHECK:          acc.yield
+!CHECK-NEXT:   }{{$}}
+!CHECK:        acc.yield
+!CHECK-NEXT: }{{$}}
+
+ !$acc serial loop tile(2)
+  DO i = 1, n
+    a(i) = b(i)
+  END DO
+
+!CHECK:      acc.serial {
+!CHECK:        [[TILESIZE:%.*]] = arith.constant 2 : i32
+!CHECK:        acc.loop tile([[TILESIZE]]: i32) {
+!CHECK:          fir.do_loop
+!CHECK:          acc.yield
+!CHECK-NEXT:   }{{$}}
+!CHECK:        acc.yield
+!CHECK-NEXT: }{{$}}
+
+ !$acc serial loop tile(*)
+  DO i = 1, n
+    a(i) = b(i)
+  END DO
+
+!CHECK:      acc.serial {
+!CHECK:        [[TILESIZEM1:%.*]] = arith.constant -1 : i32
+!CHECK:        acc.loop tile([[TILESIZEM1]]: i32) {
+!CHECK:          fir.do_loop
+!CHECK:          acc.yield
+!CHECK-NEXT:   }{{$}}
+!CHECK:        acc.yield
+!CHECK-NEXT: }{{$}}
+
+  !$acc serial loop tile(2, 2)
+  DO i = 1, n
+    DO j = 1, n
+      d(i, j) = e(i, j)
+    END DO
+  END DO
+
+!CHECK:      acc.serial {
+!CHECK:        [[TILESIZE1:%.*]] = arith.constant 2 : i32
+!CHECK:        [[TILESIZE2:%.*]] = arith.constant 2 : i32
+!CHECK:        acc.loop tile([[TILESIZE1]]: i32, [[TILESIZE2]]: i32) {
+!CHECK:          fir.do_loop
+!CHECK:          acc.yield
+!CHECK-NEXT:   }{{$}}
+!CHECK:        acc.yield
+!CHECK-NEXT: }{{$}}
+
+  !$acc serial loop tile(tileSize)
+  DO i = 1, n
+    a(i) = b(i)
+  END DO
+
+!CHECK:      acc.serial {
+!CHECK:        acc.loop tile(%{{.*}}: i32) {
+!CHECK:          fir.do_loop
+!CHECK:          acc.yield
+!CHECK-NEXT:   }{{$}}
+!CHECK:        acc.yield
+!CHECK-NEXT: }{{$}}
+
+  !$acc serial loop tile(tileSize, tileSize)
+  DO i = 1, n
+    DO j = 1, n
+      d(i, j) = e(i, j)
+    END DO
+  END DO
+
+!CHECK:      acc.serial {
+!CHECK:        acc.loop tile(%{{.*}}: i32, %{{.*}}: i32) {
+!CHECK:          fir.do_loop
+!CHECK:          acc.yield
+!CHECK-NEXT:   }{{$}}
+!CHECK:        acc.yield
+!CHECK-NEXT: }{{$}}
+
+end subroutine acc_serial_loop
diff --git a/flang/test/Lower/OpenACC/acc-serial.f90 b/flang/test/Lower/OpenACC/acc-serial.f90
new file mode 100644 (file)
index 0000000..5bc1998
--- /dev/null
@@ -0,0 +1,198 @@
+! This test checks lowering of OpenACC serial directive.
+
+! RUN: bbc -fopenacc -emit-fir %s -o - | FileCheck %s
+
+subroutine acc_serial
+  integer :: i, j
+
+  integer :: async = 1
+  integer :: wait1 = 1
+  integer :: wait2 = 2
+  integer :: numGangs = 1
+  integer :: numWorkers = 10
+  integer :: vectorLength = 128
+  logical :: ifCondition = .TRUE.
+  real, dimension(10, 10) :: a, b, c
+  real, pointer :: d, e
+
+! CHECK: [[A:%.*]] = fir.alloca !fir.array<10x10xf32> {{{.*}}uniq_name = "{{.*}}Ea"}
+! CHECK: [[B:%.*]] = fir.alloca !fir.array<10x10xf32> {{{.*}}uniq_name = "{{.*}}Eb"}
+! CHECK: [[C:%.*]] = fir.alloca !fir.array<10x10xf32> {{{.*}}uniq_name = "{{.*}}Ec"}
+! CHECK: [[D:%.*]] = fir.alloca !fir.box<!fir.ptr<f32>> {bindc_name = "d", uniq_name = "{{.*}}Ed"}
+! CHECK: [[E:%.*]] = fir.alloca !fir.box<!fir.ptr<f32>> {bindc_name = "e", uniq_name = "{{.*}}Ee"}
+! CHECK: [[IFCONDITION:%.*]] = fir.address_of(@{{.*}}ifcondition) : !fir.ref<!fir.logical<4>>
+
+  !$acc serial
+  !$acc end serial
+
+! CHECK:      acc.serial {
+! CHECK:        acc.yield
+! CHECK-NEXT: }{{$}}
+
+  !$acc serial async
+  !$acc end serial
+
+! CHECK:      acc.serial {
+! CHECK:        acc.yield
+! CHECK-NEXT: } attributes {asyncAttr}
+
+  !$acc serial async(1)
+  !$acc end serial
+
+! CHECK:      [[ASYNC1:%.*]] = arith.constant 1 : i32
+! CHECK:      acc.serial async([[ASYNC1]] : i32) {
+! CHECK:        acc.yield
+! CHECK-NEXT: }{{$}}
+
+  !$acc serial async(async)
+  !$acc end serial
+
+! CHECK:      [[ASYNC2:%.*]] = fir.load %{{.*}} : !fir.ref<i32>
+! CHECK:      acc.serial async([[ASYNC2]] : i32) {
+! CHECK:        acc.yield
+! CHECK-NEXT: }{{$}}
+
+  !$acc serial wait
+  !$acc end serial
+
+! CHECK:      acc.serial {
+! CHECK:        acc.yield
+! CHECK-NEXT: } attributes {waitAttr}
+
+  !$acc serial wait(1)
+  !$acc end serial
+
+! CHECK:      [[WAIT1:%.*]] = arith.constant 1 : i32
+! CHECK:      acc.serial wait([[WAIT1]] : i32) {
+! CHECK:        acc.yield
+! CHECK-NEXT: }{{$}}
+
+  !$acc serial wait(1, 2)
+  !$acc end serial
+
+! CHECK:      [[WAIT2:%.*]] = arith.constant 1 : i32
+! CHECK:      [[WAIT3:%.*]] = arith.constant 2 : i32
+! CHECK:      acc.serial wait([[WAIT2]], [[WAIT3]] : i32, i32) {
+! CHECK:        acc.yield
+! CHECK-NEXT: }{{$}}
+
+  !$acc serial wait(wait1, wait2)
+  !$acc end serial
+
+! CHECK:      [[WAIT4:%.*]] = fir.load %{{.*}} : !fir.ref<i32>
+! CHECK:      [[WAIT5:%.*]] = fir.load %{{.*}} : !fir.ref<i32>
+! CHECK:      acc.serial wait([[WAIT4]], [[WAIT5]] : i32, i32) {
+! CHECK:        acc.yield
+! CHECK-NEXT: }{{$}}
+
+  !$acc serial if(.TRUE.)
+  !$acc end serial
+
+! CHECK:      [[IF1:%.*]] = arith.constant true
+! CHECK:      acc.serial if([[IF1]]) {
+! CHECK:        acc.yield
+! CHECK-NEXT: }{{$}}
+
+  !$acc serial if(ifCondition)
+  !$acc end serial
+
+! CHECK:      [[IFCOND:%.*]] = fir.load %{{.*}} : !fir.ref<!fir.logical<4>>
+! CHECK:      [[IF2:%.*]] = fir.convert [[IFCOND]] : (!fir.logical<4>) -> i1
+! CHECK:      acc.serial if([[IF2]]) {
+! CHECK:        acc.yield
+! CHECK-NEXT: }{{$}}
+
+  !$acc serial self(.TRUE.)
+  !$acc end serial
+
+! CHECK:      [[SELF1:%.*]] = arith.constant true
+! CHECK:      acc.serial self([[SELF1]]) {
+! CHECK:        acc.yield
+! CHECK-NEXT: }{{$}}
+
+  !$acc serial self
+  !$acc end serial
+
+! CHECK:      acc.serial {
+! CHECK:        acc.yield
+! CHECK-NEXT: } attributes {selfAttr}
+
+  !$acc serial self(ifCondition)
+  !$acc end serial
+
+! CHECK:      [[SELF2:%.*]] = fir.convert [[IFCONDITION]] : (!fir.ref<!fir.logical<4>>) -> i1
+! CHECK:      acc.serial self([[SELF2]]) {
+! CHECK:        acc.yield
+! CHECK-NEXT: }{{$}}
+
+  !$acc serial copy(a, b, c)
+  !$acc end serial
+
+! CHECK:      acc.serial copy([[A]], [[B]], [[C]] : !fir.ref<!fir.array<10x10xf32>>, !fir.ref<!fir.array<10x10xf32>>, !fir.ref<!fir.array<10x10xf32>>) {
+! CHECK:        acc.yield
+! CHECK-NEXT: }{{$}}
+
+  !$acc serial copy(a) copy(b) copy(c)
+  !$acc end serial
+
+! CHECK:      acc.serial copy([[A]], [[B]], [[C]] : !fir.ref<!fir.array<10x10xf32>>, !fir.ref<!fir.array<10x10xf32>>, !fir.ref<!fir.array<10x10xf32>>) {
+! CHECK:        acc.yield
+! CHECK-NEXT: }{{$}}
+
+  !$acc serial copyin(a) copyin(readonly: b, c)
+  !$acc end serial
+
+! CHECK:      acc.serial copyin([[A]] : !fir.ref<!fir.array<10x10xf32>>) copyin_readonly([[B]], [[C]] : !fir.ref<!fir.array<10x10xf32>>, !fir.ref<!fir.array<10x10xf32>>) {
+! CHECK:        acc.yield
+! CHECK-NEXT: }{{$}}
+
+  !$acc serial copyout(a) copyout(zero: b) copyout(c)
+  !$acc end serial
+
+! CHECK:      acc.serial copyout([[A]], [[C]] : !fir.ref<!fir.array<10x10xf32>>, !fir.ref<!fir.array<10x10xf32>>) copyout_zero([[B]] : !fir.ref<!fir.array<10x10xf32>>) {
+! CHECK:        acc.yield
+! CHECK-NEXT: }{{$}}
+
+  !$acc serial create(a, b) create(zero: c)
+  !$acc end serial
+
+! CHECK:      acc.serial create([[A]], [[B]] : !fir.ref<!fir.array<10x10xf32>>, !fir.ref<!fir.array<10x10xf32>>) create_zero([[C]] : !fir.ref<!fir.array<10x10xf32>>) {
+! CHECK:        acc.yield
+! CHECK-NEXT: }{{$}}
+
+  !$acc serial no_create(a, b) create(zero: c)
+  !$acc end serial
+
+! CHECK:      acc.serial create_zero([[C]] : !fir.ref<!fir.array<10x10xf32>>) no_create([[A]], [[B]] : !fir.ref<!fir.array<10x10xf32>>, !fir.ref<!fir.array<10x10xf32>>) {
+! CHECK:        acc.yield
+! CHECK-NEXT: }{{$}}
+
+  !$acc serial present(a, b, c)
+  !$acc end serial
+
+! CHECK:      acc.serial present([[A]], [[B]], [[C]] : !fir.ref<!fir.array<10x10xf32>>, !fir.ref<!fir.array<10x10xf32>>, !fir.ref<!fir.array<10x10xf32>>) {
+! CHECK:        acc.yield
+! CHECK-NEXT: }{{$}}
+
+  !$acc serial deviceptr(a) deviceptr(c)
+  !$acc end serial
+
+! CHECK:      acc.serial deviceptr([[A]], [[C]] : !fir.ref<!fir.array<10x10xf32>>, !fir.ref<!fir.array<10x10xf32>>) {
+! CHECK:        acc.yield
+! CHECK-NEXT: }{{$}}
+
+  !$acc serial attach(d, e)
+  !$acc end serial
+
+! CHECK:      acc.serial attach([[D]], [[E]] : !fir.ref<!fir.box<!fir.ptr<f32>>>, !fir.ref<!fir.box<!fir.ptr<f32>>>) {
+! CHECK:        acc.yield
+! CHECK-NEXT: }{{$}}
+
+  !$acc serial private(a) firstprivate(b) private(c)
+  !$acc end serial
+
+! CHECK:      acc.serial firstprivate([[B]] : !fir.ref<!fir.array<10x10xf32>>) private([[A]], [[C]] : !fir.ref<!fir.array<10x10xf32>>, !fir.ref<!fir.array<10x10xf32>>) {
+! CHECK:        acc.yield
+! CHECK-NEXT: }{{$}}
+
+end subroutine