[flang-commits] [flang] [flang][OpenACC] Allow data action and data-sharing clause overlap (PR #218588)

via flang-commits flang-commits at lists.llvm.org
Mon Aug 24 22:58:37 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-flang-semantics

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

Author: Andre Kuhlenschmidt (akuhlens)

<details>
<summary>Changes</summary>

The changes I made in https://github.com/llvm/llvm-project/pull/211606 disallowed multiple different data actions clauses to occur on the same variable in the same construct. This PR fixes that mistake reducing the only restriction to multiple different data sharing clauses (and the reduction clause) can not be placed on the same object in the same construct.

---
Full diff: https://github.com/llvm/llvm-project/pull/218588.diff


6 Files Affected:

- (modified) flang/lib/Semantics/resolve-directives.cpp (+4-49) 
- (modified) flang/test/Lower/OpenACC/acc-copy-reduction.f90 (+12-6) 
- (modified) flang/test/Semantics/OpenACC/acc-copy-reduction.f90 (+62) 
- (added) flang/test/Semantics/OpenACC/acc-data-action-overlap.f90 (+94) 
- (modified) flang/test/Semantics/OpenACC/acc-dataclause-dedup.f90 (+24) 
- (modified) flang/test/Semantics/OpenACC/acc-default-none-arrays.f90 (+4-8) 


``````````diff
diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index 55e10453e20fc..7c58b05684e2b 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -459,7 +459,6 @@ class AccAttributeVisitor {
       Symbol::Flag, DesignatorPath,
       const parser::AccObject *occurrence = nullptr,
       bool warnSameKindDuplicate = true);
-  bool AllowsExplicitCopyReductionPair() const;
   void AllowOnlyArrayAndSubArray(const parser::AccObjectList &objectList);
   void DoNotAllowAssumedSizedArray(const parser::AccObjectList &objectList);
   void AllowOnlyVariable(const parser::AccObject &object);
@@ -2260,9 +2259,8 @@ void AccAttributeVisitor::ResolveAccObject(
           },
           [&](const parser::Name &name) { // common block
             if (auto *symbol{ResolveAccCommonBlockName(&name)}) {
-              if (!CheckClauseConsistencyInCurrentConstruct(name,
-                      Symbol::Flag::AccCommonBlock,
-                      MakeBaseDesignatorPath(*symbol))) {
+              if (!CheckClauseConsistencyInCurrentConstruct(name, accFlag,
+                      MakeBaseDesignatorPath(*symbol), &accObject)) {
                 return;
               }
               for (auto &object : symbol->get<CommonBlockDetails>().objects()) {
@@ -2304,16 +2302,6 @@ Symbol *AccAttributeVisitor::DeclareOrMarkOtherAccessEntity(
   return &object;
 }
 
-bool AccAttributeVisitor::AllowsExplicitCopyReductionPair() const {
-  switch (GetContext().directive) {
-  case llvm::acc::Directive::ACCD_parallel:
-  case llvm::acc::Directive::ACCD_serial:
-    return true;
-  default:
-    return false;
-  }
-}
-
 bool AccAttributeVisitor::CheckClauseConsistencyInCurrentConstruct(
     const parser::Name &name, Symbol::Flag accFlag, DesignatorPath designator,
     const parser::AccObject *occurrence, bool warnSameKindDuplicate) {
@@ -2332,39 +2320,7 @@ bool AccAttributeVisitor::CheckClauseConsistencyInCurrentConstruct(
       continue;
     }
 
-    if (entry.flag == Symbol::Flag::AccCommonBlock ||
-        accFlag == Symbol::Flag::AccCommonBlock) {
-      auto &message{context_.Say(source,
-          "'%s' appears in more than one data-sharing clause on the same OpenACC directive"_err_en_US,
-          displayName)};
-      if (entry.occurrence) {
-        message.Attach(parser::FindSourceLocation(*entry.occurrence),
-            "previous data-sharing object appears here"_en_US);
-      }
-      return false;
-    }
-
-    const bool isExplicitCopyReductionPair{AllowsExplicitCopyReductionPair() &&
-        relation == DesignatorRelation::Equal &&
-        ((entry.flag == Symbol::Flag::AccCopy &&
-             accFlag == Symbol::Flag::AccReduction) ||
-            (entry.flag == Symbol::Flag::AccReduction &&
-                accFlag == Symbol::Flag::AccCopy))};
-    if (isExplicitCopyReductionPair) {
-      if (entry.flag == Symbol::Flag::AccCopy) {
-        if (entry.occurrence) {
-          context_.MarkAccObjectDuplicate(entry.occurrence);
-        }
-        iter = objectsWithDSA.erase(iter);
-        continue;
-      }
-      if (occurrence) {
-        context_.MarkAccObjectDuplicate(occurrence);
-      }
-      return false;
-    }
-
-    if (!(dataSharingAttributeFlags.test(entry.flag) ||
+    if (!(dataSharingAttributeFlags.test(entry.flag) &&
             dataSharingAttributeFlags.test(accFlag))) {
       ++iter;
       continue;
@@ -2372,8 +2328,7 @@ bool AccAttributeVisitor::CheckClauseConsistencyInCurrentConstruct(
 
     // TODO: Record the reduction operator in AccDataSharingEntry so compatible
     // reductions can use the ordinary same-kind duplicate handling. Also handle
-    // copy/reduction pairs on combined constructs and private/reduction
-    // interactions on loop constructs.
+    // private/reduction interactions on loop constructs.
     if (entry.flag != accFlag || accFlag == Symbol::Flag::AccReduction) {
       auto &message{context_.Say(source,
           "'%s' appears in more than one data-sharing clause on the same OpenACC directive"_err_en_US,
diff --git a/flang/test/Lower/OpenACC/acc-copy-reduction.f90 b/flang/test/Lower/OpenACC/acc-copy-reduction.f90
index 040ecad73d979..5266adf8fc1ee 100644
--- a/flang/test/Lower/OpenACC/acc-copy-reduction.f90
+++ b/flang/test/Lower/OpenACC/acc-copy-reduction.f90
@@ -8,9 +8,13 @@ subroutine copy_then_reduction()
 end subroutine
 
 ! CHECK-LABEL: func.func @_QPcopy_then_reduction()
-! CHECK: acc.reduction varPtr({{.*}}) recipe({{.*}}) name("x") -> !fir.ref<i32>
-! CHECK-NOT: acc.copy
-! CHECK: acc.parallel reduction({{.*}}) {
+! CHECK: %[[COPY1:.*]] = acc.copyin varPtr({{.*}}) dataClause(acc_copy) name("x") -> !fir.ref<i32>
+! CHECK: %[[REDUCTION1:.*]] = acc.reduction varPtr({{.*}}) recipe({{.*}}) name("x") -> !fir.ref<i32>
+! CHECK: acc.parallel dataOperands(%[[COPY1]] : !fir.ref<i32>) reduction(%[[REDUCTION1]] : !fir.ref<i32>) {
+! TODO: The region body uses the first mapping for x, making lowering depend on
+! clause order. The reduction mapping should take priority in both cases.
+! CHECK: hlfir.declare %[[COPY1]]
+! CHECK: acc.copyout accPtr(%[[COPY1]] : !fir.ref<i32>)
 
 subroutine reduction_then_copy()
   integer :: x
@@ -20,6 +24,8 @@ subroutine reduction_then_copy()
 end subroutine
 
 ! CHECK-LABEL: func.func @_QPreduction_then_copy()
-! CHECK: acc.reduction varPtr({{.*}}) recipe({{.*}}) name("x") -> !fir.ref<i32>
-! CHECK-NOT: acc.copy
-! CHECK: acc.parallel reduction({{.*}}) {
+! CHECK: %[[REDUCTION2:.*]] = acc.reduction varPtr({{.*}}) recipe({{.*}}) name("x") -> !fir.ref<i32>
+! CHECK: %[[COPY2:.*]] = acc.copyin varPtr({{.*}}) dataClause(acc_copy) name("x") -> !fir.ref<i32>
+! CHECK: acc.parallel dataOperands(%[[COPY2]] : !fir.ref<i32>) reduction(%[[REDUCTION2]] : !fir.ref<i32>) {
+! CHECK: hlfir.declare %[[REDUCTION2]]
+! CHECK: acc.copyout accPtr(%[[COPY2]] : !fir.ref<i32>)
diff --git a/flang/test/Semantics/OpenACC/acc-copy-reduction.f90 b/flang/test/Semantics/OpenACC/acc-copy-reduction.f90
index a156ba8759cec..585e37b7e0ff0 100644
--- a/flang/test/Semantics/OpenACC/acc-copy-reduction.f90
+++ b/flang/test/Semantics/OpenACC/acc-copy-reduction.f90
@@ -13,3 +13,65 @@ subroutine reduction_then_copy()
   x = x + 1
   !$acc end parallel
 end subroutine
+
+subroutine parallel_data_clauses_with_reduction()
+  integer :: copy_var, copyin_var, copyout_var, create_var, no_create_var
+  integer :: present_var
+  !$acc parallel copy(copy_var) copyin(copyin_var) &
+  !$acc& copyout(copyout_var) create(create_var) &
+  !$acc& no_create(no_create_var) present(present_var) &
+  !$acc& reduction(+:copy_var, copyin_var, copyout_var, create_var, &
+  !$acc& no_create_var, present_var)
+  copy_var = copy_var + 1
+  copyin_var = copyin_var + 1
+  copyout_var = copyout_var + 1
+  create_var = create_var + 1
+  no_create_var = no_create_var + 1
+  present_var = present_var + 1
+  !$acc end parallel
+end subroutine
+
+subroutine serial_reduction_then_data_clauses()
+  integer :: copy_var, present_var
+  !$acc serial reduction(+:copy_var, present_var) &
+  !$acc& copy(copy_var) present(present_var)
+  copy_var = copy_var + 1
+  present_var = present_var + 1
+  !$acc end serial
+end subroutine
+
+subroutine combined_copy_reduction()
+  integer :: i, x
+  !$acc parallel loop copy(x) reduction(+:x)
+  do i = 1, 10
+    x = x + i
+  end do
+
+  !$acc serial loop reduction(+:x) copy(x)
+  do i = 1, 10
+    x = x + i
+  end do
+
+  !$acc kernels loop copy(x) reduction(+:x)
+  do i = 1, 10
+    x = x + i
+  end do
+end subroutine
+
+subroutine combined_present_reduction()
+  integer :: i, x
+  !$acc parallel loop present(x) reduction(+:x)
+  do i = 1, 10
+    x = x + i
+  end do
+
+  !$acc serial loop reduction(+:x) present(x)
+  do i = 1, 10
+    x = x + i
+  end do
+
+  !$acc kernels loop present(x) reduction(+:x)
+  do i = 1, 10
+    x = x + i
+  end do
+end subroutine
diff --git a/flang/test/Semantics/OpenACC/acc-data-action-overlap.f90 b/flang/test/Semantics/OpenACC/acc-data-action-overlap.f90
new file mode 100644
index 0000000000000..7d0833e401462
--- /dev/null
+++ b/flang/test/Semantics/OpenACC/acc-data-action-overlap.f90
@@ -0,0 +1,94 @@
+! RUN: %python %S/../test_errors.py %s %flang -fopenacc
+
+! Data-action clauses may overlap data-sharing clauses. Only two overlapping
+! data-sharing clauses conflict.
+
+subroutine data_actions_then_private(deviceptr_var)
+  integer :: deviceptr_var
+  integer :: copy_var, copyin_var, copyout_var, create_var, no_create_var
+  integer :: present_var
+  integer, pointer :: attach_var
+  !$acc parallel copy(copy_var) copyin(copyin_var) copyout(copyout_var) &
+  !$acc& create(create_var) no_create(no_create_var) present(present_var) &
+  !$acc& deviceptr(deviceptr_var) attach(attach_var) &
+  !$acc& private(copy_var, copyin_var, copyout_var, create_var, &
+  !$acc& no_create_var, present_var, deviceptr_var, attach_var)
+  copy_var = 1
+  !$acc end parallel
+end subroutine
+
+subroutine firstprivate_then_data_actions(deviceptr_var)
+  integer :: deviceptr_var
+  integer :: copy_var, copyin_var, copyout_var, create_var, no_create_var
+  integer :: present_var
+  integer, pointer :: attach_var
+  !$acc serial firstprivate(copy_var, copyin_var, copyout_var, create_var, &
+  !$acc& no_create_var, present_var, deviceptr_var, attach_var) &
+  !$acc& copy(copy_var) copyin(copyin_var) copyout(copyout_var) &
+  !$acc& create(create_var) no_create(no_create_var) present(present_var) &
+  !$acc& deviceptr(deviceptr_var) attach(attach_var)
+  copy_var = 1
+  !$acc end serial
+end subroutine
+
+subroutine reduction_with_data_actions(deviceptr_var)
+  integer :: deviceptr_var
+  integer :: copy_var, copyin_var, copyout_var, create_var, no_create_var
+  integer :: present_var
+  integer, allocatable :: attach_var
+  !$acc parallel reduction(+:copy_var, copyin_var, copyout_var, create_var, &
+  !$acc& no_create_var, present_var, deviceptr_var, attach_var) &
+  !$acc& copy(copy_var) copyin(copyin_var) copyout(copyout_var) &
+  !$acc& create(create_var) no_create(no_create_var) present(present_var) &
+  !$acc& deviceptr(deviceptr_var) attach(attach_var)
+  copy_var = copy_var + 1
+  !$acc end parallel
+end subroutine
+
+subroutine overlapping_data_actions(deviceptr_var)
+  integer :: deviceptr_var
+  integer :: x
+  integer, pointer :: p
+  !$acc kernels copy(x) copyin(x) copyout(x) create(x) no_create(x) present(x)
+  x = 1
+  !$acc end kernels
+
+  !$acc kernels deviceptr(deviceptr_var) copy(deviceptr_var)
+  deviceptr_var = 1
+  !$acc end kernels
+
+  !$acc kernels attach(p) copy(p) present(p)
+  p = 1
+  !$acc end kernels
+end subroutine
+
+subroutine combined_data_action_private()
+  integer :: i, x
+  !$acc parallel loop copy(x) private(x)
+  do i = 1, 10
+    x = i
+  end do
+
+  !$acc serial loop private(x) present(x)
+  do i = 1, 10
+    x = i
+  end do
+
+  !$acc kernels loop create(x) private(x)
+  do i = 1, 10
+    x = i
+  end do
+end subroutine
+
+subroutine common_block_data_action_private()
+  integer :: a, b
+  common /overlap_common/ a, b
+  !$acc declare link(/overlap_common/)
+  !$acc parallel copy(/overlap_common/) private(/overlap_common/)
+  a = 1
+  !$acc end parallel
+
+  !$acc serial firstprivate(/overlap_common/) copyin(/overlap_common/)
+  b = 1
+  !$acc end serial
+end subroutine
diff --git a/flang/test/Semantics/OpenACC/acc-dataclause-dedup.f90 b/flang/test/Semantics/OpenACC/acc-dataclause-dedup.f90
index 3fb4b42e52eb9..143f99f5d34b4 100644
--- a/flang/test/Semantics/OpenACC/acc-dataclause-dedup.f90
+++ b/flang/test/Semantics/OpenACC/acc-dataclause-dedup.f90
@@ -64,6 +64,30 @@ program test_dataclause_dedup
   do i = 1, 10
   end do
 
+  ! A reduction still conflicts with explicit privatization on the same
+  ! directive.
+  !ERROR: 'x' appears in more than one data-sharing clause on the same OpenACC directive
+  !$acc parallel private(x) reduction(+:x)
+  x = x + 1
+  !$acc end parallel
+
+  !ERROR: 'x' appears in more than one data-sharing clause on the same OpenACC directive
+  !$acc serial firstprivate(x) reduction(+:x)
+  x = x + 1
+  !$acc end serial
+
+  !ERROR: 'x' appears in more than one data-sharing clause on the same OpenACC directive
+  !$acc parallel loop private(x) reduction(+:x)
+  do i = 1, 10
+    x = x + i
+  end do
+
+  !ERROR: 'x' appears in more than one data-sharing clause on the same OpenACC directive
+  !$acc serial loop firstprivate(x) reduction(+:x)
+  do i = 1, 10
+    x = x + i
+  end do
+
   ! Reduction is excluded from the benign case: same-flag duplicates may
   ! differ in operator, which is a real conflict.
   !ERROR: 'x' appears in more than one data-sharing clause on the same OpenACC directive
diff --git a/flang/test/Semantics/OpenACC/acc-default-none-arrays.f90 b/flang/test/Semantics/OpenACC/acc-default-none-arrays.f90
index e64c88c374aab..df990f4f58f57 100644
--- a/flang/test/Semantics/OpenACC/acc-default-none-arrays.f90
+++ b/flang/test/Semantics/OpenACC/acc-default-none-arrays.f90
@@ -1,5 +1,4 @@
 ! RUN: %python %S/../test_errors.py %s %flang -fopenacc -fno-openacc-default-none-scalars-strict -Wno-openacc-default-none-scalars-strict
-! RUN: not %flang_fc1 -fopenacc -fno-openacc-default-none-scalars-strict -Wno-openacc-default-none-scalars-strict %s 2>&1 | FileCheck %s --check-prefix=CHECK-LOC
 
 ! Verify that array sections explicitly listed in OpenACC data clauses are
 ! correctly registered as having a DSA, so DEFAULT(NONE) uses path containment
@@ -201,25 +200,22 @@ subroutine test_unresolved_clause_objects()
   !$acc end parallel
 end subroutine
 
-! 9. Same array section in conflicting private and copy clauses.
+! 9. The same array section may appear in a data-action clause and a
+! data-sharing clause.
 subroutine test_cross_kind_sections(n)
   implicit none
   integer, intent(in) :: n
   real :: a(n)
   integer :: i
-  !ERROR: 'a(1:n)' appears in more than one data-sharing clause on the same OpenACC directive
   !$acc parallel loop default(none) copy(a(1:n)) private(a(1:n))
-  ! CHECK-LOC: error: 'a(1:n)' appears in more than one data-sharing clause on the same OpenACC directive
-  ! CHECK-LOC: previous data-sharing object appears here
   do i = 1, n
     a(i) = 0.0
   end do
   !$acc end parallel loop
 end subroutine
 
-! 10. Different sections of the same array in conflicting copy and private clauses.
-! TODO: cross-kind detection for array sections is not implemented; no error
-!       produced for 'a' appearing in both copy and private.
+! 10. Different sections may likewise appear in data-action and data-sharing
+! clauses.
 subroutine test_cross_kind_sections2(n)
   implicit none
   integer, intent(in) :: n

``````````

</details>


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


More information about the flang-commits mailing list