https://github.com/c-rhodes updated 
https://github.com/llvm/llvm-project/pull/178152

>From e636639f579b9ad5d1524a9059bcae6301cbed1c Mon Sep 17 00:00:00 2001
From: jeanPerier <[email protected]>
Date: Tue, 27 Jan 2026 10:18:41 +0100
Subject: [PATCH] [flang] fix DIR IVDEP for array assignments inside loops
 (#177940)

The access attribute set on hlfir.assign for arrays was lost in
InlineHLFIRAssign.cpp. This patch propagates it to the creates loads and
stores.

(cherry picked from commit c2d510f5bdabf71f4f5fde36a37faf5565762195)
---
 .../flang/Optimizer/Builder/HLFIRTools.h      | 11 ++++---
 .../flang/Optimizer/Dialect/FIROpsSupport.h   |  5 +++
 flang/lib/Lower/Bridge.cpp                    |  3 +-
 flang/lib/Optimizer/Builder/HLFIRTools.cpp    | 32 +++++++++++++------
 .../HLFIR/Transforms/ConvertToFIR.cpp         |  2 +-
 .../HLFIR/Transforms/InlineHLFIRAssign.cpp    |  7 +++-
 flang/test/Lower/ivdep-array.f90              | 20 ++++++++++++
 7 files changed, 63 insertions(+), 17 deletions(-)
 create mode 100644 flang/test/Lower/ivdep-array.f90

diff --git a/flang/include/flang/Optimizer/Builder/HLFIRTools.h 
b/flang/include/flang/Optimizer/Builder/HLFIRTools.h
index 9933e3ed6c308..404144f11e3df 100644
--- a/flang/include/flang/Optimizer/Builder/HLFIRTools.h
+++ b/flang/include/flang/Optimizer/Builder/HLFIRTools.h
@@ -461,7 +461,8 @@ void genNoAliasArrayAssignment(
     bool temporaryLHS = false,
     std::function<hlfir::Entity(mlir::Location, fir::FirOpBuilder &,
                                 hlfir::Entity, hlfir::Entity)> *combiner =
-        nullptr);
+        nullptr,
+    mlir::ArrayAttr accessGroups = {});
 
 /// Generate an assignment from \p rhs to \p lhs when they are known not to
 /// alias. Handles both arrays and scalars: for arrays, delegates to
@@ -474,15 +475,17 @@ void genNoAliasAssignment(
     bool temporaryLHS = false,
     std::function<hlfir::Entity(mlir::Location, fir::FirOpBuilder &,
                                 hlfir::Entity, hlfir::Entity)> *combiner =
-        nullptr);
+        nullptr,
+    mlir::ArrayAttr accessGroups = {});
 inline void genNoAliasAssignment(
     mlir::Location loc, fir::FirOpBuilder &builder, hlfir::Entity rhs,
     hlfir::Entity lhs, bool emitWorkshareLoop, bool temporaryLHS,
     std::function<hlfir::Entity(mlir::Location, fir::FirOpBuilder &,
                                 hlfir::Entity, hlfir::Entity)>
-        combiner) {
+        combiner,
+    mlir::ArrayAttr accessGroups = {}) {
   genNoAliasAssignment(loc, builder, rhs, lhs, emitWorkshareLoop, temporaryLHS,
-                       &combiner);
+                       &combiner, accessGroups);
 }
 
 /// Create a new temporary with the shape and parameters of the provided
diff --git a/flang/include/flang/Optimizer/Dialect/FIROpsSupport.h 
b/flang/include/flang/Optimizer/Dialect/FIROpsSupport.h
index ae471eb0d2e04..b014d925592cb 100644
--- a/flang/include/flang/Optimizer/Dialect/FIROpsSupport.h
+++ b/flang/include/flang/Optimizer/Dialect/FIROpsSupport.h
@@ -131,6 +131,11 @@ static constexpr llvm::StringRef 
getHasLifetimeMarkerAttrName() {
   return "fir.has_lifetime";
 }
 
