[flang-commits] [flang] [flang][DOCONCURRENT] Fix device mapping of several live-ins kinds (PR #229912)

Alessandro Fanfarillo via flang-commits flang-commits at lists.llvm.org
Fri Oct 23 09:07:15 PDT 2026


https://github.com/afanfa updated https://github.com/llvm/llvm-project/pull/229912

>From 0c26065918a7a932e8d7121d73c6e2b94122720e Mon Sep 17 00:00:00 2001
From: Alessandro Fanfarillo <alessandro.fanfarillo at amd.com>
Date: Wed, 7 Oct 2026 15:02:49 -0600
Subject: [PATCH 1/2] [flang][DOCONCURRENT] Fix device mapping of several
 live-ins kinds When a `do concurrent` loop is mapped to the device, every
 value the loop uses from outside must be mapped into the `omp.target` region
 and recreated inside it. Three cases were not handled correctly: 1. Live-ins
 declared with a `fir.shift` hit a TODO. This shape is    produced for
 descriptors with explicit lower bounds, for example an    assumed-shape dummy
 `a(5:)` or an associate-name bound to a pointer    component. The lower
 bounds are now mapped like the start indices of    a `fir.shape_shift`, and
 the box is re-declared on the device with a    rebuilt `fir.shift`. The box
 is loaded first because the mapped value    is the box's address, and
 `hlfir.declare` does not accept a shape for    a box address. Dropping the
 shift instead is not enough: the device    would then use the lower bounds of
 whichever declare result was    mapped, which is wrong when the loop uses the
 original base first. 2. Live-ins were de-duplicated by defining op. This is
 meant for the two    results of an `hlfir.declare`, but it also dropped all
 but the first    result of other multi-result ops. An array section of an   
 associate-name bound to an allocatable component uses both the lower    bound
 and the extent from one `fir.box_dims`, so the extent was never    mapped and
 verification failed with "using value defined outside the    region".
 De-duplication by op now only applies to `hlfir.declare`. 3. Only one result
 of an `hlfir.declare` is collected as a live-in, and    both host results
 were mapped to the device declare only when the    collected one was the
 original base. A loop that used the Fortran    view first, e.g. an element
 access followed by a section of the same    array, left the original base
 unmapped. Both results are now mapped    explicitly, whichever one was
 collected. map_shift_info.f90 covers (1) and map_live_in_results.mlir covers
 (2) and (3).

---
 .../OpenMP/DoConcurrentConversion.cpp         | 91 +++++++++++++------
 .../DoConcurrent/map_live_in_results.mlir     | 71 +++++++++++++++
 .../DoConcurrent/map_shift_info.f90           | 44 +++++++++
 3 files changed, 179 insertions(+), 27 deletions(-)
 create mode 100644 flang/test/Transforms/DoConcurrent/map_live_in_results.mlir
 create mode 100644 flang/test/Transforms/DoConcurrent/map_shift_info.f90

diff --git a/flang/lib/Optimizer/OpenMP/DoConcurrentConversion.cpp b/flang/lib/Optimizer/OpenMP/DoConcurrentConversion.cpp
index ee677a5d2c7f43..d1ba289c99b86a 100644
--- a/flang/lib/Optimizer/OpenMP/DoConcurrentConversion.cpp
+++ b/flang/lib/Optimizer/OpenMP/DoConcurrentConversion.cpp
@@ -117,7 +117,7 @@ using InductionVariableInfos = llvm::SmallVector<InductionVariableInfo>;
 void collectLoopLiveIns(fir::DoConcurrentLoopOp loop,
                         llvm::SmallVectorImpl<mlir::Value> &liveIns) {
   llvm::SmallDenseSet<mlir::Value> seenValues;
-  llvm::SmallPtrSet<mlir::Operation *, 8> seenOps;
+  llvm::SmallPtrSet<mlir::Operation *, 8> seenDeclares;
 
   for (auto [lb, ub, st] : llvm::zip_equal(
            loop.getLowerBound(), loop.getUpperBound(), loop.getStep())) {
@@ -128,15 +128,18 @@ void collectLoopLiveIns(fir::DoConcurrentLoopOp loop,
 
   mlir::visitUsedValuesDefinedAbove(
       loop.getRegion(), [&](mlir::OpOperand *operand) {
-        if (!seenValues.insert(operand->get()).second)
+        mlir::Value value = operand->get();
+        if (!seenValues.insert(value).second)
           return;
 
-        mlir::Operation *definingOp = operand->get().getDefiningOp();
-        // We want to collect ops corresponding to live-ins only once.
-        if (definingOp && !seenOps.insert(definingOp).second)
-          return;
+        // Both results of an `hlfir.declare` are views of the same variable,
+        // which is mapped once. Results of other multi-result ops (e.g.
+        // `fir.box_dims`) are independent values and each must be mapped.
+        if (auto declareOp = value.getDefiningOp<hlfir::DeclareOp>())
+          if (!seenDeclares.insert(declareOp).second)
+            return;
 
-        liveIns.push_back(operand->get());
+        liveIns.push_back(value);
       });
 
   for (mlir::Value local : loop.getLocalVars())
@@ -227,27 +230,35 @@ class DoConcurrentConversion
       if (!shape)
         return;
 
-      auto shapeOp =
-          mlir::dyn_cast_if_present<fir::ShapeOp>(shape.getDefiningOp());
-      auto shapeShiftOp =
-          mlir::dyn_cast_if_present<fir::ShapeShiftOp>(shape.getDefiningOp());
-
-      if (!shapeOp && !shapeShiftOp)
-        TODO(liveIn.getLoc(),
-             "Shapes not defined by `fir.shape` or `fir.shape_shift` op's are"
-             "not supported yet.");
+      mlir::Operation *shapeDefOp = shape.getDefiningOp();
 
-      if (shapeShiftOp != nullptr)
+      if (auto shapeOp = mlir::dyn_cast_if_present<fir::ShapeOp>(shapeDefOp)) {
+        extents.assign(shapeOp.getExtents().begin(),
+                       shapeOp.getExtents().end());
+      } else if (auto shapeShiftOp =
+                     mlir::dyn_cast_if_present<fir::ShapeShiftOp>(shapeDefOp)) {
         startIndices = shapeShiftOp.getOrigins();
-
-      extents = shapeOp != nullptr
-                    ? std::vector<mlir::Value>(shapeOp.getExtents().begin(),
-                                               shapeOp.getExtents().end())
-                    : shapeShiftOp.getExtents();
+        extents = shapeShiftOp.getExtents();
+      } else if (auto shiftOp =
+                     mlir::dyn_cast_if_present<fir::ShiftOp>(shapeDefOp)) {
+        startIndices.assign(shiftOp.getOrigins().begin(),
+                            shiftOp.getOrigins().end());
+      } else {
+        TODO(liveIn.getLoc(), "Shapes not defined by `fir.shape`, "
+                              "`fir.shape_shift` or `fir.shift` ops are not "
+                              "supported yet.");
+      }
     }
 
-    bool isShapedValue() const { return !extents.empty(); }
-    bool isShapeShiftedValue() const { return !startIndices.empty(); }
+    bool isShapedValue() const {
+      return !extents.empty() || !startIndices.empty();
+    }
+    bool isShapeShiftedValue() const {
+      return !startIndices.empty() && !extents.empty();
+    }
+    bool isShiftedValue() const {
+      return !startIndices.empty() && extents.empty();
+    }
   };
 
   using LiveInShapeInfoMap =
@@ -692,11 +703,16 @@ class DoConcurrentConversion
           mapper.map(hostValue, deviceValue);
       };
 
-      mapHostValueToDevice(mappedVar, liveInDeclare.getOriginalBase());
-
+      // Only one result of a host `hlfir.declare` is collected as a live-in,
+      // but the loop may use both, so map both regardless of which one it is.
       if (auto origDeclareOp = mlir::dyn_cast_if_present<hlfir::DeclareOp>(
-              mappedVar.getDefiningOp()))
+              mappedVar.getDefiningOp())) {
+        mapHostValueToDevice(origDeclareOp.getOriginalBase(),
+                             liveInDeclare.getOriginalBase());
         mapHostValueToDevice(origDeclareOp.getBase(), liveInDeclare.getBase());
+      } else {
+        mapHostValueToDevice(mappedVar, liveInDeclare.getOriginalBase());
+      }
     }
 
     for (auto [arg, hostEval] : llvm::zip_equal(argIface.getHostEvalBlockArgs(),
@@ -735,6 +751,27 @@ class DoConcurrentConversion
     if (fir::isa_ref_type(liveInType))
       liveInType = fir::unwrapRefType(liveInType);
 
+    if (targetShapeCreationInfo.isShiftedValue()) {
+      // A `fir.shift` is only valid on a box value. Box live-ins are mapped
+      // through a temporary, so load the box before re-declaring it.
+      assert(fir::isa_ref_type(liveInArg.getType()) &&
+             "expected a box live-in mapped through a temporary");
+      mlir::Value box =
+          fir::LoadOp::create(builder, liveInArg.getLoc(), liveInArg);
+      llvm::SmallVector<mlir::Value> origins;
+      for (auto [idx, startIndex] :
+           llvm::enumerate(targetShapeCreationInfo.startIndices))
+        origins.push_back(Fortran::utils::openmp::mapTemporaryValue(
+            builder, targetOp, startIndex,
+            liveInName + ".start_idx.dim" + std::to_string(idx)));
+      auto shiftType =
+          fir::ShiftType::get(builder.getContext(), origins.size());
+      mlir::Value shift =
+          fir::ShiftOp::create(builder, liveInArg.getLoc(), shiftType, origins);
+      return hlfir::DeclareOp::create(builder, liveInArg.getLoc(), box,
+                                      liveInName, shift);
+    }
+
     mlir::Value shape = [&]() -> mlir::Value {
       if (!targetShapeCreationInfo.isShapedValue())
         return {};
diff --git a/flang/test/Transforms/DoConcurrent/map_live_in_results.mlir b/flang/test/Transforms/DoConcurrent/map_live_in_results.mlir
new file mode 100644
index 00000000000000..3002134b4328de
--- /dev/null
+++ b/flang/test/Transforms/DoConcurrent/map_live_in_results.mlir
@@ -0,0 +1,71 @@
+// Tests that every value used inside a device-mapped `do concurrent` loop is
+// mapped to the target region, including:
+// * multiple results of a non-declare op (`fir.box_dims`), and
+// * both results of an `hlfir.declare`, regardless of which one the loop
+//   uses first.
+
+// RUN: fir-opt --omp-do-concurrent-conversion="map-to=device" %s -o - | FileCheck %s
+
+func.func @box_dims_results(%box: !fir.box<!fir.array<?xf32>>) {
+  %c0 = arith.constant 0 : index
+  %dims:3 = fir.box_dims %box, %c0 : (!fir.box<!fir.array<?xf32>>, index) -> (index, index, index)
+  %c1 = arith.constant 1 : index
+  %c10 = arith.constant 10 : index
+  fir.do_concurrent {
+    %0 = fir.alloca i32 {bindc_name = "i"}
+    %1:2 = hlfir.declare %0 uniq_name("_QFEi") : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+    fir.do_concurrent.loop (%arg0) = (%c1) to (%c10) step (%c1) {
+      %2 = fir.convert %arg0 : (index) -> i32
+      fir.store %2 to %1#0 : !fir.ref<i32>
+      %3 = arith.addi %dims#0, %dims#1 : index
+      %4 = fir.convert %3 : (index) -> i32
+      fir.store %4 to %1#0 : !fir.ref<i32>
+    }
+  }
+  return
+}
+
+// CHECK-LABEL: func.func @box_dims_results
+// CHECK:         %[[DIMS:.*]]:3 = fir.box_dims
+// CHECK-DAG:     fir.store %[[DIMS]]#0 to %[[LB_TMP:.*]] : !fir.ref<index>
+// CHECK-DAG:     fir.store %[[DIMS]]#1 to %[[EXT_TMP:.*]] : !fir.ref<index>
+// CHECK-DAG:     %[[LB_MAP:.*]] = omp.map.info var_ptr(%[[LB_TMP]] : !fir.ref<index>, index)
+// CHECK-DAG:     %[[EXT_MAP:.*]] = omp.map.info var_ptr(%[[EXT_TMP]] : !fir.ref<index>, index)
+// CHECK:         omp.target
+// CHECK-SAME:      %[[LB_MAP]] -> %[[LB_ARG:arg[0-9]+]], %[[EXT_MAP]] -> %[[EXT_ARG:arg[0-9]+]]
+// CHECK-DAG:       %[[LB_DECL:.*]]:2 = hlfir.declare %[[LB_ARG]]
+// CHECK-DAG:       %[[EXT_DECL:.*]]:2 = hlfir.declare %[[EXT_ARG]]
+// CHECK-DAG:       %[[LB:.*]] = fir.load %[[LB_DECL]]#1 : !fir.ref<index>
+// CHECK-DAG:       %[[EXT:.*]] = fir.load %[[EXT_DECL]]#1 : !fir.ref<index>
+// CHECK:           omp.loop_nest
+// CHECK:             arith.addi %[[LB]], %[[EXT]] : index
+
+func.func @declare_results_order(%arg: !fir.box<!fir.array<?xf32>>) {
+  %a:2 = hlfir.declare %arg uniq_name("_QFEa") : (!fir.box<!fir.array<?xf32>>) -> (!fir.box<!fir.array<?xf32>>, !fir.box<!fir.array<?xf32>>)
+  %c0 = arith.constant 0 : index
+  %c1 = arith.constant 1 : index
+  %c10 = arith.constant 10 : index
+  fir.do_concurrent {
+    %0 = fir.alloca i32 {bindc_name = "i"}
+    %1:2 = hlfir.declare %0 uniq_name("_QFEi") : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+    fir.do_concurrent.loop (%arg0) = (%c1) to (%c10) step (%c1) {
+      %2 = fir.convert %arg0 : (index) -> i32
+      fir.store %2 to %1#0 : !fir.ref<i32>
+      %d0:3 = fir.box_dims %a#0, %c0 : (!fir.box<!fir.array<?xf32>>, index) -> (index, index, index)
+      %d1:3 = fir.box_dims %a#1, %c0 : (!fir.box<!fir.array<?xf32>>, index) -> (index, index, index)
+      %3 = arith.addi %d0#1, %d1#1 : index
+      %4 = fir.convert %3 : (index) -> i32
+      fir.store %4 to %1#0 : !fir.ref<i32>
+    }
+  }
+  return
+}
+
+// CHECK-LABEL: func.func @declare_results_order
+// CHECK:         omp.target
+// CHECK:           %[[A:.*]]:2 = hlfir.declare %{{.*}} uniq_name("_QFEa")
+// CHECK-DAG:       %[[A1:.*]] = fir.load %[[A]]#1 : !fir.ref<!fir.box<!fir.array<?xf32>>>
+// CHECK-DAG:       %[[A0:.*]] = fir.load %[[A]]#0 : !fir.ref<!fir.box<!fir.array<?xf32>>>
+// CHECK:           omp.loop_nest
+// CHECK:             fir.box_dims %[[A0]], %{{.*}}
+// CHECK:             fir.box_dims %[[A1]], %{{.*}}
diff --git a/flang/test/Transforms/DoConcurrent/map_shift_info.f90 b/flang/test/Transforms/DoConcurrent/map_shift_info.f90
new file mode 100644
index 00000000000000..a153d98c1a8863
--- /dev/null
+++ b/flang/test/Transforms/DoConcurrent/map_shift_info.f90
@@ -0,0 +1,44 @@
+! Tests that descriptors declared with a `fir.shift` (explicit lower bounds)
+! are re-declared with a rebuilt `fir.shift` inside the target region.
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fdo-concurrent-to-openmp=device %s -o - \
+! RUN:   | FileCheck %s
+
+subroutine assumed_shape_lbound(a, b)
+  implicit none
+  real, intent(in) :: a(5:, :)
+  real, intent(out) :: b(:, :)
+  integer :: j
+  do concurrent (j = 1:size(b, 2))
+    b(:, j) = a(:, j)
+  end do
+end subroutine
+
+! CHECK-LABEL: func.func @_QPassumed_shape_lbound
+! CHECK: %[[LB0_MAP:.*]] = omp.map.info {{.*}} name("_QFassumed_shape_lboundEa.start_idx.dim0")
+! CHECK: %[[LB1_MAP:.*]] = omp.map.info {{.*}} name("_QFassumed_shape_lboundEa.start_idx.dim1")
+! CHECK: omp.target {{.*}}%[[LB0_MAP]] -> %[[LB0_ARG:[^,]+]], %[[LB1_MAP]] -> %[[LB1_ARG:[^,]+]]
+! CHECK-DAG: %[[LB0:.*]] = fir.load %[[LB0_ARG]] : !fir.ref<index>
+! CHECK-DAG: %[[LB1:.*]] = fir.load %[[LB1_ARG]] : !fir.ref<index>
+! CHECK: %[[BOX:.*]] = fir.load %{{.*}} : !fir.ref<!fir.box<!fir.array<?x?xf32>>>
+! CHECK: %[[SHIFT:.*]] = fir.shift %[[LB0]], %[[LB1]] : (index, index) -> !fir.shift<2>
+! CHECK: hlfir.declare %[[BOX]](%[[SHIFT]]) uniq_name("_QFassumed_shape_lboundEa")
+
+subroutine associate_pointer_component(p, b)
+  implicit none
+  type t
+    real, pointer :: values(:)
+  end type
+  type(t), intent(in) :: p
+  real, intent(out) :: b(:)
+  integer :: i
+  associate(v => p%values)
+    do concurrent (i = 1:size(b))
+      b(i) = v(i)
+    end do
+  end associate
+end subroutine
+
+! CHECK-LABEL: func.func @_QPassociate_pointer_component
+! CHECK: omp.target
+! CHECK: %[[SHIFT:.*]] = fir.shift %{{.*}} : (index) -> !fir.shift<1>
+! CHECK: hlfir.declare %{{.*}}(%[[SHIFT]]) uniq_name("_QFassociate_pointer_componentEv")
\ No newline at end of file

>From 75f02fb88df97e348672f63aa5d67f4d1754e210 Mon Sep 17 00:00:00 2001
From: Alessandro Fanfarillo <alessandro.fanfarillo at amd.com>
Date: Fri, 23 Oct 2026 10:01:06 -0600
Subject: [PATCH 2/2] [flang][DOCONCURRENT] Address review comments

Remove the TODO for live-in shapes not defined by `fir.shape`,
`fir.shape_shift` or `fir.shift`: the shape operand of `hlfir.declare`
can only be one of those.

Do not map constant start indices and extents through a temporary when
re-declaring live-ins on the device. `cloneOrMapRegionOutsiders`
rematerializes them inside the target region instead, avoiding an
alloca/store/map/load round-trip, e.g. for the lower bound of an
assumed-shape dummy such as `a(4:)`.

Co-authored-by: Cursor <cursoragent at cursor.com>
---
 .../OpenMP/DoConcurrentConversion.cpp         | 39 ++++----
 .../DoConcurrent/map_shape_info.f90           | 89 +++----------------
 .../DoConcurrent/map_shift_info.f90           | 33 +++++--
 .../DoConcurrent/not_perfectly_nested.f90     |  5 +-
 .../DoConcurrent/skip_all_nested_loops.f90    |  5 +-
 5 files changed, 65 insertions(+), 106 deletions(-)

diff --git a/flang/lib/Optimizer/OpenMP/DoConcurrentConversion.cpp b/flang/lib/Optimizer/OpenMP/DoConcurrentConversion.cpp
index d1ba289c99b86a..34322f96109bb1 100644
--- a/flang/lib/Optimizer/OpenMP/DoConcurrentConversion.cpp
+++ b/flang/lib/Optimizer/OpenMP/DoConcurrentConversion.cpp
@@ -206,6 +206,14 @@ static void localizeLoopLocalValue(mlir::Value local, mlir::Region &allocRegion,
                                    mlir::ConversionPatternRewriter &rewriter) {
   rewriter.moveOpBefore(local.getDefiningOp(), &allocRegion.front().front());
 }
+
+/// Returns true if \p value is an integer constant, possibly wrapped in
+/// `fir.convert` ops.
+static bool isIntConstant(mlir::Value value) {
+  while (auto convertOp = value.getDefiningOp<fir::ConvertOp>())
+    value = convertOp.getValue();
+  return fir::getIntIfConstant(value).has_value();
+}
 } // namespace looputils
 
 class DoConcurrentConversion
@@ -243,10 +251,6 @@ class DoConcurrentConversion
                      mlir::dyn_cast_if_present<fir::ShiftOp>(shapeDefOp)) {
         startIndices.assign(shiftOp.getOrigins().begin(),
                             shiftOp.getOrigins().end());
-      } else {
-        TODO(liveIn.getLoc(), "Shapes not defined by `fir.shape`, "
-                              "`fir.shape_shift` or `fir.shift` ops are not "
-                              "supported yet.");
       }
     }
 
