[flang-commits] [flang] 4848313 - [flang] propagate IVDEP in array expressions optimization (#178171)

via flang-commits flang-commits at lists.llvm.org
Tue Jan 27 06:19:18 PST 2026


Author: jeanPerier
Date: 2026-01-27T15:19:14+01:00
New Revision: 4848313824ef17e85a474331c1f4f7b261c7ec77

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

LOG: [flang] propagate IVDEP in array expressions optimization (#178171)

Follow-up on https://github.com/llvm/llvm-project/pull/177940.
This propagates the access attribute in cases where hlfir.assign is
being transformed in array expression optimizations.
It also adds handling for the cases where there are WHERE/FORALL or user
defined assignments inside the loop and that an hlfir.region_assign is
first being generated.

Added: 
    flang/test/Lower/HLFIR/ivdep-elemental.f90
    flang/test/Lower/HLFIR/ivdep-where.f90

Modified: 
    flang/lib/Lower/Bridge.cpp
    flang/lib/Optimizer/HLFIR/Transforms/LowerHLFIROrderedAssignments.cpp
    flang/lib/Optimizer/HLFIR/Transforms/OptimizedBufferization.cpp

Removed: 
    


################################################################################
diff  --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index 1699b4b94a3dd..1d8d89776c33d 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -2408,6 +2408,14 @@ class FirConverter : public Fortran::lower::AbstractConverter {
             // necessary to forward the AccessGroups attribute.
             assignOp.getOperation()->setAttr(fir::getAccessGroupsAttrName(),
                                              attrs);
+          } else if (hlfir::RegionAssignOp regionAssignOp =
+                         mlir::dyn_cast<hlfir::RegionAssignOp>(op)) {
+            // User defined assignment, WHERE and FORALL assignments are
+            // abstracted via hlfir.region_assign at that stage. Set the
+            // access group on it so that it can later be propagated to
+            // hlfir.assign/fir.store/fir.loads created to implement it.
+            regionAssignOp.getOperation()->setAttr(
+                fir::getAccessGroupsAttrName(), attrs);
           } else if (fir::CallOp callOp = mlir::dyn_cast<fir::CallOp>(op)) {
             callOp.setAccessGroupsAttr(attrs);
           }

diff  --git a/flang/lib/Optimizer/HLFIR/Transforms/LowerHLFIROrderedAssignments.cpp b/flang/lib/Optimizer/HLFIR/Transforms/LowerHLFIROrderedAssignments.cpp
index 32998ab64cb8c..71b4e91f0110d 100644
--- a/flang/lib/Optimizer/HLFIR/Transforms/LowerHLFIROrderedAssignments.cpp
+++ b/flang/lib/Optimizer/HLFIR/Transforms/LowerHLFIROrderedAssignments.cpp
@@ -517,7 +517,10 @@ void OrderedAssignmentRewriter::pre(hlfir::RegionAssignOp regionAssignOp) {
   } else {
     // TODO: preserve allocatable assignment aspects for forall once
     // they are conveyed in hlfir.region_assign.
-    hlfir::AssignOp::create(builder, loc, rhsEntity, lhsEntity);
+    auto assignOp = hlfir::AssignOp::create(builder, loc, rhsEntity, lhsEntity);
+    if (auto accessGroups = regionAssignOp->getAttrOfType<mlir::ArrayAttr>(
+            fir::getAccessGroupsAttrName()))
+      assignOp->setAttr(fir::getAccessGroupsAttrName(), accessGroups);
   }
   generateCleanupIfAny(loweredLhs.elementalCleanup);
   if (loweredLhs.vectorSubscriptLoopNest)

diff  --git a/flang/lib/Optimizer/HLFIR/Transforms/OptimizedBufferization.cpp b/flang/lib/Optimizer/HLFIR/Transforms/OptimizedBufferization.cpp
index 2712bfba60dd4..5351a9a50954f 100644
--- a/flang/lib/Optimizer/HLFIR/Transforms/OptimizedBufferization.cpp
+++ b/flang/lib/Optimizer/HLFIR/Transforms/OptimizedBufferization.cpp
@@ -727,9 +727,13 @@ llvm::LogicalResult ElementalAssignBufferization::matchAndRewrite(
   // Assign the element value to the array element for this iteration.
   auto arrayElement =
       hlfir::getElementAt(loc, builder, lhs, loopNest.oneBasedIndices);
-  hlfir::AssignOp::create(
+  auto newAssign = hlfir::AssignOp::create(
       builder, loc, elementValue, arrayElement, /*realloc=*/false,
       /*keep_lhs_length_if_realloc=*/false, match->assign.getTemporaryLhs());
+  if (auto accessGroups =
+          match->assign.getOperation()->getAttrOfType<mlir::ArrayAttr>(
+              fir::getAccessGroupsAttrName()))
+    newAssign->setAttr(fir::getAccessGroupsAttrName(), accessGroups);
 
   rewriter.eraseOp(match->assign);
   rewriter.eraseOp(match->destroy);
@@ -788,6 +792,11 @@ llvm::LogicalResult BroadcastAssignBufferization::matchAndRewrite(
   llvm::SmallVector<mlir::Value> extents =
       hlfir::getIndexExtents(loc, builder, shape);
 
+  mlir::ArrayAttr accessGroups;
+  if (auto attrs = assign.getOperation()->getAttrOfType<mlir::ArrayAttr>(
+          fir::getAccessGroupsAttrName()))
+    accessGroups = attrs;
+
   if (lhs.isSimplyContiguous() && extents.size() > 1) {
     // Flatten the array to use a single assign loop, that can be better
     // optimized.
@@ -824,7 +833,9 @@ llvm::LogicalResult BroadcastAssignBufferization::matchAndRewrite(
     mlir::Value arrayElement =
         hlfir::DesignateOp::create(builder, loc, fir::ReferenceType::get(eleTy),
                                    flatArray, loopNest.oneBasedIndices);
-    hlfir::AssignOp::create(builder, loc, rhs, arrayElement);
+    auto newAssign = hlfir::AssignOp::create(builder, loc, rhs, arrayElement);
+    if (accessGroups)
+      newAssign->setAttr(fir::getAccessGroupsAttrName(), accessGroups);
   } else {
     hlfir::LoopNest loopNest =
         hlfir::genLoopNest(loc, builder, extents, /*isUnordered=*/true,
@@ -832,7 +843,9 @@ llvm::LogicalResult BroadcastAssignBufferization::matchAndRewrite(
     builder.setInsertionPointToStart(loopNest.body);
     auto arrayElement =
         hlfir::getElementAt(loc, builder, lhs, loopNest.oneBasedIndices);
-    hlfir::AssignOp::create(builder, loc, rhs, arrayElement);
+    auto newAssign = hlfir::AssignOp::create(builder, loc, rhs, arrayElement);
+    if (accessGroups)
+      newAssign->setAttr(fir::getAccessGroupsAttrName(), accessGroups);
   }
 
   rewriter.eraseOp(assign);

diff  --git a/flang/test/Lower/HLFIR/ivdep-elemental.f90 b/flang/test/Lower/HLFIR/ivdep-elemental.f90
new file mode 100644
index 0000000000000..ac5b274429725
--- /dev/null
+++ b/flang/test/Lower/HLFIR/ivdep-elemental.f90
@@ -0,0 +1,20 @@
+! RUN: %flang_fc1 -emit-fir -O2 %s -o - | FileCheck %s
+
+! CHECK: #[[ANNOTATION:.*]] = #llvm.loop_annotation<vectorize = #{{.*}}, parallelAccesses = #[[GROUP:.*]]>
+subroutine elemental_assignment_in_loop(a, b)
+  real :: a(100,100), b(100,100)
+  !dir$ ivdep
+  ! CHECK: fir.do_loop
+  ! CHECK-SAME: loopAnnotation = #[[ANNOTATION]]
+  do i=1,100
+    ! CHECK: fir.do_loop
+      ! CHECK: fir.load
+      ! CHECK-SAME: accessGroups = [#[[GROUP]]]
+      ! CHECK: fir.store
+      ! CHECK-SAME: accessGroups = [#[[GROUP]]]
+    a(i, :) = b(i, :) * 3.0
+    ! CHECK: }
+  ! CHECK: }
+  ! CHECK: return
+  end do
+end subroutine

diff  --git a/flang/test/Lower/HLFIR/ivdep-where.f90 b/flang/test/Lower/HLFIR/ivdep-where.f90
new file mode 100644
index 0000000000000..cddf28cf4e4b7
--- /dev/null
+++ b/flang/test/Lower/HLFIR/ivdep-where.f90
@@ -0,0 +1,17 @@
+! RUN: %flang_fc1 -emit-fir -O2 %s -o - | FileCheck %s
+
+! CHECK: #[[ANNOTATION:.*]] = #llvm.loop_annotation<vectorize = #{{.*}}, parallelAccesses = #[[GROUP:.*]]>
+subroutine test_where(a, l)
+  real :: a(100,100)
+  logical :: l(100, 100)
+  !dir$ ivdep
+  ! CHECK: fir.do_loop
+  ! CHECK-SAME: loopAnnotation = #[[ANNOTATION]]
+  do i=1,100
+    ! CHECK: fir.do_loop
+    where (l(i, :)) a(i, :) = 3.0
+    ! CHECK: fir.store
+    ! CHECK-SAME: accessGroups = [#[[GROUP]]]
+    ! CHECK: }
+  end do
+end subroutine


        


More information about the flang-commits mailing list