[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