@@ -751,6 +755,17 @@ class DoConcurrentConversion
     if (fir::isa_ref_type(liveInType))
       liveInType = fir::unwrapRefType(liveInType);
 
+    // Constants are left for `cloneOrMapRegionOutsiders` to rematerialize
+    // inside the target region instead of being mapped through a temporary.
+    auto mapShapeValue = [&](mlir::Value value, llvm::StringRef kind,
+                             size_t dim) -> mlir::Value {
+      if (looputils::isIntConstant(value))
+        return value;
+      return Fortran::utils::openmp::mapTemporaryValue(
+          builder, targetOp, value,
+          liveInName + "." + kind.str() + ".dim" + std::to_string(dim));
+    };
+
     if (targetShapeCreationInfo.isShiftedValue()) {
       // A `fir.shift` is only valid on a box value. Box live-ins are mapped
       // through a temporary, so load the box before re-declaring it.
@@ -761,9 +776,7 @@ class DoConcurrentConversion
       llvm::SmallVector<mlir::Value> origins;
       for (auto [idx, startIndex] :
            llvm::enumerate(targetShapeCreationInfo.startIndices))
-        origins.push_back(Fortran::utils::openmp::mapTemporaryValue(
-            builder, targetOp, startIndex,
-            liveInName + ".start_idx.dim" + std::to_string(idx)));
+        origins.push_back(mapShapeValue(startIndex, "start_idx", idx));
       auto shiftType =
           fir::ShiftType::get(builder.getContext(), origins.size());
       mlir::Value shift =
@@ -784,13 +797,9 @@ class DoConcurrentConversion
              llvm::zip_equal(targetShapeCreationInfo.startIndices,
                              targetShapeCreationInfo.extents)) {
           shapeShiftOperands.push_back(
-              Fortran::utils::openmp::mapTemporaryValue(
-                  builder, targetOp, startIndex,
-                  liveInName + ".start_idx.dim" + std::to_string(shapeIdx)));
+              mapShapeValue(startIndex, "start_idx", shapeIdx));
           shapeShiftOperands.push_back(
-              Fortran::utils::openmp::mapTemporaryValue(
-                  builder, targetOp, extent,
-                  liveInName + ".extent.dim" + std::to_string(shapeIdx)));
+              mapShapeValue(extent, "extent", shapeIdx));
           ++shapeIdx;
         }
 