+/// Attribute to mark the access groups of an operation.
+static constexpr llvm::StringRef getAccessGroupsAttrName() {
+  return "access_groups";
+}
+
 /// Does the function, \p func, have a host-associations tuple argument?
 /// Some internal procedures may have access to host procedure variables.
 bool hasHostAssociationArgument(mlir::func::FuncOp func);
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index 1f35153928500..cd743cc0b27c6 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -2405,7 +2405,8 @@ class FirConverter : public 
Fortran::lower::AbstractConverter {
             // In some loops, the HLFIR AssignOp operation can be translated
             // into FIR operation(s) containing StoreOp. It is therefore
             // necessary to forward the AccessGroups attribute.
-            assignOp.getOperation()->setAttr("access_groups", attrs);
+            assignOp.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/Builder/HLFIRTools.cpp 
b/flang/lib/Optimizer/Builder/HLFIRTools.cpp
index a345dcb86e3d6..133fa17af3f71 100644
--- a/flang/lib/Optimizer/Builder/HLFIRTools.cpp
+++ b/flang/lib/Optimizer/Builder/HLFIRTools.cpp
@@ -1396,23 +1396,33 @@ static void combineAndStoreElement(
     mlir::Location loc, fir::FirOpBuilder &builder, hlfir::Entity lhs,
     hlfir::Entity rhs, bool temporaryLHS,
     std::function<hlfir::Entity(mlir::Location, fir::FirOpBuilder &,
-                                hlfir::Entity, hlfir::Entity)> *combiner) {
+                                hlfir::Entity, hlfir::Entity)> *combiner,
+    mlir::ArrayAttr accessGroups) {
   hlfir::Entity valueToAssign = hlfir::loadTrivialScalar(loc, builder, rhs);
+  if (accessGroups)
+    if (auto load = valueToAssign.getDefiningOp<fir::LoadOp>())
+      load.setAccessGroupsAttr(accessGroups);
   if (combiner) {
     hlfir::Entity lhsValue = hlfir::loadTrivialScalar(loc, builder, lhs);
+    if (accessGroups)
+      if (auto load = lhsValue.getDefiningOp<fir::LoadOp>())
+        load.setAccessGroupsAttr(accessGroups);
     valueToAssign = (*combiner)(loc, builder, lhsValue, valueToAssign);
   }
-  hlfir::AssignOp::create(builder, loc, valueToAssign, lhs,
-                          /*realloc=*/false,
-                          /*keep_lhs_length_if_realloc=*/false,
-                          /*temporary_lhs=*/temporaryLHS);
+  auto assign = hlfir::AssignOp::create(builder, loc, valueToAssign, lhs,
+                                        /*realloc=*/false,
+                                        /*keep_lhs_length_if_realloc=*/false,
+                                        /*temporary_lhs=*/temporaryLHS);
+  if (accessGroups)
+    assign->setAttr(fir::getAccessGroupsAttrName(), accessGroups);
 }
 
 void hlfir::genNoAliasArrayAssignment(
     mlir::Location loc, fir::FirOpBuilder &builder, hlfir::Entity rhs,
     hlfir::Entity lhs, bool emitWorkshareLoop, bool temporaryLHS,
     std::function<hlfir::Entity(mlir::Location, fir::FirOpBuilder &,
-                                hlfir::Entity, hlfir::Entity)> *combiner) {
+                                hlfir::Entity, hlfir::Entity)> *combiner,
+    mlir::ArrayAttr accessGroups) {
   mlir::OpBuilder::InsertionGuard guard(builder);
   rhs = hlfir::derefPointersAndAllocatables(loc, builder, rhs);
   lhs = hlfir::derefPointersAndAllocatables(loc, builder, lhs);
@@ -1434,22 +1444,24 @@ void hlfir::genNoAliasArrayAssignment(
   auto lhsArrayElement =
       hlfir::getElementAt(loc, builder, lhs, loopNest.oneBasedIndices);
   combineAndStoreElement(loc, builder, lhsArrayElement, rhsArrayElement,
-                         temporaryLHS, combiner);
+                         temporaryLHS, combiner, accessGroups);
 }
 
 void hlfir::genNoAliasAssignment(
     mlir::Location loc, fir::FirOpBuilder &builder, hlfir::Entity rhs,
     hlfir::Entity lhs, bool emitWorkshareLoop, bool temporaryLHS,
     std::function<hlfir::Entity(mlir::Location, fir::FirOpBuilder &,
-                                hlfir::Entity, hlfir::Entity)> *combiner) {
+                                hlfir::Entity, hlfir::Entity)> *combiner,
+    mlir::ArrayAttr accessGroups) {
   if (lhs.isArray()) {
     genNoAliasArrayAssignment(loc, builder, rhs, lhs, emitWorkshareLoop,
-                              temporaryLHS, combiner);
+                              temporaryLHS, combiner, accessGroups);
     return;
   }
   rhs = hlfir::derefPointersAndAllocatables(loc, builder, rhs);
   lhs = hlfir::derefPointersAndAllocatables(loc, builder, lhs);
