[flang-commits] [flang] [flang][OpenACC] Reject valued gang/worker/vector outside kernels (PR #218695)

via flang-commits flang-commits at lists.llvm.org
Tue Aug 25 07:26:17 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-flang-fir-hlfir

Author: Delaram Talaashrafi (delaram-talaashrafi)

<details>
<summary>Changes</summary>

`gang(num:)`, `worker(n)`, and `vector(n)` are only valid on a loop associated with kernels, and then only if that kernels construct does not already specify `num_gangs`, `num_workers`, or `vector_length`.

---

Patch is 30.64 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/218695.diff


5 Files Affected:

- (modified) flang/lib/Lower/OpenACC.cpp (+104) 
- (added) flang/test/Lower/OpenACC/acc-loop-level-clause-value.f90 (+395) 
- (modified) flang/test/Lower/OpenACC/acc-loop.f90 (-71) 
- (modified) flang/test/Lower/OpenACC/acc-parallel-loop.f90 (-79) 
- (modified) flang/test/Lower/OpenACC/acc-serial-loop.f90 (-77) 


``````````diff
diff --git a/flang/lib/Lower/OpenACC.cpp b/flang/lib/Lower/OpenACC.cpp
index 2e4b36178748b..cb85b63ad327c 100644
--- a/flang/lib/Lower/OpenACC.cpp
+++ b/flang/lib/Lower/OpenACC.cpp
@@ -46,6 +46,7 @@
 #include "mlir/IR/MLIRContext.h"
 #include "mlir/Support/LLVM.h"
 #include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/STLFunctionalExtras.h"
 #include "llvm/Frontend/OpenACC/ACC.h.inc"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Debug.h"
@@ -2353,6 +2354,61 @@ getAccLoopDoStmtEval(Fortran::lower::pft::Evaluation &eval) {
   return nullptr;
 }
 
+/// Reject a valued gang/worker/vector clause on a loop that is not associated
+/// with a kernels construct.
+static void checkLoopLevelClauseValueInKernels(
+    fir::FirOpBuilder &builder, mlir::Operation *parentCompute,
+    mlir::Location loc,
+    std::optional<mlir::acc::CombinedConstructsType> combinedConstructs,
+    llvm::StringRef clauseName) {
+  llvm::acc::Directive parentDir = llvm::acc::Directive::ACCD_loop;
+  if (combinedConstructs == mlir::acc::CombinedConstructsType::ParallelLoop)
+    parentDir = llvm::acc::Directive::ACCD_parallel_loop;
+  else if (combinedConstructs == mlir::acc::CombinedConstructsType::SerialLoop)
+    parentDir = llvm::acc::Directive::ACCD_serial_loop;
+  else if (mlir::isa_and_present<mlir::acc::ParallelOp>(parentCompute))
+    parentDir = llvm::acc::Directive::ACCD_parallel_loop;
+  else if (mlir::isa_and_present<mlir::acc::SerialOp>(parentCompute))
+    parentDir = llvm::acc::Directive::ACCD_serial_loop;
+  else if (mlir::acc::isAccRoutine(builder.getFunction().getOperation()))
+    parentDir = llvm::acc::Directive::ACCD_routine;
+
+  llvm::StringRef notAllowed =
+      parentDir == llvm::acc::Directive::ACCD_routine
+          ? "' not allowed in subprogram compiled with "
+          : "' not allowed in ";
+  fir::emitFatalError(
+      loc,
+      llvm::Twine("'") + clauseName + "(value)" + notAllowed +
+          Fortran::parser::ToUpperCaseLetters(
+              llvm::acc::getOpenACCDirectiveName(parentDir).str()) +
+          " directive",
+      /*genCrashDiag=*/false);
+}
+
+/// Reject a valued gang/worker/vector clause when the enclosing kernels
+/// construct already specifies the corresponding size clause.
+static void checkLoopLevelClauseConflictsWithKernels(
+    mlir::Operation *parentCompute, mlir::Location loc,
+    std::optional<mlir::acc::CombinedConstructsType> combinedConstructs,
+    llvm::StringRef loopClauseName, llvm::StringRef kernelsClauseName,
+    llvm::function_ref<bool(mlir::acc::KernelsOp)> hasKernelsClause) {
+  auto kernelsOp =
+      mlir::dyn_cast_if_present<mlir::acc::KernelsOp>(parentCompute);
+  if (!kernelsOp || !hasKernelsClause(kernelsOp))
+    return;
+
+  llvm::StringRef dirName =
+      combinedConstructs == mlir::acc::CombinedConstructsType::KernelsLoop
+          ? "KERNELS LOOP"
+          : "KERNELS";
+  fir::emitFatalError(loc,
+                      llvm::Twine("'") + loopClauseName +
+                          "(value)' not allowed in " + dirName +
+                          " region that has a " + kernelsClauseName + " clause",
+                      /*genCrashDiag=*/false);
+}
+
 static mlir::acc::LoopOp createLoopOp(
     Fortran::lower::AbstractConverter &converter,
     mlir::Location currentLocation,
@@ -2384,12 +2440,40 @@ static mlir::acc::LoopOp createLoopOp(
   crtDeviceTypes.push_back(mlir::acc::DeviceTypeAttr::get(
       builder.getContext(), mlir::acc::DeviceType::None));
 
+  // A valued gang/worker/vector clause is only allowed when the loop is
+  // associated with a kernels construct, and then only when the kernels
+  // construct does not already specify the corresponding size clause.
+  mlir::Operation *parentCompute =
+      mlir::acc::getEnclosingComputeOp(*builder.getBlock()->getParent());
+  bool isKernels =
+      mlir::isa_and_present<mlir::acc::KernelsOp>(parentCompute) ||
+      combinedConstructs == mlir::acc::CombinedConstructsType::KernelsLoop;
+
   for (const Fortran::parser::AccClause &clause : accClauseList.v) {
     mlir::Location clauseLocation = converter.genLocation(clause.source);
     if (const auto *gangClause =
             std::get_if<Fortran::parser::AccClause::Gang>(&clause.u)) {
       if (gangClause->v) {
         const Fortran::parser::AccGangArgList &x = *gangClause->v;
+        // Only the num argument is restricted to kernels. The static and dim
+        // arguments are allowed on any loop.
+        bool hasNumArg =
+            llvm::any_of(x.v, [](const Fortran::parser::AccGangArg &gangArg) {
+              return std::holds_alternative<Fortran::parser::AccGangArg::Num>(
+                  gangArg.u);
+            });
+        if (hasNumArg) {
+          if (!isKernels)
+            checkLoopLevelClauseValueInKernels(builder, parentCompute,
+                                               clauseLocation,
+                                               combinedConstructs, "Gang");
+          else
+            checkLoopLevelClauseConflictsWithKernels(
+                parentCompute, clauseLocation, combinedConstructs, "Gang",
+                "NUM_GANGS", [](mlir::acc::KernelsOp op) {
+                  return !op.getNumGangs().empty();
+                });
+        }
         mlir::SmallVector<mlir::Value> gangValues;
         mlir::SmallVector<mlir::Attribute> gangArgs;
         for (const Fortran::parser::AccGangArg &gangArg : x.v) {
@@ -2438,6 +2522,16 @@ static mlir::acc::LoopOp createLoopOp(
     } else if (const auto *workerClause =
                    std::get_if<Fortran::parser::AccClause::Worker>(&clause.u)) {
       if (workerClause->v) {
+        if (!isKernels)
+          checkLoopLevelClauseValueInKernels(builder, parentCompute,
+                                             clauseLocation, combinedConstructs,
+                                             "Worker");
+        else
+          checkLoopLevelClauseConflictsWithKernels(
+              parentCompute, clauseLocation, combinedConstructs, "Worker",
+              "NUM_WORKERS", [](mlir::acc::KernelsOp op) {
+                return !op.getNumWorkers().empty();
+              });
         mlir::Value workerNumValue = fir::getBase(converter.genExprValue(
             *Fortran::semantics::GetExpr(*workerClause->v), stmtCtx));
         for (auto crtDeviceTypeAttr : crtDeviceTypes) {
@@ -2451,6 +2545,16 @@ static mlir::acc::LoopOp createLoopOp(
     } else if (const auto *vectorClause =
                    std::get_if<Fortran::parser::AccClause::Vector>(&clause.u)) {
       if (vectorClause->v) {
+        if (!isKernels)
+          checkLoopLevelClauseValueInKernels(builder, parentCompute,
+                                             clauseLocation, combinedConstructs,
+                                             "Vector");
+        else
+          checkLoopLevelClauseConflictsWithKernels(
+              parentCompute, clauseLocation, combinedConstructs, "Vector",
+              "VECTOR_LENGTH", [](mlir::acc::KernelsOp op) {
+                return !op.getVectorLength().empty();
+              });
         mlir::Value vectorValue = fir::getBase(converter.genExprValue(
             *Fortran::semantics::GetExpr(*vectorClause->v), stmtCtx));
         for (auto crtDeviceTypeAttr : crtDeviceTypes) {
diff --git a/flang/test/Lower/OpenACC/acc-loop-level-clause-value.f90 b/flang/test/Lower/OpenACC/acc-loop-level-clause-value.f90
new file mode 100644
index 0000000000000..2c817e1ab308b
--- /dev/null
+++ b/flang/test/Lower/OpenACC/acc-loop-level-clause-value.f90
@@ -0,0 +1,395 @@
+! Valued gang/worker/vector on a loop are only allowed when the loop is
+! associated with kernels, and then only when that kernels construct does not
+! already specify the matching size clause.
+
+! RUN: split-file %s %t
+
+! Non-kernels: standalone loop
+! RUN: not bbc -fopenacc -emit-hlfir %t/loop-gang.f90 -o - 2>&1 | FileCheck %s --check-prefix=LOOP-GANG
+! RUN: not bbc -fopenacc -emit-hlfir %t/loop-worker.f90 -o - 2>&1 | FileCheck %s --check-prefix=LOOP-WORKER
+! RUN: not bbc -fopenacc -emit-hlfir %t/loop-vector.f90 -o - 2>&1 | FileCheck %s --check-prefix=LOOP-VECTOR
+
+! Non-kernels: combined constructs
+! RUN: not bbc -fopenacc -emit-hlfir %t/parallel-loop-gang.f90 -o - 2>&1 | FileCheck %s --check-prefix=PLOOP-GANG
+! RUN: not bbc -fopenacc -emit-hlfir %t/parallel-loop-worker.f90 -o - 2>&1 | FileCheck %s --check-prefix=PLOOP-WORKER
+! RUN: not bbc -fopenacc -emit-hlfir %t/parallel-loop-vector.f90 -o - 2>&1 | FileCheck %s --check-prefix=PLOOP-VECTOR
+! RUN: not bbc -fopenacc -emit-hlfir %t/serial-loop-gang.f90 -o - 2>&1 | FileCheck %s --check-prefix=SLOOP-GANG
+! RUN: not bbc -fopenacc -emit-hlfir %t/serial-loop-worker.f90 -o - 2>&1 | FileCheck %s --check-prefix=SLOOP-WORKER
+! RUN: not bbc -fopenacc -emit-hlfir %t/serial-loop-vector.f90 -o - 2>&1 | FileCheck %s --check-prefix=SLOOP-VECTOR
+
+! Non-kernels: nested loop inside a compute construct
+! RUN: not bbc -fopenacc -emit-hlfir %t/parallel-nested-gang.f90 -o - 2>&1 | FileCheck %s --check-prefix=PAR-GANG
+! RUN: not bbc -fopenacc -emit-hlfir %t/parallel-nested-worker.f90 -o - 2>&1 | FileCheck %s --check-prefix=PAR-WORKER
+! RUN: not bbc -fopenacc -emit-hlfir %t/parallel-nested-vector.f90 -o - 2>&1 | FileCheck %s --check-prefix=PAR-VECTOR
+! RUN: not bbc -fopenacc -emit-hlfir %t/serial-nested-gang.f90 -o - 2>&1 | FileCheck %s --check-prefix=SER-GANG
+! RUN: not bbc -fopenacc -emit-hlfir %t/serial-nested-worker.f90 -o - 2>&1 | FileCheck %s --check-prefix=SER-WORKER
+! RUN: not bbc -fopenacc -emit-hlfir %t/serial-nested-vector.f90 -o - 2>&1 | FileCheck %s --check-prefix=SER-VECTOR
+
+! Non-kernels: orphan loop in an acc routine
+! RUN: not bbc -fopenacc -emit-hlfir %t/routine-gang.f90 -o - 2>&1 | FileCheck %s --check-prefix=RTN-GANG
+! RUN: not bbc -fopenacc -emit-hlfir %t/routine-worker.f90 -o - 2>&1 | FileCheck %s --check-prefix=RTN-WORKER
+! RUN: not bbc -fopenacc -emit-hlfir %t/routine-vector.f90 -o - 2>&1 | FileCheck %s --check-prefix=RTN-VECTOR
+
+! Kernels with a conflicting size clause
+! RUN: not bbc -fopenacc -emit-hlfir %t/kernels-num-gangs.f90 -o - 2>&1 | FileCheck %s --check-prefix=K-NG
+! RUN: not bbc -fopenacc -emit-hlfir %t/kernels-num-workers.f90 -o - 2>&1 | FileCheck %s --check-prefix=K-NW
+! RUN: not bbc -fopenacc -emit-hlfir %t/kernels-vector-length.f90 -o - 2>&1 | FileCheck %s --check-prefix=K-VL
+! RUN: not bbc -fopenacc -emit-hlfir %t/kernels-loop-num-gangs.f90 -o - 2>&1 | FileCheck %s --check-prefix=KL-NG
+! RUN: not bbc -fopenacc -emit-hlfir %t/kernels-loop-num-workers.f90 -o - 2>&1 | FileCheck %s --check-prefix=KL-NW
+! RUN: not bbc -fopenacc -emit-hlfir %t/kernels-loop-vector-length.f90 -o - 2>&1 | FileCheck %s --check-prefix=KL-VL
+
+! Allowed: kernels without a conflicting size clause, and bare clauses
+! RUN: bbc -fopenacc -emit-hlfir %t/allowed.f90 -o - | FileCheck %s --check-prefix=OK
+
+! LOOP-GANG: 'Gang(value)' not allowed in LOOP directive
+! LOOP-WORKER: 'Worker(value)' not allowed in LOOP directive
+! LOOP-VECTOR: 'Vector(value)' not allowed in LOOP directive
+! PLOOP-GANG: 'Gang(value)' not allowed in PARALLEL LOOP directive
+! PLOOP-WORKER: 'Worker(value)' not allowed in PARALLEL LOOP directive
+! PLOOP-VECTOR: 'Vector(value)' not allowed in PARALLEL LOOP directive
+! SLOOP-GANG: 'Gang(value)' not allowed in SERIAL LOOP directive
+! SLOOP-WORKER: 'Worker(value)' not allowed in SERIAL LOOP directive
+! SLOOP-VECTOR: 'Vector(value)' not allowed in SERIAL LOOP directive
+! PAR-GANG: 'Gang(value)' not allowed in PARALLEL LOOP directive
+! PAR-WORKER: 'Worker(value)' not allowed in PARALLEL LOOP directive
+! PAR-VECTOR: 'Vector(value)' not allowed in PARALLEL LOOP directive
+! SER-GANG: 'Gang(value)' not allowed in SERIAL LOOP directive
+! SER-WORKER: 'Worker(value)' not allowed in SERIAL LOOP directive
+! SER-VECTOR: 'Vector(value)' not allowed in SERIAL LOOP directive
+! RTN-GANG: 'Gang(value)' not allowed in subprogram compiled with ROUTINE directive
+! RTN-WORKER: 'Worker(value)' not allowed in subprogram compiled with ROUTINE directive
+! RTN-VECTOR: 'Vector(value)' not allowed in subprogram compiled with ROUTINE directive
+! K-NG: 'Gang(value)' not allowed in KERNELS region that has a NUM_GANGS clause
+! K-NW: 'Worker(value)' not allowed in KERNELS region that has a NUM_WORKERS clause
+! K-VL: 'Vector(value)' not allowed in KERNELS region that has a VECTOR_LENGTH clause
+! KL-NG: 'Gang(value)' not allowed in KERNELS LOOP region that has a NUM_GANGS clause
+! KL-NW: 'Worker(value)' not allowed in KERNELS LOOP region that has a NUM_WORKERS clause
+! KL-VL: 'Vector(value)' not allowed in KERNELS LOOP region that has a VECTOR_LENGTH clause
+
+!--- loop-gang.f90
+subroutine loop_gang(a, n)
+  integer :: i, n
+  real :: a(n)
+  !$acc loop gang(8)
+  do i = 1, n
+    a(i) = a(i) + 1
+  end do
+end subroutine
+
+!--- loop-worker.f90
+subroutine loop_worker(a, n)
+  integer :: i, n
+  real :: a(n)
+  !$acc loop worker(128)
+  do i = 1, n
+    a(i) = a(i) + 1
+  end do
+end subroutine
+
+!--- loop-vector.f90
+subroutine loop_vector(a, n)
+  integer :: i, n
+  real :: a(n)
+  !$acc loop vector(128)
+  do i = 1, n
+    a(i) = a(i) + 1
+  end do
+end subroutine
+
+!--- parallel-loop-gang.f90
+subroutine parallel_loop_gang(a, n)
+  integer :: i, n
+  real :: a(n)
+  !$acc parallel loop gang(8)
+  do i = 1, n
+    a(i) = a(i) + 1
+  end do
+end subroutine
+
+!--- parallel-loop-worker.f90
+subroutine parallel_loop_worker(a, n)
+  integer :: i, n
+  real :: a(n)
+  !$acc parallel loop worker(128)
+  do i = 1, n
+    a(i) = a(i) + 1
+  end do
+end subroutine
+
+!--- parallel-loop-vector.f90
+subroutine parallel_loop_vector(a, n)
+  integer :: i, n
+  real :: a(n)
+  !$acc parallel loop vector(128)
+  do i = 1, n
+    a(i) = a(i) + 1
+  end do
+end subroutine
+
+!--- serial-loop-gang.f90
+subroutine serial_loop_gang(a, n)
+  integer :: i, n
+  real :: a(n)
+  !$acc serial loop gang(8)
+  do i = 1, n
+    a(i) = a(i) + 1
+  end do
+end subroutine
+
+!--- serial-loop-worker.f90
+subroutine serial_loop_worker(a, n)
+  integer :: i, n
+  real :: a(n)
+  !$acc serial loop worker(128)
+  do i = 1, n
+    a(i) = a(i) + 1
+  end do
+end subroutine
+
+!--- serial-loop-vector.f90
+subroutine serial_loop_vector(a, n)
+  integer :: i, n
+  real :: a(n)
+  !$acc serial loop vector(128)
+  do i = 1, n
+    a(i) = a(i) + 1
+  end do
+end subroutine
+
+!--- parallel-nested-gang.f90
+subroutine parallel_nested_gang(a, n)
+  integer :: i, n
+  real :: a(n)
+  !$acc parallel
+  !$acc loop gang(8)
+  do i = 1, n
+    a(i) = a(i) + 1
+  end do
+  !$acc end parallel
+end subroutine
+
+!--- parallel-nested-worker.f90
+subroutine parallel_nested_worker(a, n)
+  integer :: i, n
+  real :: a(n)
+  !$acc parallel
+  !$acc loop worker(128)
+  do i = 1, n
+    a(i) = a(i) + 1
+  end do
+  !$acc end parallel
+end subroutine
+
+!--- parallel-nested-vector.f90
+subroutine parallel_nested_vector(a, n)
+  integer :: i, n
+  real :: a(n)
+  !$acc parallel
+  !$acc loop vector(128)
+  do i = 1, n
+    a(i) = a(i) + 1
+  end do
+  !$acc end parallel
+end subroutine
+
+!--- serial-nested-gang.f90
+subroutine serial_nested_gang(a, n)
+  integer :: i, n
+  real :: a(n)
+  !$acc serial
+  !$acc loop gang(8)
+  do i = 1, n
+    a(i) = a(i) + 1
+  end do
+  !$acc end serial
+end subroutine
+
+!--- serial-nested-worker.f90
+subroutine serial_nested_worker(a, n)
+  integer :: i, n
+  real :: a(n)
+  !$acc serial
+  !$acc loop worker(128)
+  do i = 1, n
+    a(i) = a(i) + 1
+  end do
+  !$acc end serial
+end subroutine
+
+!--- serial-nested-vector.f90
+subroutine serial_nested_vector(a, n)
+  integer :: i, n
+  real :: a(n)
+  !$acc serial
+  !$acc loop vector(128)
+  do i = 1, n
+    a(i) = a(i) + 1
+  end do
+  !$acc end serial
+end subroutine
+
+!--- routine-gang.f90
+subroutine routine_gang(a, n)
+  integer :: i, n
+  real :: a(n)
+  !$acc routine
+  !$acc loop gang(8)
+  do i = 1, n
+    a(i) = a(i) + 1
+  end do
+end subroutine
+
+!--- routine-worker.f90
+subroutine routine_worker(a, n)
+  integer :: i, n
+  real :: a(n)
+  !$acc routine
+  !$acc loop worker(128)
+  do i = 1, n
+    a(i) = a(i) + 1
+  end do
+end subroutine
+
+!--- routine-vector.f90
+subroutine routine_vector(a, n)
+  integer :: i, n
+  real :: a(n)
+  !$acc routine
+  !$acc loop vector(128)
+  do i = 1, n
+    a(i) = a(i) + 1
+  end do
+end subroutine
+
+!--- kernels-num-gangs.f90
+subroutine kernels_num_gangs(a, n)
+  integer :: i, n
+  real :: a(n)
+  !$acc kernels num_gangs(8)
+  !$acc loop gang(8)
+  do i = 1, n
+    a(i) = a(i) + 1
+  end do
+  !$acc end kernels
+end subroutine
+
+!--- kernels-num-workers.f90
+subroutine kernels_num_workers(a, n)
+  integer :: i, n
+  real :: a(n)
+  !$acc kernels num_workers(128)
+  !$acc loop worker(128)
+  do i = 1, n
+    a(i) = a(i) + 1
+  end do
+  !$acc end kernels
+end subroutine
+
+!--- kernels-vector-length.f90
+subroutine kernels_vector_length(a, n)
+  integer :: i, n
+  real :: a(n)
+  !$acc kernels vector_length(128)
+  !$acc loop vector(128)
+  do i = 1, n
+    a(i) = a(i) + 1
+  end do
+  !$acc end kernels
+end subroutine
+
+!--- kernels-loop-num-gangs.f90
+subroutine kernels_loop_num_gangs(a, n)
+  integer :: i, n
+  real :: a(n)
+  !$acc kernels loop num_gangs(8) gang(8)
+  do i = 1, n
+    a(i) = a(i) + 1
+  end do
+end subroutine
+
+!--- kernels-loop-num-workers.f90
+subroutine kernels_loop_num_workers(a, n)
+  integer :: i, n
+  real :: a(n)
+  !$acc kernels loop num_workers(128) worker(128)
+  do i = 1, n
+    a(i) = a(i) + 1
+  end do
+end subroutine
+
+!--- kernels-loop-vector-length.f90
+subroutine kernels_loop_vector_length(a, n)
+  integer :: i, n
+  real :: a(n)
+  !$acc kernels loop vector_length(128) vector(128)
+  do i = 1, n
+    a(i) = a(i) + 1
+  end do
+end subroutine
+
+!--- allowed.f90
+subroutine allowed_kernels_valued(a, n)
+  integer :: i, n
+  real :: a(n)
+  !$acc kernels
+  !$acc loop gang(8)
+  do i = 1, n
+    a(i) = a(i) + 1
+  end do
+  !$acc loop worker(128)
+  do i = 1, n
+    a(i) = a(i) + 1
+  end do
+  !$acc loop vector(128)
+  do i = 1, n
+    a(i) = a(i) + 1
+  end do
+  !$acc end kernels
+end subroutine
+! OK-LABEL: func.func @_QPallowed_kernels_valued
+! OK: acc.kernels
+! OK: acc.loop {{.*}}gang({num=%{{.*}} : i32})
+! OK: acc.loop {{.*}}worker(%{{.*}} : i32)
+! OK: acc.loop {{.*}}vector(%{{.*}} : i32)
+
+subroutine allowed_kernels_loop_valued(a, n)
+  integer :: i, n
+  real :: a(n)
+  !$acc kernels loop gang(8)
+  do i = 1, n
+    a(i) = a(i) + 1
+  end do
+  !$acc kernels loop worker(128)
+  do i = 1, n
+    a(i) = a(i) + 1
+  end do
+  !$acc kernels loop vector(128)
+  do i = 1, n
+    a(i) = a(i) + 1
+  end do
+end subroutine
+! OK-LABEL: func.func @_QPallowed_kernels_loop_valued
+! OK: acc.kernels {{.*}}combined
+! OK: acc.loop {{.*}}gang({num=%{{.*}} : i32})
+! OK: acc.loop {{.*}}worker(%{{.*}} : i32)
+! OK: acc.loop {{.*}}vector(%{{.*}} : i32)
+
+subroutine allowed_bare_and_size_clause(a, n)
+  integer :: i, n
+  real :: a(n)
+  !$acc parallel loop gang worker vector
+  do i = 1, n
+    a(i) = a(i) + 1
+  end do
+  !$acc kernels num_gangs(8) num_workers(128) vector_length(128)
+  !$acc loop gang worker vector
+  do i = 1, n
+    a(i) = a(i) + 1
+  end do
+  !$acc end kernels
+end subroutine
+! OK-LABEL: func.func @_QPallowed_bare_and_size_clause
+! OK: acc.parallel
+! OK: acc.loop {{.*}}gang
+! OK: acc.kernels {{.*}}num_gangs
+! OK: acc.loop {{.*}}gang
diff --git a/flang/test/Lower/OpenACC/acc-loop.f90 b/flang/test/Lower/OpenACC/acc-loop.f90
index 2a00f55b08751..3978f29dbf1fc 100644
--- a/flang/test/Lower/OpenACC/acc-loop.f90
+++ b/flang/test/Lower/OpenACC/acc-loop.f90
@@ -70,38 +70,6 @@ program acc_loop
 ! CHECK:      %[[PRIVATE_I:.*]] = acc.private varPtr(%{{.*}} : !fir.ref<i32>) recipe(@privatization_ref_i32) implicit(true) name("i") -> !fir.ref<i32>
 ! CHECK:      acc.loop gang private(%[[PRIVATE_I]] : !fir.ref<i32>) control(%arg0 : i32) = (%{{.*}} : i32) to (%{{.*}} : i32) step (%{{.*}} : i32) {
 ! CHECK:        acc.yield
-! CHECK-NEXT: } inclusiveUpperbound(array<i1: true>) independent
-
-  !$acc loop gang(num: 8)
-  DO i = 1, n
-    a(i) = b(i)
-  END DO
-
-! CHECK:      [[GANGNUM1:%.*]] = arith.constant 8 : i32
-! CHECK:      %[[PRIVATE_I:.*]] = acc.private varPtr(%{{.*}} : !fir.ref<i32>) recipe(@privatization_ref_i32) implicit(true) name("i") -> !fir.ref<i32>
-! CHECK:      acc.loop gang({num=[[GANGNUM1]] : i32}) private(%[[PRIVATE_I...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/218695


More information about the flang-commits mailing list