@@ -803,9 +812,7 @@ class DoConcurrentConversion
       llvm::SmallVector<mlir::Value> shapeOperands;
       size_t shapeIdx = 0;
       for (auto extent : targetShapeCreationInfo.extents) {
-        shapeOperands.push_back(Fortran::utils::openmp::mapTemporaryValue(
-            builder, targetOp, extent,
-            liveInName + ".extent.dim" + std::to_string(shapeIdx)));
+        shapeOperands.push_back(mapShapeValue(extent, "extent", shapeIdx));
         ++shapeIdx;
       }
 
diff --git a/flang/test/Transforms/DoConcurrent/map_shape_info.f90 b/flang/test/Transforms/DoConcurrent/map_shape_info.f90
index 7fdabf16a14ee2..ce256f8f260700 100644
--- a/flang/test/Transforms/DoConcurrent/map_shape_info.f90
+++ b/flang/test/Transforms/DoConcurrent/map_shape_info.f90
@@ -13,48 +13,13 @@ program do_concurrent_shape
     end do
 end program do_concurrent_shape
 
-! CHECK: fir.store %{{c10.*}} to %[[DIM0_EXT:.*]] : !fir.ref<index>
-! CHECK: fir.store %{{c20.*}} to %[[DIM1_EXT:.*]] : !fir.ref<index>
-
-! CHECK: omp.map.info
-! CHECK: omp.map.info
-! CHECK: omp.map.info
-
-! CHECK: omp.map.info
-! CHECK: omp.map.info
-! CHECK: omp.map.info
-
-! CHECK: omp.map.info
-! CHECK: omp.map.info
-! CHECK: omp.map.info
-
-! CHECK: %[[DIM0_EXT_MAP:.*]] = omp.map.info
-! CHECK-SAME:   var_ptr(%[[DIM0_EXT]] : !fir.ref<index>, index)
-! CHECK-SAME:   map_clauses(implicit)
-! CHECK-SAME:   capture(ByCopy) name("_QFEa.extent.dim0") -> !fir.ref<index>
-
-! CHECK: %[[DIM1_EXT_MAP:.*]] = omp.map.info
-! CHECK-SAME:   var_ptr(%[[DIM1_EXT]] : !fir.ref<index>, index)
-! CHECK-SAME:   map_clauses(implicit)
-! CHECK-SAME:   capture(ByCopy) name("_QFEa.extent.dim1") -> !fir.ref<index>
-
-! CHECK: omp.target kernel_type(spmd) host_eval({{.*}}) map_entries(
-! CHECK-SAME:   %{{[^[:space:]]+}} -> %{{[^,]+}},
-! CHECK-SAME:   %{{[^[:space:]]+}} -> %{{[^,]+}},
-! CHECK-SAME:   %{{[^[:space:]]+}} -> %{{[^,]+}},
-! CHECK-SAME:   %{{[^[:space:]]+}} -> %{{[^,]+}},
-! CHECK-SAME:   %{{[^[:space:]]+}} -> %{{[^,]+}},
-! CHECK-SAME:   %{{[^[:space:]]+}} -> %{{[^,]+}},
-! CHECK-SAME:   %{{[^[:space:]]+}} -> %{{[^,]+}},
-! CHECK-SAME:   %{{[^[:space:]]+}} -> %{{[^,]+}},
-! CHECK-SAME:   %{{[^[:space:]]+}} -> %{{[^,]+}},
-! CHECK-SAME:   %[[DIM0_EXT_MAP]] -> %[[DIM0_EXT_ARG:[^,]+]],
-! CHECK-SAME:   %[[DIM1_EXT_MAP]] -> %[[DIM1_EXT_ARG:[^,]+]] : {{.*}})
-
-! CHECK-DAG:    %[[DIM0_EXT_DEV:.*]] = fir.load %[[DIM0_EXT_ARG]]
-! CHECK-DAG:    %[[DIM1_EXT_DEV:.*]] = fir.load %[[DIM1_EXT_ARG]]
-
-! CHECK:        %[[SHAPE:.*]] = fir.shape %[[DIM0_EXT_DEV]], %[[DIM1_EXT_DEV]]
+! Constant extents are rematerialized on the device rather than mapped.
+! CHECK-LABEL: func.func @_QQmain
+! CHECK-NOT:    name("_QFEa.extent.dim{{[0-9]}}")
+! CHECK:        omp.target
+! CHECK-DAG:    %[[DIM0_EXT:.*]] = arith.constant 10 : index
+! CHECK-DAG:    %[[DIM1_EXT:.*]] = arith.constant 20 : index
+! CHECK:        %[[SHAPE:.*]] = fir.shape %[[DIM0_EXT]], %[[DIM1_EXT]]
 ! CHECK:        %{{.*}}:2 = hlfir.declare %{{.*}}(%[[SHAPE]]) uniq_name("_QFEa")
 
 subroutine do_concurrent_shape_shift