-  combineAndStoreElement(loc, builder, lhs, rhs, temporaryLHS, combiner);
+  combineAndStoreElement(loc, builder, lhs, rhs, temporaryLHS, combiner,
+                         accessGroups);
 }
 
 std::pair<hlfir::Entity, bool>
diff --git a/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp 
b/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
index a63695f38afc6..13d9fc264b9b8 100644
--- a/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
+++ b/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
@@ -151,7 +151,7 @@ class AssignOpConversion : public 
mlir::OpRewritePattern<hlfir::AssignOp> {
 
       mlir::ArrayAttr accessGroups;
       if (auto attrs = assignOp.getOperation()->getAttrOfType<mlir::ArrayAttr>(
-              "access_groups"))
+              fir::getAccessGroupsAttrName()))
         accessGroups = attrs;
 
       // genScalarAssignment() must take care of potential overlap
diff --git a/flang/lib/Optimizer/HLFIR/Transforms/InlineHLFIRAssign.cpp 
b/flang/lib/Optimizer/HLFIR/Transforms/InlineHLFIRAssign.cpp
index 1fc592c7fe522..a6a2eb0cb3c37 100644
--- a/flang/lib/Optimizer/HLFIR/Transforms/InlineHLFIRAssign.cpp
+++ b/flang/lib/Optimizer/HLFIR/Transforms/InlineHLFIRAssign.cpp
@@ -107,8 +107,13 @@ class InlineHLFIRAssignConversion
     mlir::Location loc = assign->getLoc();
     fir::FirOpBuilder builder(rewriter, assign.getOperation());
     builder.setInsertionPoint(assign);
+    mlir::ArrayAttr accessGroups;
+    if (auto attrs = assign.getOperation()->getAttrOfType<mlir::ArrayAttr>(
+            fir::getAccessGroupsAttrName()))
+      accessGroups = attrs;
     hlfir::genNoAliasArrayAssignment(
-        loc, builder, rhs, lhs, flangomp::shouldUseWorkshareLowering(assign));
+        loc, builder, rhs, lhs, flangomp::shouldUseWorkshareLowering(assign),
+        /*temporaryLHS=*/false, /*combiner=*/nullptr, accessGroups);
     rewriter.eraseOp(assign);
     return mlir::success();
   }
diff --git a/flang/test/Lower/ivdep-array.f90 b/flang/test/Lower/ivdep-array.f90
new file mode 100644
index 0000000000000..d018fbaf81a92
--- /dev/null
+++ b/flang/test/Lower/ivdep-array.f90
@@ -0,0 +1,20 @@
+! RUN: %flang_fc1 -emit-fir -O2 %s -o - | FileCheck %s
+
+! CHECK: #[[ANNOTATION:.*]] = #llvm.loop_annotation<vectorize = #{{.*}}, 
parallelAccesses = #[[GROUP:.*]]>
+subroutine array_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, :)
+    ! CHECK: }
+  ! CHECK: }
+  ! CHECK: return
+  end do
+end subroutine

_______________________________________________
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits

Reply via email to