[flang-commits] [flang] [flang][acc] Fix cache directive with mapped component (PR #179335)
via flang-commits
flang-commits at lists.llvm.org
Tue Feb 3 01:46:59 PST 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-openacc
Author: None (khaki3)
<details>
<summary>Changes</summary>
When a derived type component is mapped via copyin (e.g.,
`copyin(data%A(...))`), the base address inside the parallel region
comes from the mapped address, not from an hlfir.designate op.
Handle this case by conditionally extracting shape/typeparams/attrs
only when the base is a `DesignateOp`.
---
Full diff: https://github.com/llvm/llvm-project/pull/179335.diff
2 Files Affected:
- (modified) flang/lib/Lower/OpenACC.cpp (+12-6)
- (modified) flang/test/Lower/OpenACC/acc-cache.f90 (+104)
``````````diff
diff --git a/flang/lib/Lower/OpenACC.cpp b/flang/lib/Lower/OpenACC.cpp
index 183f9e717532a..058c3ea2e533d 100644
--- a/flang/lib/Lower/OpenACC.cpp
+++ b/flang/lib/Lower/OpenACC.cpp
@@ -4304,20 +4304,26 @@ genACC(Fortran::lower::AbstractConverter &converter,
fir::substBase(hostExv, cacheOp.getAccVar());
converter.bindSymbol(symbol, cacheExv);
} else {
- // Must be a derived type component reference.
+ // Derived type component reference.
assert(designator && "expected designator for non-symbol cache operand");
std::optional<Fortran::evaluate::Component> componentRef =
extractComponentFromDesignator(designator);
assert(componentRef &&
"expected component reference for derived type cache operand");
- // Component references are lowered to designate operations.
- auto designate = base.getDefiningOp<hlfir::DesignateOp>();
- assert(designate && "expected designate op for component reference");
+ // When component is mapped via a data clause, base may be a declare op
+ // instead of a designate op.
+ auto varIface = base.getDefiningOp<fir::FortranVariableOpInterface>();
+ assert(varIface &&
+ "expected FortranVariableOpInterface for component reference");
+ fir::FortranVariableFlagsAttr attrs;
+ if (auto fortranAttrs = varIface.getFortranAttrs())
+ attrs = fir::FortranVariableFlagsAttr::get(builder.getContext(),
+ *fortranAttrs);
auto declareOp = hlfir::DeclareOp::create(
builder, operandLocation, cacheOp.getAccVar(), asFortran.str(),
- designate.getShape(), designate.getTypeparams(),
+ varIface.getShape(), varIface.getExplicitTypeParams(),
/*dummyScope=*/nullptr, /*storage=*/nullptr,
- /*storageOffset=*/0, designate.getFortranAttrsAttr());
+ /*storageOffset=*/0, attrs);
converter.getSymbolMap().addComponentOverride(*componentRef, declareOp);
}
}
diff --git a/flang/test/Lower/OpenACC/acc-cache.f90 b/flang/test/Lower/OpenACC/acc-cache.f90
index 22dd0a84aee8a..36874d3c21cdb 100644
--- a/flang/test/Lower/OpenACC/acc-cache.f90
+++ b/flang/test/Lower/OpenACC/acc-cache.f90
@@ -638,6 +638,110 @@ subroutine test_cache_nested_derived_type()
! CHECK: acc.yield
end subroutine
+! Test cache with allocatable component in combined construct
+! CHECK-LABEL: func.func @_QPtest_cache_combined_allocatable(
+subroutine test_cache_combined_allocatable(data, C, M)
+ type :: dt
+ real, dimension(:), allocatable :: A
+ end type
+
+ type(dt), intent(inout) :: data
+ real, dimension(:), intent(out) :: C
+ integer, intent(in) :: M
+ integer :: i
+
+ !$acc parallel loop gang vector copyin(data, data%A(-3:M+4)) copyout(C(1:M))
+ do i = 1, M
+ !$acc cache(data%A(i-4:i+4))
+ C(i) = data%A(i)
+ end do
+
+! CHECK: acc.parallel {{.*}} {
+! CHECK: acc.loop
+! CHECK: acc.cache varPtr(%{{.*}}) bounds(%{{.*}}) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>> {name = "data%a(i-4_4:i+4_4)", structured = false}
+! CHECK: hlfir.declare %{{.*}} {{{.*}}uniq_name = "data%a(i-4_4:i+4_4)"}
+! CHECK: acc.yield
+end subroutine
+
+! Test cache with copy of whole struct (not explicit component copyin)
+! CHECK-LABEL: func.func @_QPtest_cache_parallel_copy_struct(
+subroutine test_cache_parallel_copy_struct(data, M)
+ type :: dt
+ real, dimension(:), allocatable :: A
+ end type
+
+ type(dt), intent(inout) :: data
+ integer, intent(in) :: M
+ real :: r
+ integer :: i
+
+ !$acc parallel loop copy(data)
+ do i = 1, M
+ !$acc cache(data%A(i))
+ r = data%A(i)
+ end do
+
+! CHECK: acc.parallel {{.*}} {
+! CHECK: acc.loop
+! CHECK: acc.cache varPtr(%{{.*}}) bounds(%{{.*}}) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>> {name = "data%a(i)", structured = false}
+! CHECK: hlfir.declare %{{.*}} {{{.*}}uniq_name = "data%a(i)"}
+! CHECK: acc.yield
+end subroutine
+
+! Test cache with nested derived type in parallel loop with copyin
+! CHECK-LABEL: func.func @_QPtest_cache_nested_parallel(
+subroutine test_cache_nested_parallel(obj, N)
+ type :: inner
+ real, dimension(:), allocatable :: arr
+ end type
+
+ type :: outer
+ type(inner) :: in
+ end type
+
+ type(outer), intent(inout) :: obj
+ integer, intent(in) :: N
+ real :: r
+ integer :: i
+
+ !$acc parallel loop copyin(obj%in%arr(1:N))
+ do i = 1, N
+ !$acc cache(obj%in%arr(i))
+ r = obj%in%arr(i)
+ end do
+
+! CHECK: acc.parallel {{.*}} {
+! CHECK: acc.loop
+! CHECK: acc.cache varPtr(%{{.*}}) bounds(%{{.*}}) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>> {name = "obj%in%arr(i)", structured = false}
+! CHECK: hlfir.declare %{{.*}} {{{.*}}uniq_name = "obj%in%arr(i)"}
+! CHECK: acc.yield
+end subroutine
+
+! Test cache with explicit shape component in parallel loop with copyin
+! CHECK-LABEL: func.func @_QPtest_cache_explicit_shape_comp(
+subroutine test_cache_explicit_shape_comp(data, C, M)
+ type :: dt
+ real, dimension(10) :: A
+ end type
+
+ type(dt), intent(inout) :: data
+ real, dimension(:), intent(out) :: C
+ integer, intent(in) :: M
+ integer :: i
+
+ !$acc parallel loop gang vector copyin(data, data%A(1:M)) copyout(C(1:M))
+ do i = 1, M
+ !$acc cache(data%A(i:i+4))
+ C(i) = data%A(i)
+ end do
+
+! CHECK: acc.parallel {{.*}} {
+! CHECK: acc.loop
+! CHECK: acc.cache varPtr(%{{.*}}) bounds(%{{.*}}) -> !fir.ref<!fir.array<10xf32>> {name = "data%a(i:i+4_4)", structured = false}
+! CHECK: hlfir.declare %{{.*}}(%{{.*}}) {uniq_name = "data%a(i:i+4_4)"}
+! CHECK: acc.yield
+end subroutine
+
! Test cache with temporary in designator bounds - verifies local statement context
! doesn't cause issues with temporary cleanup
! CHECK-LABEL: func.func @_QPtest_cache_temp_in_designator(
``````````
</details>
https://github.com/llvm/llvm-project/pull/179335
More information about the flang-commits
mailing list