@@ -67,38 +32,10 @@ subroutine do_concurrent_shape_shift
     end do
 end subroutine do_concurrent_shape_shift
 
-! CHECK: fir.store %{{c2.*}} to %[[DIM0_STRT:.*]] : !fir.ref<index>
-! CHECK: fir.store %{{c9.*}} to %[[DIM0_EXT:.*]] : !fir.ref<index>
-
-! CHECK: omp.map.info
-! CHECK: omp.map.info
-! CHECK: omp.map.info
-
-! CHECK: omp.map.info
-! CHECK: omp.map.info
-
-! CHECK: %[[DIM0_STRT_MAP:.*]] = omp.map.info
-! CHECK-SAME:   var_ptr(%[[DIM0_STRT]] : !fir.ref<index>, index)
-! CHECK-SAME:   map_clauses(implicit)
-! CHECK-SAME:   capture(ByCopy) name("_QF{{.*}}Ea.start_idx.dim0") -> !fir.ref<index>
-
-! CHECK: %[[DIM0_EXT_MAP:.*]] = omp.map.info
-! CHECK-SAME:   var_ptr(%[[DIM0_EXT]] : !fir.ref<index>, index)
-! CHECK-SAME:   map_clauses(implicit)
-! CHECK-SAME:   capture(ByCopy) name("_QF{{.*}}Ea.extent.dim0") -> !fir.ref<index>
-
-! CHECK: omp.target kernel_type(spmd) host_eval({{.*}}) map_entries(
-! CHECK-SAME:   %{{[^[:space:]]+}} -> %{{[^,]+}},
-! CHECK-SAME:   %{{[^[:space:]]+}} -> %{{[^,]+}},
-! CHECK-SAME:   %{{[^[:space:]]+}} -> %{{[^,]+}},
-! CHECK-SAME:   %{{[^[:space:]]+}} -> %{{[^,]+}},
-! CHECK-SAME:   %{{[^[:space:]]+}} -> %{{[^,]+}},
-! CHECK-SAME:   %[[DIM0_STRT_MAP]] -> %[[DIM0_STRT_ARG:[^,]+]],
-! CHECK-SAME:   %[[DIM0_EXT_MAP]] -> %[[DIM0_EXT_ARG:[^,]+]] : {{.*}})
-
-! CHECK-DAG:    %[[DIM0_STRT_DEV:.*]] = fir.load %[[DIM0_STRT_ARG]]
-! CHECK-DAG:    %[[DIM0_EXT_DEV:.*]] = fir.load %[[DIM0_EXT_ARG]]
-
-! CHECK:        %[[SHAPE_SHIFT:.*]] = fir.shape_shift %[[DIM0_STRT_DEV]], %[[DIM0_EXT_DEV]]
+! CHECK-LABEL: func.func @_QPdo_concurrent_shape_shift
+! CHECK-NOT:    name("_QF{{.*}}Ea.{{(start_idx|extent)}}.dim0")
+! CHECK:        omp.target
+! CHECK-DAG:    %[[DIM0_STRT:.*]] = arith.constant 2 : index
+! CHECK-DAG:    %[[DIM0_EXT:.*]] = arith.constant 9 : index
+! CHECK:        %[[SHAPE_SHIFT:.*]] = fir.shape_shift %[[DIM0_STRT]], %[[DIM0_EXT]]
 ! CHECK:        %{{.*}}:2 = hlfir.declare %{{.*}}(%[[SHAPE_SHIFT]]) uniq_name("_QF{{.*}}Ea")
-
diff --git a/flang/test/Transforms/DoConcurrent/map_shift_info.f90 b/flang/test/Transforms/DoConcurrent/map_shift_info.f90
index a153d98c1a8863..aed0d263dadc8a 100644
--- a/flang/test/Transforms/DoConcurrent/map_shift_info.f90
+++ b/flang/test/Transforms/DoConcurrent/map_shift_info.f90
@@ -13,16 +13,37 @@ subroutine assumed_shape_lbound(a, b)
   end do
 end subroutine
 
+! Constant lower bounds are rematerialized on the device rather than mapped.
 ! CHECK-LABEL: func.func @_QPassumed_shape_lbound
-! CHECK: %[[LB0_MAP:.*]] = omp.map.info {{.*}} name("_QFassumed_shape_lboundEa.start_idx.dim0")
-! CHECK: %[[LB1_MAP:.*]] = omp.map.info {{.*}} name("_QFassumed_shape_lboundEa.start_idx.dim1")
-! CHECK: omp.target {{.*}}%[[LB0_MAP]] -> %[[LB0_ARG:[^,]+]], %[[LB1_MAP]] -> %[[LB1_ARG:[^,]+]]
-! CHECK-DAG: %[[LB0:.*]] = fir.load %[[LB0_ARG]] : !fir.ref<index>
-! CHECK-DAG: %[[LB1:.*]] = fir.load %[[LB1_ARG]] : !fir.ref<index>
+! CHECK-NOT: name("_QFassumed_shape_lboundEa.start_idx.dim{{[0-9]}}")
+! CHECK: omp.target
+! CHECK-DAG: %[[C5:.*]] = arith.constant 5 : i64
+! CHECK-DAG: %[[C1:.*]] = arith.constant 1 : i64
+! CHECK-DAG: %[[LB0:.*]] = fir.convert %[[C5]] : (i64) -> index
+! CHECK-DAG: %[[LB1:.*]] = fir.convert %[[C1]] : (i64) -> index
 ! CHECK: %[[BOX:.*]] = fir.load %{{.*}} : !fir.ref<!fir.box<!fir.array<?x?xf32>>>
 ! CHECK: %[[SHIFT:.*]] = fir.shift %[[LB0]], %[[LB1]] : (index, index) -> !fir.shift<2>
 ! CHECK: hlfir.declare %[[BOX]](%[[SHIFT]]) uniq_name("_QFassumed_shape_lboundEa")
 
+subroutine assumed_shape_runtime_lbound(a, b, lb)
+  implicit none
+  integer, intent(in) :: lb
+  real, intent(in) :: a(lb:)
+  real, intent(out) :: b(:)
+  integer :: i
+  do concurrent (i = 1:size(b))
+    b(i) = a(i + lb - 1)
+  end do
+end subroutine
+
+! CHECK-LABEL: func.func @_QPassumed_shape_runtime_lbound
+! CHECK: %[[LB0_MAP:.*]] = omp.map.info {{.*}} name("_QFassumed_shape_runtime_lboundEa.start_idx.dim0")
+! CHECK: omp.target {{.*}}%[[LB0_MAP]] -> %[[LB0_ARG:[^,]+]]
+! CHECK-DAG: %[[LB0:.*]] = fir.load %[[LB0_ARG]] : !fir.ref<index>
+! CHECK-DAG: %[[BOX:.*]] = fir.load %{{.*}} : !fir.ref<!fir.box<!fir.array<?xf32>>>
+! CHECK: %[[SHIFT:.*]] = fir.shift %[[LB0]] : (index) -> !fir.shift<1>
+! CHECK: hlfir.declare %[[BOX]](%[[SHIFT]]) uniq_name("_QFassumed_shape_runtime_lboundEa")
+
 subroutine associate_pointer_component(p, b)
   implicit none
   type t
@@ -41,4 +62,4 @@ subroutine associate_pointer_component(p, b)
 ! CHECK-LABEL: func.func @_QPassociate_pointer_component
 ! CHECK: omp.target
 ! CHECK: %[[SHIFT:.*]] = fir.shift %{{.*}} : (index) -> !fir.shift<1>
-! CHECK: hlfir.declare %{{.*}}(%[[SHIFT]]) uniq_name("_QFassociate_pointer_componentEv")
\ No newline at end of file
+! CHECK: hlfir.declare %{{.*}}(%[[SHIFT]]) uniq_name("_QFassociate_pointer_componentEv")
diff --git a/flang/test/Transforms/DoConcurrent/not_perfectly_nested.f90 b/flang/test/Transforms/DoConcurrent/not_perfectly_nested.f90
index 3401f37b8ad570..6f8c99d937b72e 100644
--- a/flang/test/Transforms/DoConcurrent/not_perfectly_nested.f90
+++ b/flang/test/Transforms/DoConcurrent/not_perfectly_nested.f90
@@ -31,10 +31,7 @@ program main
 ! DEVICE-SAME:   %{{[[:alnum:]]+}} -> %{{[^,]+}},
 ! DEVICE-SAME:   %{{[^[:space:]]+}} -> %[[I_ARG:[^,]+]],
 ! DEVICE-SAME:   %{{[^[:space:]]+}} -> %[[X_ARG:[^,]+]],
-! DEVICE-SAME:   %{{[^[:space:]]+}} -> %[[A_ARG:[^,]+]],
-! DEVICE-SAME:   %{{[^[:space:]]+}} -> %{{[^,]+}},
-! DEVICE-SAME:   %{{[^[:space:]]+}} -> %{{[^,]+}},
-! DEVICE-SAME:   %{{[^[:space:]]+}} -> %{{[^:]+}} :
+! DEVICE-SAME:   %{{[^[:space:]]+}} -> %[[A_ARG:[^:]+]] :
 ! DEVICE-SAME:   {{.*}}) {
 
 ! DEVICE: omp.teams
diff --git a/flang/test/Transforms/DoConcurrent/skip_all_nested_loops.f90 b/flang/test/Transforms/DoConcurrent/skip_all_nested_loops.f90
index 49633bac442956..1fc887ef436a7c 100644
--- a/flang/test/Transforms/DoConcurrent/skip_all_nested_loops.f90
+++ b/flang/test/Transforms/DoConcurrent/skip_all_nested_loops.f90
@@ -32,10 +32,7 @@ program main
 ! DEVICE-SAME:   %{{[[:alnum:]]+}} -> %{{[^,]+}},
 ! DEVICE-SAME:   %{{[^[:space:]]+}} -> %[[I_ARG:[^,]+]],
 ! DEVICE-SAME:   %{{[^[:space:]]+}} -> %[[J_ARG:[^,]+]],
-! DEVICE-SAME:   %{{[^[:space:]]+}} -> %[[A_ARG:[^,]+]],
-! DEVICE-SAME:   %{{[^[:space:]]+}} -> %{{[^,]+}},
-! DEVICE-SAME:   %{{[^[:space:]]+}} -> %{{[^,]+}},
-! DEVICE-SAME:   %{{[^[:space:]]+}} -> %{{[^:]+}} :
+! DEVICE-SAME:   %{{[^[:space:]]+}} -> %[[A_ARG:[^:]+]] :
 ! DEVICE-SAME:   {{.*}}) {
 
 ! DEVICE: %[[TARGET_J_DECL:.*]]:2 = hlfir.declare %[[J_ARG]] uniq_name("_QFEj")



More information about the flang-commits mailing list