[Mlir-commits] [flang] [mlir] [mlir][flang][OpenMP] Select iterators per locator and allow multi-block regions (PR #227454)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Sat Oct 10 23:29:19 PDT 2026
https://github.com/chichunchen updated https://github.com/llvm/llvm-project/pull/227454
>From 940985ba754136ec914cec45fa3a6cdcf2c040ed Mon Sep 17 00:00:00 2001
From: "Chi Chun, Chen" <chichun.chen at hpe.com>
Date: Wed, 7 Oct 2026 17:10:06 -0500
Subject: [PATCH 1/8] [mlir][OpenMP] Allow multi-block omp.iterator regions
Flang lowers a locator inside an omp.iterator region like any other
expression, so the region can contain control flow. For example, LEN_TRIM
in `depend(iterator(i=1:n), in: a(i+len_trim(s)))` becomes a loop, and SUM
or COUNT get inlined as loops at -O1. After control-flow conversion the
region has several blocks, which omp.iterator rejects.
Allow the region to have several blocks. Exactly one of them ends in
omp.yield, and every other block branches within the region. Translation
keeps the single-block path; for multi-block regions it converts the
blocks in dominance order and reads the yielded value after the yield,
relying on createIteratorLoop's support for multi-block bodies.
Translation also used the i64 induction value for each region argument,
whatever its declared type, so passing an i32 argument to another block
gave a badly typed PHI. Rebuild each induction value in its range's
declared type, and verify that the region arguments match the ranges in
number and type.
Assisted with Copilot and Claude Opus 5.
---
mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td | 14 +-
mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp | 54 +++++-
.../OpenMP/OpenMPToLLVMIRTranslation.cpp | 94 ++++++----
mlir/test/Dialect/OpenMP/invalid.mlir | 92 ++++++++-
mlir/test/Dialect/OpenMP/ops.mlir | 21 +++
.../LLVMIR/openmp-iterator-multi-block.mlir | 174 ++++++++++++++++++
.../Target/LLVMIR/openmp-iterator-wide.mlir | 74 ++++++++
7 files changed, 474 insertions(+), 49 deletions(-)
create mode 100644 mlir/test/Target/LLVMIR/openmp-iterator-multi-block.mlir
create mode 100644 mlir/test/Target/LLVMIR/openmp-iterator-wide.mlir
diff --git a/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td b/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td
index 6bc99cf765699..a839287121396 100644
--- a/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td
+++ b/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td
@@ -2727,7 +2727,7 @@ def AffinityEntryOp : OpenMP_Op<"affinity_entry", [Pure]> {
// Iterator Op
//===----------------------------------------------------------------------===//
-def IteratorOp : OpenMP_Op<"iterator", [AttrSizedOperandSegments, SingleBlock],
+def IteratorOp : OpenMP_Op<"iterator", [AttrSizedOperandSegments],
clauses = [OpenMP_LoopRelatedClause]> {
let summary = "OpenMP iterator modifier";
let description = [{
@@ -2736,6 +2736,9 @@ def IteratorOp : OpenMP_Op<"iterator", [AttrSizedOperandSegments, SingleBlock],
can be directly consumed by OpenMP clauses that accept iterator modifiers,
such as `affinity`, `map`, `to`, `from`, or `depend`.
+ The region may contain multiple blocks. Exactly one of them is terminated
+ by `omp.yield`; every other block branches to a block of the region.
+
Example:
%it = omp.iterator(%i, %j) =
(%lb_i to %ub_i step %st_i, %lb_j to %ub_j step %st_j) {
@@ -2744,7 +2747,7 @@ def IteratorOp : OpenMP_Op<"iterator", [AttrSizedOperandSegments, SingleBlock],
} -> !omp.iterated<ptr>
}];
- let regions = (region SizedRegion<1>:$region);
+ let regions = (region MinSizedRegion<1>:$region);
let results = (outs OpenMP_IteratedType:$iterated);
let assemblyFormat = [{
@@ -2754,7 +2757,14 @@ def IteratorOp : OpenMP_Op<"iterator", [AttrSizedOperandSegments, SingleBlock],
(`inclusive` $loop_inclusive^)? `->` qualified(type($iterated)) attr-dict
}];
+ let extraClassDeclaration = [{
+ /// Returns the region's unique `omp.yield`, or null if the region has none
+ /// or more than one.
+ YieldOp getYieldOp();
+ }] # clausesExtraClassDeclaration;
+
let hasVerifier = 1;
+ let hasRegionVerifier = 1;
}
//===----------------------------------------------------------------------===//
diff --git a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
index c6a424bd93214..a46ae84df1784 100644
--- a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
+++ b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
@@ -2613,10 +2613,11 @@ static LogicalResult verifyMapClause(Operation *op, OperandRange mapVars,
"'omp.iterator' ops";
// Check that the iterator body yields a value defined by omp.map.info.
- auto yieldOp =
- cast<mlir::omp::YieldOp>(iterOp.getRegion().front().getTerminator());
+ mlir::omp::YieldOp yieldOp = iterOp.getYieldOp();
auto yieldedMapInfo =
- yieldOp.getResults()[0].getDefiningOp<mlir::omp::MapInfoOp>();
+ yieldOp && yieldOp.getNumOperands() == 1
+ ? yieldOp.getResults()[0].getDefiningOp<mlir::omp::MapInfoOp>()
+ : nullptr;
if (!yieldedMapInfo)
return op->emitOpError() << "'map_iterated' iterator body must yield "
"a value defined by 'omp.map.info'";
@@ -5742,11 +5743,35 @@ static void printIteratorHeader(OpAsmPrinter &p, Operation *op, Region ®ion,
/*printBlockTerminators=*/true);
}
+YieldOp IteratorOp::getYieldOp() {
+ YieldOp yield;
+ for (Block &block : getRegion()) {
+ auto blockYield =
+ dyn_cast_if_present<YieldOp>(block.empty() ? nullptr : &block.back());
+ if (!blockYield)
+ continue;
+ if (yield)
+ return {};
+ yield = blockYield;
+ }
+ return yield;
+}
+
LogicalResult IteratorOp::verify() {
auto iteratedTy = llvm::dyn_cast<omp::IteratedType>(getIterated().getType());
if (!iteratedTy)
return emitOpError() << "result must be omp.iterated<entry_ty>";
+ Block::BlockArgListType ivs = getRegion().front().getArguments();
+ if (getLoopLowerBounds().size() != ivs.size())
+ return emitOpError() << "number of range arguments and IVs do not match";
+
+ for (auto [lb, iv] : llvm::zip_equal(getLoopLowerBounds(), ivs)) {
+ if (lb.getType() != iv.getType())
+ return emitOpError()
+ << "range argument type does not match corresponding IV type";
+ }
+
for (auto [lb, ub, step] : llvm::zip_equal(
getLoopLowerBounds(), getLoopUpperBounds(), getLoopSteps())) {
if (matchPattern(step, m_Zero()))
@@ -5771,11 +5796,15 @@ LogicalResult IteratorOp::verify() {
"greater than or equal to upper bound";
}
- Block &b = getRegion().front();
- auto yield = llvm::dyn_cast<omp::YieldOp>(b.getTerminator());
-
- if (!yield)
+ YieldOp yield = getYieldOp();
+ if (!yield) {
+ bool hasYield = llvm::any_of(getRegion(), [](Block &block) {
+ return !block.empty() && isa<YieldOp>(block.back());
+ });
+ if (hasYield)
+ return emitOpError() << "region must contain exactly one omp.yield";
return emitOpError() << "region must be terminated by omp.yield";
+ }
if (yield.getNumOperands() != 1)
return emitOpError()
@@ -5792,6 +5821,17 @@ LogicalResult IteratorOp::verify() {
return success();
}
+LogicalResult IteratorOp::verifyRegions() {
+ // Translation routes only the omp.yield block back to the iterator loop.
+ for (Block &block : getRegion()) {
+ Operation *terminator = block.getTerminator();
+ if (block.getNumSuccessors() == 0 && !isa<YieldOp>(terminator))
+ return mlir::emitError(terminator->getLoc())
+ << "expected exit block terminator to be an `omp.yield` op.";
+ }
+ return success();
+}
+
//===----------------------------------------------------------------------===//
// GroupprivateOp
//===----------------------------------------------------------------------===//
diff --git a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
index e8613060fee9e..1e953bd071e62 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
@@ -2853,8 +2853,9 @@ class TaskContextStructManager {
/// mlir::omp::IteratorOp for lowering to LLVM IR.
///
/// It computes the per-dimension trip counts and the total linearized trip
-/// count, casted to i64. These are used to build a canonical loop and to
-/// reconstruct the physical induction variables inside the loop body.
+/// count as i64. Bounds and steps keep their declared type so that the
+/// physical induction variables can be reconstructed in that type inside the
+/// loop body.
class IteratorInfo {
private:
llvm::SmallVector<llvm::Value *> lowerBounds;
@@ -2864,18 +2865,6 @@ class IteratorInfo {
unsigned dims;
llvm::Value *totalTrips;
- llvm::Value *lookUpAsI64(mlir::Value val, const LLVM::ModuleTranslation &mt,
- llvm::IRBuilderBase &builder) {
- llvm::Value *v = mt.lookupValue(val);
- if (!v)
- return nullptr;
- if (v->getType()->isIntegerTy(64))
- return v;
- if (v->getType()->isIntegerTy())
- return builder.CreateSExtOrTrunc(v, builder.getInt64Ty());
- return nullptr;
- }
-
public:
IteratorInfo(mlir::omp::IteratorOp itersOp,
mlir::LLVM::ModuleTranslation &moduleTranslation,
@@ -2887,12 +2876,12 @@ class IteratorInfo {
trips.resize(dims);
for (unsigned d = 0; d < dims; ++d) {
- llvm::Value *lb = lookUpAsI64(itersOp.getLoopLowerBounds()[d],
- moduleTranslation, builder);
- llvm::Value *ub = lookUpAsI64(itersOp.getLoopUpperBounds()[d],
- moduleTranslation, builder);
+ llvm::Value *lb =
+ moduleTranslation.lookupValue(itersOp.getLoopLowerBounds()[d]);
+ llvm::Value *ub =
+ moduleTranslation.lookupValue(itersOp.getLoopUpperBounds()[d]);
llvm::Value *st =
- lookUpAsI64(itersOp.getLoopSteps()[d], moduleTranslation, builder);
+ moduleTranslation.lookupValue(itersOp.getLoopSteps()[d]);
assert(lb && ub && st &&
"Expect lowerBounds, upperBounds, and steps in IteratorOp");
assert((!llvm::isa<llvm::ConstantInt>(st) ||
@@ -2904,10 +2893,13 @@ class IteratorInfo {
steps[d] = st;
// trips = ((ub - lb) / step) + 1 (inclusive ub, assume positive step)
- llvm::Value *diff = builder.CreateSub(ub, lb);
- llvm::Value *div = builder.CreateSDiv(diff, st);
- trips[d] = builder.CreateAdd(
- div, llvm::ConstantInt::get(builder.getInt64Ty(), 1));
+ llvm::Type *i64Ty = builder.getInt64Ty();
+ llvm::Value *lb64 = builder.CreateSExtOrTrunc(lb, i64Ty);
+ llvm::Value *ub64 = builder.CreateSExtOrTrunc(ub, i64Ty);
+ llvm::Value *st64 = builder.CreateSExtOrTrunc(st, i64Ty);
+ llvm::Value *diff = builder.CreateSub(ub64, lb64);
+ llvm::Value *div = builder.CreateSDiv(diff, st64);
+ trips[d] = builder.CreateAdd(div, llvm::ConstantInt::get(i64Ty, 1));
}
totalTrips = llvm::ConstantInt::get(builder.getInt64Ty(), 1);
@@ -3035,11 +3027,10 @@ static void fillAffinityLocators(Operation::operand_range affinityVars,
}
}
-static mlir::LogicalResult
-convertIteratorRegion(llvm::Value *linearIV, IteratorInfo &iterInfo,
- mlir::Block &iteratorRegionBlock,
- llvm::IRBuilderBase &builder,
- LLVM::ModuleTranslation &moduleTranslation) {
+static mlir::LogicalResult convertIteratorRegion(
+ llvm::Value *linearIV, IteratorInfo &iterInfo, mlir::Region &iteratorRegion,
+ llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation) {
+ mlir::Block &entryBlock = iteratorRegion.front();
llvm::Value *tmp = linearIV;
for (int d = (int)iterInfo.getDims() - 1; d >= 0; --d) {
llvm::Value *trip = iterInfo.getTrips()[d];
@@ -3049,20 +3040,47 @@ convertIteratorRegion(llvm::Value *linearIV, IteratorInfo &iterInfo,
tmp = builder.CreateUDiv(tmp, trip);
// physIV_d = lb_d + idx_d * step_d
+ idx =
+ builder.CreateZExtOrTrunc(idx, iterInfo.getLowerBounds()[d]->getType());
llvm::Value *physIV = builder.CreateAdd(
iterInfo.getLowerBounds()[d],
builder.CreateMul(idx, iterInfo.getSteps()[d]), "omp.it.phys_iv");
- moduleTranslation.mapValue(iteratorRegionBlock.getArgument(d), physIV);
+ moduleTranslation.mapValue(entryBlock.getArgument(d), physIV);
}
// Translate the iterator region into the loop body.
- moduleTranslation.mapBlock(&iteratorRegionBlock, builder.GetInsertBlock());
- if (mlir::failed(moduleTranslation.convertBlock(iteratorRegionBlock,
- /*ignoreArguments=*/true,
- builder))) {
- return mlir::failure();
+ if (iteratorRegion.hasOneBlock()) {
+ moduleTranslation.mapBlock(&entryBlock, builder.GetInsertBlock());
+ return moduleTranslation.convertBlock(entryBlock, /*ignoreArguments=*/true,
+ builder);
+ }
+
+ // Unlike convertOmpOpRegions, do not forward the yielded value through a PHI:
+ // it may have no LLVM type (e.g. `!omp.affinity_entry_ty`). The unique
+ // `omp.yield` block is the continuation's only predecessor, so callers can
+ // look up the yielded value directly.
+ llvm::BasicBlock *continuation =
+ splitBB(builder, true, "omp.iterator.region.cont");
+ llvm::Instruction *sourceBranch = builder.GetInsertBlock()->getTerminator();
+ for (mlir::Block &block : iteratorRegion)
+ moduleTranslation.mapBlock(
+ &block,
+ llvm::BasicBlock::Create(builder.getContext(), "omp.iterator.region",
+ continuation->getParent(), continuation));
+ sourceBranch->setSuccessor(0, moduleTranslation.lookupBlock(&entryBlock));
+
+ for (mlir::Block *block : getBlocksSortedByDominance(iteratorRegion)) {
+ llvm::IRBuilderBase::InsertPointGuard guard(builder);
+ if (failed(moduleTranslation.convertBlock(*block, block->isEntryBlock(),
+ builder)))
+ return mlir::failure();
+ if (isa<omp::YieldOp>(block->getTerminator()))
+ builder.CreateBr(continuation);
}
+ LLVM::detail::connectPHINodes(iteratorRegion, moduleTranslation);
+
+ builder.SetInsertPoint(continuation);
return mlir::success();
}
@@ -3075,7 +3093,6 @@ fillIteratorLoop(mlir::omp::IteratorOp itersOp, llvm::IRBuilderBase &builder,
IteratorInfo &iterInfo, llvm::StringRef loopName,
IteratorStoreEntryTy genStoreEntry) {
mlir::Region &itersRegion = itersOp.getRegion();
- mlir::Block &iteratorRegionBlock = itersRegion.front();
llvm::OpenMPIRBuilder::LocationDescription loc(builder);
@@ -3084,14 +3101,13 @@ fillIteratorLoop(mlir::omp::IteratorOp itersOp, llvm::IRBuilderBase &builder,
llvm::IRBuilderBase::InsertPointGuard guard(builder);
builder.restoreIP(bodyIP);
- if (failed(convertIteratorRegion(linearIV, iterInfo, iteratorRegionBlock,
- builder, moduleTranslation))) {
+ if (failed(convertIteratorRegion(linearIV, iterInfo, itersRegion, builder,
+ moduleTranslation))) {
return llvm::make_error<llvm::StringError>(
"failed to convert iterator region", llvm::inconvertibleErrorCode());
}
- auto yield =
- mlir::dyn_cast<mlir::omp::YieldOp>(iteratorRegionBlock.getTerminator());
+ mlir::omp::YieldOp yield = itersOp.getYieldOp();
assert(yield && yield.getResults().size() == 1 &&
"expect omp.yield in iterator region to have one result");
diff --git a/mlir/test/Dialect/OpenMP/invalid.mlir b/mlir/test/Dialect/OpenMP/invalid.mlir
index ad74eeadfb829..1f0a09fad85a6 100644
--- a/mlir/test/Dialect/OpenMP/invalid.mlir
+++ b/mlir/test/Dialect/OpenMP/invalid.mlir
@@ -4894,6 +4894,27 @@ func.func @iterator_bad_result_type(%lb : index, %ub : index, %st : index) {
// -----
+func.func @iterator_iv_count_mismatch(%lb : i64, %ub : i64, %st : i64, %x : !llvm.ptr) {
+ // expected-error at +1 {{number of range arguments and IVs do not match}}
+ %0 = "omp.iterator"(%lb, %ub, %st) <{operandSegmentSizes = array<i32: 1, 1, 1>}> ({
+ omp.yield(%x : !llvm.ptr)
+ }) : (i64, i64, i64) -> !omp.iterated<!llvm.ptr>
+ return
+}
+
+// -----
+
+func.func @iterator_iv_type_mismatch(%lb : i32, %ub : i32, %st : i32, %x : !llvm.ptr) {
+ // expected-error at +1 {{range argument type does not match corresponding IV type}}
+ %0 = "omp.iterator"(%lb, %ub, %st) <{operandSegmentSizes = array<i32: 1, 1, 1>}> ({
+ ^bb0(%i: i64):
+ omp.yield(%x : !llvm.ptr)
+ }) : (i32, i32, i32) -> !omp.iterated<!llvm.ptr>
+ return
+}
+
+// -----
+
func.func @iterator_zero_step(%s2 : !llvm.struct<(ptr, i64)>) {
%lb = arith.constant 1 : index
%ub = arith.constant 4 : index
@@ -4947,7 +4968,7 @@ func.func @iterator_missing_yield(%lb : index, %ub : index, %st : index) {
// -----
func.func @iterator_empty_body(%lb : index, %ub : index, %st : index) {
- // expected-error at +1 {{expects a non-empty block}}
+ // expected-error at +1 {{region must be terminated by omp.yield}}
%0 = omp.iterator(%i: index) = (%lb to %ub step %st) {
} -> !omp.iterated<index>
return
@@ -4975,6 +4996,60 @@ func.func @iterator_yield_type_mismatch(%lb : index, %ub : index, %st : index) {
// -----
+func.func @iterator_multi_block_yield_type_mismatch(%lb : index, %ub : index, %st : index) {
+ // expected-error at +1 {{omp.iterated element type ('i64') does not match omp.yield operand type ('index')}}
+ %0 = omp.iterator(%i: index) = (%lb to %ub step %st) {
+ cf.br ^bb1
+ ^bb1:
+ omp.yield(%i : index)
+ } -> !omp.iterated<i64>
+ return
+}
+
+// -----
+
+func.func @iterator_two_yields(%lb : index, %ub : index, %st : index, %c : i1) {
+ // expected-error at +1 {{region must contain exactly one omp.yield}}
+ %0 = omp.iterator(%i: index) = (%lb to %ub step %st) {
+ cf.cond_br %c, ^bb1, ^bb2
+ ^bb1:
+ omp.yield(%i : index)
+ ^bb2:
+ omp.yield(%i : index)
+ } -> !omp.iterated<index>
+ return
+}
+
+// -----
+
+func.func @iterator_return_exit(%lb : index, %ub : index, %st : index, %c : i1) {
+ %0 = omp.iterator(%i: index) = (%lb to %ub step %st) {
+ cf.cond_br %c, ^bb1, ^bb2
+ ^bb1:
+ omp.yield(%i : index)
+ ^bb2:
+ // expected-error @below {{expected exit block terminator to be an `omp.yield` op.}}
+ llvm.return
+ } -> !omp.iterated<index>
+ return
+}
+
+// -----
+
+func.func @iterator_terminator_exit(%lb : index, %ub : index, %st : index, %c : i1) {
+ %0 = omp.iterator(%i: index) = (%lb to %ub step %st) {
+ cf.cond_br %c, ^bb1, ^bb2
+ ^bb1:
+ omp.yield(%i : index)
+ ^bb2:
+ // expected-error @below {{expected exit block terminator to be an `omp.yield` op.}}
+ omp.terminator
+ } -> !omp.iterated<index>
+ return
+}
+
+// -----
+
func.func @map_iterated_not_iterator(%it : !omp.iterated<!llvm.ptr>) {
// expected-error @below {{'omp.target_update' op 'map_iterated' arguments must be defined by 'omp.iterator' ops}}
omp.target_update map_iterated(%it : !omp.iterated<!llvm.ptr>)
@@ -4995,6 +5070,21 @@ func.func @map_iterated_yield_not_map_info(%lb : index, %ub : index, %st : index
// -----
+func.func @map_iterated_multi_block_yield_not_map_info(%lb : index, %ub : index,
+ %st : index,
+ %addr : !llvm.ptr) {
+ %it = omp.iterator(%iv: index) = (%lb to %ub step %st) {
+ cf.br ^bb1
+ ^bb1:
+ omp.yield(%addr : !llvm.ptr)
+ } -> !omp.iterated<!llvm.ptr>
+ // expected-error @below {{'omp.target_enter_data' op 'map_iterated' iterator body must yield a value defined by 'omp.map.info'}}
+ omp.target_enter_data map_iterated(%it : !omp.iterated<!llvm.ptr>) {}
+ return
+}
+
+// -----
+
func.func @map_iterated_yield_not_map_info_exit(%lb : index, %ub : index, %st : index,
%addr : !llvm.ptr) {
%it = omp.iterator(%iv: index) = (%lb to %ub step %st) {
diff --git a/mlir/test/Dialect/OpenMP/ops.mlir b/mlir/test/Dialect/OpenMP/ops.mlir
index 9371d3599b72a..7416c3da3b395 100644
--- a/mlir/test/Dialect/OpenMP/ops.mlir
+++ b/mlir/test/Dialect/OpenMP/ops.mlir
@@ -4270,6 +4270,27 @@ func.func @omp_iterator_negative_step(%s2 : !llvm.struct<(ptr, i64)>) -> () {
return
}
+// CHECK-LABEL: func.func @omp_iterator_multi_block
+func.func @omp_iterator_multi_block(%a : !llvm.ptr, %b : !llvm.ptr) -> () {
+ // CHECK: omp.iterator(%[[IV:.*]]: index) = (%{{.*}} to %{{.*}} step %{{.*}}) {
+ // CHECK: %[[C:.*]] = arith.cmpi eq, %[[IV]], %{{.*}} : index
+ // CHECK: cf.cond_br %[[C]], ^[[BB1:.*]](%{{.*}} : !llvm.ptr), ^[[BB1]](%{{.*}} : !llvm.ptr)
+ // CHECK: ^[[BB1]](%[[P:.*]]: !llvm.ptr):
+ // CHECK: omp.yield(%[[P]] : !llvm.ptr)
+ // CHECK: } -> !omp.iterated<!llvm.ptr>
+ %lb = arith.constant 1 : index
+ %ub = arith.constant 4 : index
+ %st = arith.constant 1 : index
+
+ %0 = omp.iterator(%iv: index) = (%lb to %ub step %st) {
+ %c = arith.cmpi eq, %iv, %lb : index
+ cf.cond_br %c, ^bb1(%a : !llvm.ptr), ^bb1(%b : !llvm.ptr)
+ ^bb1(%p : !llvm.ptr):
+ omp.yield(%p : !llvm.ptr)
+ } -> !omp.iterated<!llvm.ptr>
+ return
+}
+
// CHECK-LABEL: func.func @omp_task_affinity_iterator_1d
func.func @omp_task_affinity_iterator_1d(%lb : index, %ub : index, %step : index,
%addr : !llvm.ptr, %len : i64) -> () {
diff --git a/mlir/test/Target/LLVMIR/openmp-iterator-multi-block.mlir b/mlir/test/Target/LLVMIR/openmp-iterator-multi-block.mlir
new file mode 100644
index 0000000000000..b131b55a0f061
--- /dev/null
+++ b/mlir/test/Target/LLVMIR/openmp-iterator-multi-block.mlir
@@ -0,0 +1,174 @@
+// RUN: mlir-translate --mlir-to-llvmir %s | FileCheck %s
+
+// An omp.iterator region may span several blocks. Each entry stores the value
+// yielded by the region's single omp.yield.
+
+// The yielded address is selected by a branch.
+llvm.func @depend_diamond(%a : !llvm.ptr, %b : !llvm.ptr) {
+ %c1 = llvm.mlir.constant(1 : i64) : i64
+ %c4 = llvm.mlir.constant(4 : i64) : i64
+ %it = omp.iterator(%iv: i64) = (%c1 to %c4 step %c1) {
+ %first = llvm.icmp "eq" %iv, %c1 : i64
+ llvm.cond_br %first, ^bb1(%a : !llvm.ptr), ^bb1(%b : !llvm.ptr)
+ ^bb1(%p : !llvm.ptr):
+ omp.yield(%p : !llvm.ptr)
+ } -> !omp.iterated<!llvm.ptr>
+ omp.task depend(taskdependin -> %it : !omp.iterated<!llvm.ptr>) {
+ omp.terminator
+ }
+ llvm.return
+}
+
+// CHECK-LABEL: define void @depend_diamond
+// CHECK-SAME: (ptr %[[A:[0-9]+]], ptr %[[B:[0-9]+]])
+// CHECK: %[[DEPS:.*]] = tail call ptr @malloc(i64 80)
+// CHECK: omp_dep_iterator.body:
+// CHECK: %[[IV:.*]] = add i64 1, %{{.*}}
+// CHECK: br label %[[ENTRY:omp.iterator.region]]
+// CHECK: [[ENTRY]]:
+// CHECK: %[[FIRST:.*]] = icmp eq i64 %[[IV]], 1
+// CHECK: br i1 %[[FIRST]], label %[[MERGE:omp.iterator.region[0-9]+]], label %[[ELSE:omp.iterator.region[0-9]+]]
+// CHECK: [[MERGE]]:
+// CHECK: %[[P:.*]] = phi ptr [ %[[BV:.*]], %[[ELSE]] ], [ %[[A]], %[[ENTRY]] ]
+// CHECK: br label %omp.iterator.region.cont
+// CHECK: [[ELSE]]:
+// CHECK: %[[BV]] = phi ptr [ %[[B]], %[[ENTRY]] ]
+// CHECK: omp.iterator.region.cont:
+// CHECK: %[[ADDR:.*]] = ptrtoint ptr %[[P]] to i64
+// CHECK: store i64 %[[ADDR]], ptr
+// CHECK: br label %omp_dep_iterator.inc
+// CHECK: call i32 @__kmpc_omp_task_with_deps({{.*}}, i32 4, ptr %[[DEPS]], i32 0, ptr null)
+
+// The affinity length is defined before the branch, the address after it.
+llvm.func @affinity_split(%a : !llvm.ptr, %b : !llvm.ptr) {
+ %c1 = llvm.mlir.constant(1 : i64) : i64
+ %c3 = llvm.mlir.constant(3 : i64) : i64
+ %it = omp.iterator(%iv: i64) = (%c1 to %c3 step %c1) {
+ %len = llvm.mul %iv, %c3 : i64
+ %first = llvm.icmp "eq" %iv, %c1 : i64
+ llvm.cond_br %first, ^bb1, ^bb2
+ ^bb1:
+ llvm.br ^bb3(%a : !llvm.ptr)
+ ^bb2:
+ llvm.br ^bb3(%b : !llvm.ptr)
+ ^bb3(%p : !llvm.ptr):
+ %e = omp.affinity_entry %p, %len
+ : (!llvm.ptr, i64) -> !omp.affinity_entry_ty<!llvm.ptr, i64>
+ omp.yield(%e : !omp.affinity_entry_ty<!llvm.ptr, i64>)
+ } -> !omp.iterated<!omp.affinity_entry_ty<!llvm.ptr, i64>>
+ omp.task affinity(%it : !omp.iterated<!omp.affinity_entry_ty<!llvm.ptr, i64>>) {
+ omp.terminator
+ }
+ llvm.return
+}
+
+// CHECK-LABEL: define void @affinity_split
+// CHECK-SAME: (ptr %[[A:[0-9]+]], ptr %[[B:[0-9]+]])
+// CHECK: omp_iterator.body:
+// CHECK: %[[IV:.*]] = add i64 1, %{{.*}}
+// CHECK: omp.iterator.region:
+// CHECK: %[[LEN:.*]] = mul i64 %[[IV]], 3
+// CHECK: %[[P:.*]] = phi ptr [ %[[B]], %{{.*}} ], [ %[[A]], %{{.*}} ]
+// CHECK: omp.iterator.region.cont:
+// CHECK: %[[ADDR:.*]] = ptrtoint ptr %[[P]] to i64
+// CHECK: store i64 %[[ADDR]], ptr
+// CHECK: store i64 %[[LEN]], ptr
+// CHECK: br label %omp_iterator.inc
+// CHECK: call i32 @__kmpc_omp_reg_task_with_affinity({{.*}}, i32 3, ptr
+
+// A loop inside the region computes the yielded address.
+llvm.func @depend_inner_loop(%addr : !llvm.ptr) {
+ %c0 = llvm.mlir.constant(0 : i64) : i64
+ %c1 = llvm.mlir.constant(1 : i64) : i64
+ %c3 = llvm.mlir.constant(3 : i64) : i64
+ %it = omp.iterator(%iv: i64) = (%c0 to %c3 step %c1) {
+ llvm.br ^loop(%c0, %c0 : i64, i64)
+ ^loop(%k : i64, %acc : i64):
+ %done = llvm.icmp "sge" %k, %iv : i64
+ llvm.cond_br %done, ^exit, ^body
+ ^body:
+ %acc2 = llvm.add %acc, %k : i64
+ %k2 = llvm.add %k, %c1 : i64
+ llvm.br ^loop(%k2, %acc2 : i64, i64)
+ ^exit:
+ %p = llvm.getelementptr %addr[%acc] : (!llvm.ptr, i64) -> !llvm.ptr, i8
+ omp.yield(%p : !llvm.ptr)
+ } -> !omp.iterated<!llvm.ptr>
+ omp.task depend(taskdependin -> %it : !omp.iterated<!llvm.ptr>) {
+ omp.terminator
+ }
+ llvm.return
+}
+
+// CHECK-LABEL: define void @depend_inner_loop
+// CHECK-SAME: (ptr %[[ADDR:[0-9]+]])
+// CHECK: omp_dep_iterator.body:
+// CHECK: %[[IV:.*]] = add i64 0, %{{.*}}
+// CHECK: [[LOOP:omp.iterator.region[0-9]+]]:
+// CHECK: %[[K:.*]] = phi i64 [ %[[K2:.*]], %[[BODY:omp.iterator.region[0-9]+]] ], [ 0, %omp.iterator.region ]
+// CHECK: %[[ACC:.*]] = phi i64 [ %[[ACC2:.*]], %[[BODY]] ], [ 0, %omp.iterator.region ]
+// CHECK: %[[DONE:.*]] = icmp sge i64 %[[K]], %[[IV]]
+// CHECK: br i1 %[[DONE]], label %[[EXIT:omp.iterator.region[0-9]+]], label %[[BODY]]
+// CHECK: [[BODY]]:
+// CHECK: %[[ACC2]] = add i64 %[[ACC]], %[[K]]
+// CHECK: %[[K2]] = add i64 %[[K]], 1
+// CHECK: br label %[[LOOP]]
+// CHECK: [[EXIT]]:
+// CHECK: %[[P:.*]] = getelementptr i8, ptr %[[ADDR]], i64 %[[ACC]]
+// CHECK: omp.iterator.region.cont:
+// CHECK: %[[PI:.*]] = ptrtoint ptr %[[P]] to i64
+// CHECK: store i64 %[[PI]], ptr
+// CHECK: call i32 @__kmpc_omp_task_with_deps({{.*}}, i32 4, ptr
+
+// Both induction values are mapped in their declared order.
+llvm.func @depend_2d(%a : !llvm.ptr, %b : !llvm.ptr) {
+ %c1 = llvm.mlir.constant(1 : i64) : i64
+ %c2 = llvm.mlir.constant(2 : i64) : i64
+ %c3 = llvm.mlir.constant(3 : i64) : i64
+ %it = omp.iterator(%i: i64, %j: i64) = (%c1 to %c2 step %c1, %c1 to %c3 step %c1) {
+ %lt = llvm.icmp "slt" %i, %j : i64
+ llvm.cond_br %lt, ^bb1(%a : !llvm.ptr), ^bb1(%b : !llvm.ptr)
+ ^bb1(%p : !llvm.ptr):
+ omp.yield(%p : !llvm.ptr)
+ } -> !omp.iterated<!llvm.ptr>
+ omp.task depend(taskdependin -> %it : !omp.iterated<!llvm.ptr>) {
+ omp.terminator
+ }
+ llvm.return
+}
+
+// CHECK-LABEL: define void @depend_2d
+// CHECK-SAME: (ptr %[[A:[0-9]+]], ptr %[[B:[0-9]+]])
+// CHECK: omp_dep_iterator.body:
+// CHECK: %[[J:.*]] = add i64 1, %{{.*}}
+// CHECK: %[[I:.*]] = add i64 1, %{{.*}}
+// CHECK: omp.iterator.region:
+// CHECK: icmp slt i64 %[[I]], %[[J]]
+// CHECK: %[[P:.*]] = phi ptr [ %{{.*}}, %{{.*}} ], [ %[[A]], %omp.iterator.region ]
+// CHECK: phi ptr [ %[[B]], %omp.iterator.region ]
+// CHECK: omp.iterator.region.cont:
+// CHECK: %[[PI:.*]] = ptrtoint ptr %[[P]] to i64
+// CHECK: store i64 %[[PI]], ptr
+// CHECK: call i32 @__kmpc_omp_task_with_deps({{.*}}, i32 6, ptr
+
+// A block argument fed by the induction value keeps its declared type.
+llvm.func @depend_narrow(%x : !llvm.ptr) {
+ %lo = llvm.mlir.constant(1 : i32) : i32
+ %hi = llvm.mlir.constant(2 : i32) : i32
+ %it = omp.iterator(%i: i32) = (%lo to %hi step %lo) {
+ llvm.br ^next(%i : i32)
+ ^next(%v: i32):
+ llvm.store %v, %x : i32, !llvm.ptr
+ omp.yield(%x : !llvm.ptr)
+ } -> !omp.iterated<!llvm.ptr>
+ omp.taskwait depend(taskdependin -> %it : !omp.iterated<!llvm.ptr>)
+ llvm.return
+}
+
+// CHECK-LABEL: define void @depend_narrow
+// CHECK: omp_dep_iterator.body:
+// CHECK: %[[IDX:.*]] = trunc i64 %{{.*}} to i32
+// CHECK: %[[OFF:.*]] = mul i32 %[[IDX]], 1
+// CHECK: %[[IV:.*]] = add i32 1, %[[OFF]]
+// CHECK: %[[V:.*]] = phi i32 [ %[[IV]], %omp.iterator.region ]
+// CHECK: store i32 %[[V]], ptr
diff --git a/mlir/test/Target/LLVMIR/openmp-iterator-wide.mlir b/mlir/test/Target/LLVMIR/openmp-iterator-wide.mlir
new file mode 100644
index 0000000000000..70fca4ce3ea1d
--- /dev/null
+++ b/mlir/test/Target/LLVMIR/openmp-iterator-wide.mlir
@@ -0,0 +1,74 @@
+// RUN: mlir-translate --mlir-to-llvmir %s | FileCheck %s
+
+// Bounds and induction values keep their declared width; only the trip count
+// is converted to i64.
+llvm.func @dynamic(%x: !llvm.ptr, %lb: i128, %ub: i128, %st: i128) {
+ %it = omp.iterator(%i: i128) = (%lb to %ub step %st) {
+ llvm.store %i, %x : i128, !llvm.ptr
+ omp.yield(%x : !llvm.ptr)
+ } -> !omp.iterated<!llvm.ptr>
+ omp.taskwait depend(taskdependin -> %it : !omp.iterated<!llvm.ptr>)
+ llvm.return
+}
+// CHECK-LABEL: define void @dynamic(
+// CHECK-SAME: i128 %[[LB:[0-9]+]], i128 %{{[0-9]+}}, i128 %[[ST:[0-9]+]])
+// CHECK: %[[IDX:.*]] = zext i64 %{{.*}} to i128
+// CHECK: %[[OFFSET:.*]] = mul i128 %[[IDX]], %[[ST]]
+// CHECK: %[[IV:.*]] = add i128 %[[LB]], %[[OFFSET]]
+// CHECK: store i128 %[[IV]], ptr
+
+// The unsigned linear index must also convert to narrower region arguments.
+llvm.func @narrow(%x: !llvm.ptr, %lb: i32, %ub: i32, %st: i32) {
+ %it = omp.iterator(%i: i32) = (%lb to %ub step %st) {
+ llvm.store %i, %x : i32, !llvm.ptr
+ omp.yield(%x : !llvm.ptr)
+ } -> !omp.iterated<!llvm.ptr>
+ omp.taskwait depend(taskdependin -> %it : !omp.iterated<!llvm.ptr>)
+ llvm.return
+}
+// CHECK-LABEL: define void @narrow(
+// CHECK-SAME: i32 %[[LB:[0-9]+]], i32 %{{[0-9]+}}, i32 %[[ST:[0-9]+]])
+// CHECK: %[[IDX:.*]] = trunc i64 %{{.*}} to i32
+// CHECK: %[[OFFSET:.*]] = mul i32 %[[IDX]], %[[ST]]
+// CHECK: %[[IV:.*]] = add i32 %[[LB]], %[[OFFSET]]
+// CHECK: store i32 %[[IV]], ptr
+
+llvm.func @nonempty_positive(%x: !llvm.ptr) {
+ %lb = llvm.mlir.constant(18446744073709551617 : i128) : i128
+ %ub = llvm.mlir.constant(18446744073709551619 : i128) : i128
+ %st = llvm.mlir.constant(1 : i128) : i128
+ %it = omp.iterator(%i: i128) = (%lb to %ub step %st) {
+ llvm.store %i, %x : i128, !llvm.ptr
+ omp.yield(%x : !llvm.ptr)
+ } -> !omp.iterated<!llvm.ptr>
+ omp.taskwait depend(taskdependin -> %it : !omp.iterated<!llvm.ptr>)
+ llvm.return
+}
+// CHECK-LABEL: define void @nonempty_positive(
+// CHECK: icmp ult i64 %{{.*}}, 3
+// CHECK: %[[IDX:.*]] = zext i64 %{{.*}} to i128
+// CHECK: %[[OFFSET:.*]] = mul i128 %[[IDX]], 1
+// CHECK: %[[IV:.*]] = add i128 18446744073709551617, %[[OFFSET]]
+// CHECK: store i128 %[[IV]], ptr
+// CHECK: call void @__kmpc_omp_taskwait_deps_51(
+// CHECK-SAME: i32 3, ptr %{{.*}}, i32 0, ptr null, i32 0)
+
+llvm.func @nonempty_negative(%x: !llvm.ptr) {
+ %lb = llvm.mlir.constant(18446744073709551619 : i128) : i128
+ %ub = llvm.mlir.constant(18446744073709551617 : i128) : i128
+ %st = llvm.mlir.constant(-1 : i128) : i128
+ %it = omp.iterator(%i: i128) = (%lb to %ub step %st) {
+ llvm.store %i, %x : i128, !llvm.ptr
+ omp.yield(%x : !llvm.ptr)
+ } -> !omp.iterated<!llvm.ptr>
+ omp.taskwait depend(taskdependin -> %it : !omp.iterated<!llvm.ptr>)
+ llvm.return
+}
+// CHECK-LABEL: define void @nonempty_negative(
+// CHECK: icmp ult i64 %{{.*}}, 3
+// CHECK: %[[IDX:.*]] = zext i64 %{{.*}} to i128
+// CHECK: %[[OFFSET:.*]] = mul i128 %[[IDX]], -1
+// CHECK: %[[IV:.*]] = add i128 18446744073709551619, %[[OFFSET]]
+// CHECK: store i128 %[[IV]], ptr
+// CHECK: call void @__kmpc_omp_taskwait_deps_51(
+// CHECK-SAME: i32 3, ptr %{{.*}}, i32 0, ptr null, i32 0)
>From 58a7cc1475f0757c78f5552fecd8fc6504d7ff36 Mon Sep 17 00:00:00 2001
From: "Chi-Chun, Chen" <chichun.chen at hpe.com>
Date: Wed, 30 Sep 2026 12:18:55 -0500
Subject: [PATCH 2/8] [mlir][flang][OpenMP] Select depend and affinity
iterators per locator
Flang expands each iterator-dependent depend or affinity locator over all
ranges in the clause, including iterators absent from that locator. For
example:
depend(iterator(i=1:2, j=3:m), in: a(i))
When m < 3, the unused empty j range suppresses both required dependences
on a. This can lose task ordering. A nonempty unused range instead repeats
entries unnecessarily; affinity locators have the same expansion problem.
Select ranges according to the iterator identifiers appearing in each
locator's source, preserving declaration order. Making this change safely
also requires preserving source occurrences and handling empty ranges:
- Record resolved iterator references before using the folded expression
for lowering. In a(j/d + 0*i), folding removes 0*i, but an empty i range
must still suppress the locator and prevent evaluation of j/d.
- Keep references per locator and separate from object identity, since
distinct source locators can have equal folded designators.
- Fix empty-range counting: removing an unused range can expose a
negative count previously masked by multiplication by zero. Count each
range with the canonical trip-count helper, one bit wider than its
operands so the span cannot overflow.
- Accept constant empty ranges in the verifier, retaining the zero-step
diagnostic so constant and dynamic empty ranges behave consistently.
- Test depend and affinity counts, locator evaluation guards, folded
references, shadowed names, and target-clause propagation.
Addresses the prerequisite fix requested for #197757:
https://github.com/llvm/llvm-project/pull/197757#discussion_r4079319531
Fixes https://github.com/llvm/llvm-project/issues/227443.
Assisted with codex.
---
flang/include/flang/Lower/OpenMP/Clauses.h | 12 +
flang/lib/Lower/OpenMP/ClauseProcessor.cpp | 44 ++-
flang/lib/Lower/OpenMP/Clauses.cpp | 50 +++-
flang/lib/Lower/OpenMP/Utils.cpp | 29 +-
flang/lib/Lower/OpenMP/Utils.h | 9 +-
flang/test/Lower/OpenMP/depend-iterator.f90 | 92 ++++++
.../Lower/OpenMP/iterator-empty-range.f90 | 282 ++++++++++++++++++
.../OpenMP/iterator-source-occurrences.f90 | 149 +++++++++
flang/test/Lower/OpenMP/task-affinity.f90 | 106 +++++++
mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp | 21 +-
.../OpenMP/OpenMPToLLVMIRTranslation.cpp | 20 +-
mlir/test/Dialect/OpenMP/invalid.mlir | 28 --
mlir/test/Dialect/OpenMP/iterator-empty.mlir | 18 ++
.../Target/LLVMIR/openmp-iterator-empty.mlir | 54 ++++
.../LLVMIR/openmp-iterator-multi-block.mlir | 32 ++
.../Target/LLVMIR/openmp-iterator-wide.mlir | 30 ++
mlir/test/Target/LLVMIR/openmp-iterator.mlir | 67 ++++-
17 files changed, 934 insertions(+), 109 deletions(-)
create mode 100644 flang/test/Lower/OpenMP/iterator-empty-range.f90
create mode 100644 flang/test/Lower/OpenMP/iterator-source-occurrences.f90
create mode 100644 mlir/test/Dialect/OpenMP/iterator-empty.mlir
create mode 100644 mlir/test/Target/LLVMIR/openmp-iterator-empty.mlir
diff --git a/flang/include/flang/Lower/OpenMP/Clauses.h b/flang/include/flang/Lower/OpenMP/Clauses.h
index 9d4b1aa20bbe9..fb5b5d50670f7 100644
--- a/flang/include/flang/Lower/OpenMP/Clauses.h
+++ b/flang/include/flang/Lower/OpenMP/Clauses.h
@@ -76,6 +76,11 @@ struct ObjectT<Fortran::lower::omp::IdTyTemplate<Fortran::lower::omp::ExprTy>,
using IdTy = Fortran::lower::omp::IdTyTemplate<Fortran::lower::omp::ExprTy>;
using ExprTy = Fortran::lower::omp::ExprTy;
+ ObjectT() = default;
+ ObjectT(IdTy id) : identity(std::move(id)) {}
+ ObjectT(Fortran::semantics::Symbol *symbol, std::optional<ExprTy> designator)
+ : identity{symbol, std::move(designator)} {}
+
IdTy id() const { return identity; }
Fortran::semantics::Symbol *sym() const { return identity.symbol; }
const std::optional<ExprTy> &ref() const { return identity.designator; }
@@ -85,6 +90,13 @@ struct ObjectT<Fortran::lower::omp::IdTyTemplate<Fortran::lower::omp::ExprTy>,
}
IdTy identity;
+
+ // Resolved iterator references in the source locator, before expression
+ // folding can remove them. This is per-occurrence metadata, not object
+ // identity: a(j) and a(j + 0*i) may have equal folded designators.
+ // An engaged, empty list means the locator references no clause iterators.
+ std::optional<Fortran::lower::omp::List<const Fortran::semantics::Symbol *>>
+ sourceIteratorReferences = std::nullopt;
};
} // namespace tomp::type
diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
index e41223b5b16c0..6d235c4279171 100644
--- a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
+++ b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
@@ -338,25 +338,23 @@ static mlir::Value buildIteratorOp(Fortran::lower::AbstractConverter &converter,
}
template <typename ClauseTuple>
-static void collectIteratorIVs(
- const ClauseTuple &clause, Fortran::lower::AbstractConverter &converter,
- Fortran::lower::StatementContext &stmtCtx,
- llvm::SmallVectorImpl<IteratorRange> &iteratorRanges,
- llvm::SmallPtrSetImpl<const Fortran::semantics::Symbol *> &ivSyms) {
+static llvm::SmallVector<IteratorRange>
+lowerIteratorRanges(const ClauseTuple &clause,
+ Fortran::lower::AbstractConverter &converter,
+ Fortran::lower::StatementContext &stmtCtx) {
auto &iteratorModifier =
std::get<std::optional<omp::clause::Iterator>>(clause.t);
if (!iteratorModifier.has_value())
- return;
+ return {};
+ llvm::SmallVector<IteratorRange> iteratorRanges;
mlir::Location clauseLocation = converter.getCurrentLocation();
const auto &iteratorModifierSpecs = *iteratorModifier;
iteratorRanges.reserve(iteratorModifierSpecs.size());
for (const auto &itSpec : iteratorModifierSpecs)
iteratorRanges.push_back(lowerIteratorRange<Fortran::evaluate::SomeType>(
converter, itSpec, stmtCtx, clauseLocation));
-
- for (const IteratorRange &r : iteratorRanges)
- ivSyms.insert(&r.ivSym->GetUltimate());
+ return iteratorRanges;
}
//===----------------------------------------------------------------------===//
@@ -1046,22 +1044,18 @@ bool ClauseProcessor::processAffinity(
.getResult();
};
- llvm::SmallVector<IteratorRange> iteratorRanges;
- llvm::SmallPtrSet<const Fortran::semantics::Symbol *, 4> ivSyms;
-
- auto &iteratorModifier =
- std::get<std::optional<omp::clause::Iterator>>(clause.t);
- collectIteratorIVs(clause, converter, stmtCtx, iteratorRanges, ivSyms);
+ auto iteratorRanges = lowerIteratorRanges(clause, converter, stmtCtx);
TodoLocators(clauseLocation, objects);
for (const omp::Object &object : objects) {
llvm::SmallVector<mlir::Value> bounds;
std::stringstream asFortran;
- if (iteratorModifier.has_value() &&
- hasIteratorIVReference(object, ivSyms)) {
+ llvm::SmallVector<IteratorRange> objectRanges =
+ getIteratorRangesForObject(object, iteratorRanges);
+ if (!objectRanges.empty()) {
mlir::Value iterHandle = buildIteratorOp(
- converter, clauseLocation, iterTy, iteratorRanges,
+ converter, clauseLocation, iterTy, objectRanges,
[&](fir::FirOpBuilder &builder, mlir::Location loc,
llvm::ArrayRef<mlir::Value> /*ivs*/) -> mlir::Value {
lower::StatementContext iterStmtCtx;
@@ -1509,12 +1503,7 @@ bool ClauseProcessor::processDepend(lower::SymMap &symMap,
return dependVar;
};
- auto &iteratorModifier =
- std::get<std::optional<omp::clause::Iterator>>(clause.t);
-
- llvm::SmallVector<IteratorRange> iteratorRanges;
- llvm::SmallPtrSet<const Fortran::semantics::Symbol *, 4> ivSyms;
- collectIteratorIVs(clause, converter, stmtCtx, iteratorRanges, ivSyms);
+ auto iteratorRanges = lowerIteratorRanges(clause, converter, stmtCtx);
mlir::Type ptrTy =
mlir::LLVM::LLVMPointerType::get(&converter.getMLIRContext());
@@ -1522,10 +1511,11 @@ bool ClauseProcessor::processDepend(lower::SymMap &symMap,
mlir::omp::IteratedType::get(&converter.getMLIRContext(), ptrTy);
for (const omp::Object &object : objects) {
- if (iteratorModifier.has_value() &&
- hasIteratorIVReference(object, ivSyms)) {
+ llvm::SmallVector<IteratorRange> objectRanges =
+ getIteratorRangesForObject(object, iteratorRanges);
+ if (!objectRanges.empty()) {
mlir::Value iterHandle = buildIteratorOp(
- converter, clauseLocation, iterTy, iteratorRanges,
+ converter, clauseLocation, iterTy, objectRanges,
[&](fir::FirOpBuilder &builder, mlir::Location loc,
llvm::ArrayRef<mlir::Value> /*ivs*/) -> mlir::Value {
lower::StatementContext iterStmtCtx;
diff --git a/flang/lib/Lower/OpenMP/Clauses.cpp b/flang/lib/Lower/OpenMP/Clauses.cpp
index ee16ae55af30f..5ef2af3962ad5 100644
--- a/flang/lib/Lower/OpenMP/Clauses.cpp
+++ b/flang/lib/Lower/OpenMP/Clauses.cpp
@@ -11,6 +11,7 @@
#include "flang/Common/idioms.h"
#include "flang/Evaluate/expression.h"
#include "flang/Optimizer/Builder/Todo.h"
+#include "flang/Parser/parse-tree-visitor.h"
#include "flang/Parser/parse-tree.h"
#include "flang/Semantics/expression.h"
#include "flang/Semantics/openmp-modifiers.h"
@@ -362,6 +363,49 @@ Iterator makeIterator(const parser::OmpIterator &inp,
return iterator;
}
+// Walk source syntax rather than the analyzed designator: folding can remove
+// an iterator reference that still determines whether a locator is evaluated.
+struct IteratorReferenceCollector {
+ template <typename T>
+ bool Pre(const T &) {
+ return true;
+ }
+ template <typename T>
+ void Post(const T &) {}
+
+ bool Pre(const parser::Name &name) {
+ if (name.symbol) {
+ const semantics::Symbol *symbol = &name.symbol->GetUltimate();
+ if (llvm::is_contained(iterators, symbol) &&
+ !llvm::is_contained(references, symbol))
+ references.push_back(symbol);
+ }
+ return true;
+ }
+
+ const List<const semantics::Symbol *> &iterators;
+ List<const semantics::Symbol *> &references;
+};
+
+static ObjectList makeIteratorObjects(const parser::OmpObjectList &objects,
+ const std::optional<Iterator> &iterator,
+ semantics::SemanticsContext &semaCtx) {
+ if (!iterator)
+ return makeObjects(objects, semaCtx);
+
+ List<const semantics::Symbol *> symbols;
+ for (const auto &specifier : *iterator)
+ symbols.push_back(&std::get<Object>(specifier.t).sym()->GetUltimate());
+
+ return makeList(objects.v, [&](const parser::OmpObject &source) {
+ Object object = makeObject(source, semaCtx);
+ auto &references = object.sourceIteratorReferences.emplace();
+ IteratorReferenceCollector collector{symbols, references};
+ parser::Walk(source, collector);
+ return object;
+ });
+}
+
DefinedOperator makeDefinedOperator(const parser::DefinedOperator &inp,
semantics::SemanticsContext &semaCtx) {
CLAUSET_ENUM_CONVERT( //
@@ -488,8 +532,9 @@ Affinity make(const parser::OmpClause::Affinity &inp,
auto &&maybeIter =
m0 ? makeIterator(*m0, semaCtx) : std::optional<Iterator>{};
+ auto objects = makeIteratorObjects(t1, maybeIter, semaCtx);
return Affinity{{/*Iterator=*/std::move(maybeIter),
- /*LocatorList=*/makeObjects(t1, semaCtx)}};
+ /*LocatorList=*/std::move(objects)}};
}
Align make(const parser::OmpClause::Align &inp,
@@ -764,10 +809,11 @@ Depend makeDepend(const parser::OmpDependClause::TaskDep &inp,
auto &&maybeIter =
m0 ? makeIterator(*m0, semaCtx) : std::optional<Iterator>{};
+ auto objects = makeIteratorObjects(t1, maybeIter, semaCtx);
return Depend{{/*DependenceType=*/makeDepType(*m1),
/*Iterator=*/std::move(maybeIter),
/*Vector=*/std::nullopt,
- /*LocatorList=*/makeObjects(t1, semaCtx)}};
+ /*LocatorList=*/std::move(objects)}};
}
// depend(source) / depend(sink: vec) on ordered (4.5..5.1 spelling, deprecated
diff --git a/flang/lib/Lower/OpenMP/Utils.cpp b/flang/lib/Lower/OpenMP/Utils.cpp
index e05a3eab6fad6..f53429a615a39 100644
--- a/flang/lib/Lower/OpenMP/Utils.cpp
+++ b/flang/lib/Lower/OpenMP/Utils.cpp
@@ -1086,21 +1086,20 @@ mlir::Value genAffinityLen(fir::FirOpBuilder &builder, mlir::Location loc,
builder, loc, getTotalElements(builder, loc, entity), elemBytes);
}
-bool hasIteratorIVReference(
- const omp::Object &object,
- const llvm::SmallPtrSetImpl<const Fortran::semantics::Symbol *> &ivSyms) {
- auto ref = object.ref();
- if (!ref)
- return false;
-
- Fortran::lower::SomeExpr expr = toEvExpr(*ref);
-
- for (Fortran::evaluate::SymbolRef s : CollectSymbols(expr)) {
- const Fortran::semantics::Symbol &ult = s->GetUltimate();
- if (ivSyms.contains(&ult))
- return true;
- }
- return false;
+llvm::SmallVector<IteratorRange>
+getIteratorRangesForObject(const omp::Object &object,
+ llvm::ArrayRef<IteratorRange> ranges) {
+ llvm::SmallVector<IteratorRange> objectRanges;
+ if (ranges.empty())
+ return objectRanges;
+
+ assert(object.sourceIteratorReferences &&
+ "expected source iterator references for the locator");
+ for (const IteratorRange &range : ranges)
+ if (llvm::is_contained(*object.sourceIteratorReferences,
+ &range.ivSym->GetUltimate()))
+ objectRanges.push_back(range);
+ return objectRanges;
}
void defaultMangler(Fortran::lower::AbstractConverter &converter,
diff --git a/flang/lib/Lower/OpenMP/Utils.h b/flang/lib/Lower/OpenMP/Utils.h
index 4560c9df349b2..3228905fd57c4 100644
--- a/flang/lib/Lower/OpenMP/Utils.h
+++ b/flang/lib/Lower/OpenMP/Utils.h
@@ -216,9 +216,12 @@ struct IteratorRange {
Fortran::semantics::Symbol *ivSym = nullptr;
};
-bool hasIteratorIVReference(
- const omp::Object &object,
- const llvm::SmallPtrSetImpl<const Fortran::semantics::Symbol *> &ivSyms);
+/// Select ranges referenced in the locator source, even if folding removes
+/// their occurrences from the analyzed expression. Preserve declaration order.
+/// An empty result means the locator is not iterator-dependent.
+llvm::SmallVector<IteratorRange>
+getIteratorRangesForObject(const omp::Object &object,
+ llvm::ArrayRef<IteratorRange> ranges);
/// Default name mangler for implicit default mappers.
///
diff --git a/flang/test/Lower/OpenMP/depend-iterator.f90 b/flang/test/Lower/OpenMP/depend-iterator.f90
index d785c629f5e6e..47431fce1b1a7 100644
--- a/flang/test/Lower/OpenMP/depend-iterator.f90
+++ b/flang/test/Lower/OpenMP/depend-iterator.f90
@@ -10,6 +10,98 @@
! task
!===============================================================================
+! The unused j range must not suppress a(i) when m < 3.
+subroutine depend_unused_iterator(m)
+ integer :: m
+ integer :: a(4)
+
+ !$omp task depend(iterator(i = 1:2, j = 3:m), in: a(i))
+ !$omp end task
+end subroutine
+
+! CHECK-LABEL: func.func @_QPdepend_unused_iterator(
+! CHECK: %[[A:.*]]:2 = hlfir.declare
+! CHECK-SAME: uniq_name("_QFdepend_unused_iteratorEa")
+! CHECK: %[[M:.*]]:2 = hlfir.declare
+! CHECK-SAME: uniq_name("_QFdepend_unused_iteratorEm")
+! CHECK: %[[I_LB32:.*]] = arith.constant 1 : i32
+! CHECK: %[[I_UB32:.*]] = arith.constant 2 : i32
+! CHECK: %[[I_LB:.*]] = fir.convert %[[I_LB32]] : (i32) -> index
+! CHECK: %[[I_UB:.*]] = fir.convert %[[I_UB32]] : (i32) -> index
+! CHECK: %[[I_STEP:.*]] = arith.constant 1 : index
+! CHECK: %[[IT_I:.*]] = omp.iterator(%[[IV_I:.*]]: index) =
+! CHECK-SAME: (%[[I_LB]] to %[[I_UB]] step %[[I_STEP]]) {
+! CHECK: %[[V32_I:.*]] = fir.convert %[[IV_I]] : (index) -> i32
+! CHECK: fir.store %[[V32_I]] to %[[MEM_I:.*]] : !fir.ref<i32>
+! CHECK: %[[DECL_I:.*]]:2 = hlfir.declare %[[MEM_I]]
+! CHECK: %[[LD_I:.*]] = fir.load %[[DECL_I]]#0 : !fir.ref<i32>
+! CHECK: %[[IDX_I:.*]] = fir.convert %[[LD_I]] : (i32) -> i64
+! CHECK: %[[COOR_I:.*]] = fir.array_coor %[[A]]#0(%{{.*}}) %[[IDX_I]]
+! CHECK: %[[PTR_I:.*]] = fir.convert %[[COOR_I]]
+! CHECK-SAME: (!fir.ref<i32>) -> !llvm.ptr
+! CHECK: omp.yield(%[[PTR_I]] : !llvm.ptr)
+! CHECK: } -> !omp.iterated<!llvm.ptr>
+! CHECK-NOT: omp.iterator
+! CHECK: omp.task depend(
+! CHECK-SAME: taskdependin -> %[[IT_I]] : !omp.iterated<!llvm.ptr>) {
+
+! Each locator uses its own iterator subset; c remains non-iterated.
+subroutine depend_per_locator(m)
+ integer :: m
+ integer :: a(4), b(4), c
+
+ !$omp task depend(iterator(i = 1:2, j = 3:m), in: a(i), b(j), c)
+ !$omp end task
+end subroutine
+
+! CHECK-LABEL: func.func @_QPdepend_per_locator(
+! CHECK: %[[A:.*]]:2 = hlfir.declare
+! CHECK-SAME: uniq_name("_QFdepend_per_locatorEa")
+! CHECK: %[[B:.*]]:2 = hlfir.declare
+! CHECK-SAME: uniq_name("_QFdepend_per_locatorEb")
+! CHECK: %[[C:.*]]:2 = hlfir.declare
+! CHECK-SAME: uniq_name("_QFdepend_per_locatorEc")
+! CHECK: %[[M:.*]]:2 = hlfir.declare
+! CHECK-SAME: uniq_name("_QFdepend_per_locatorEm")
+! CHECK: %[[I_LB32:.*]] = arith.constant 1 : i32
+! CHECK: %[[I_UB32:.*]] = arith.constant 2 : i32
+! CHECK: %[[I_LB:.*]] = fir.convert %[[I_LB32]] : (i32) -> index
+! CHECK: %[[I_UB:.*]] = fir.convert %[[I_UB32]] : (i32) -> index
+! CHECK: %[[I_STEP:.*]] = arith.constant 1 : index
+! CHECK: %[[J_LB32:.*]] = arith.constant 3 : i32
+! CHECK: %[[J_UB32:.*]] = fir.load %[[M]]#0 : !fir.ref<i32>
+! CHECK: %[[J_LB:.*]] = fir.convert %[[J_LB32]] : (i32) -> index
+! CHECK: %[[J_UB:.*]] = fir.convert %[[J_UB32]] : (i32) -> index
+! CHECK: %[[J_STEP:.*]] = arith.constant 1 : index
+! CHECK: %[[IT_I:.*]] = omp.iterator(%[[IV_I:.*]]: index) =
+! CHECK-SAME: (%[[I_LB]] to %[[I_UB]] step %[[I_STEP]]) {
+! CHECK: %[[V32_I:.*]] = fir.convert %[[IV_I]] : (index) -> i32
+! CHECK: fir.store %[[V32_I]] to %[[MEM_I:.*]] : !fir.ref<i32>
+! CHECK: %[[DECL_I:.*]]:2 = hlfir.declare %[[MEM_I]]
+! CHECK: %[[LD_I:.*]] = fir.load %[[DECL_I]]#0 : !fir.ref<i32>
+! CHECK: %[[IDX_I:.*]] = fir.convert %[[LD_I]] : (i32) -> i64
+! CHECK: %[[COOR_I:.*]] = fir.array_coor %[[A]]#0(%{{.*}}) %[[IDX_I]]
+! CHECK: %[[PTR_I:.*]] = fir.convert %[[COOR_I]]
+! CHECK-SAME: (!fir.ref<i32>) -> !llvm.ptr
+! CHECK: omp.yield(%[[PTR_I]] : !llvm.ptr)
+! CHECK: } -> !omp.iterated<!llvm.ptr>
+! CHECK: %[[IT_J:.*]] = omp.iterator(%[[IV_J:.*]]: index) =
+! CHECK-SAME: (%[[J_LB]] to %[[J_UB]] step %[[J_STEP]]) {
+! CHECK: %[[V32_J:.*]] = fir.convert %[[IV_J]] : (index) -> i32
+! CHECK: fir.store %[[V32_J]] to %[[MEM_J:.*]] : !fir.ref<i32>
+! CHECK: %[[DECL_J:.*]]:2 = hlfir.declare %[[MEM_J]]
+! CHECK: %[[LD_J:.*]] = fir.load %[[DECL_J]]#0 : !fir.ref<i32>
+! CHECK: %[[IDX_J:.*]] = fir.convert %[[LD_J]] : (i32) -> i64
+! CHECK: %[[COOR_J:.*]] = fir.array_coor %[[B]]#0(%{{.*}}) %[[IDX_J]]
+! CHECK: %[[PTR_J:.*]] = fir.convert %[[COOR_J]]
+! CHECK-SAME: (!fir.ref<i32>) -> !llvm.ptr
+! CHECK: omp.yield(%[[PTR_J]] : !llvm.ptr)
+! CHECK: } -> !omp.iterated<!llvm.ptr>
+! CHECK-NOT: omp.iterator
+! CHECK: omp.task depend(taskdependin -> %[[C]]#0 : !fir.ref<i32>,
+! CHECK-SAME: taskdependin -> %[[IT_I]] : !omp.iterated<!llvm.ptr>,
+! CHECK-SAME: taskdependin -> %[[IT_J]] : !omp.iterated<!llvm.ptr>) {
+
subroutine task_depend_iterator_simple()
integer, parameter :: n = 16
integer :: a(n)
diff --git a/flang/test/Lower/OpenMP/iterator-empty-range.f90 b/flang/test/Lower/OpenMP/iterator-empty-range.f90
new file mode 100644
index 0000000000000..dcdd8752dea94
--- /dev/null
+++ b/flang/test/Lower/OpenMP/iterator-empty-range.f90
@@ -0,0 +1,282 @@
+! RUN: %flang_fc1 -emit-llvm -O1 -fopenmp -fopenmp-version=52 -o - %s \
+! RUN: | FileCheck %s
+
+! Empty ranges must produce zero entries and skip locator evaluation. Test
+! dynamic bounds and both step directions. Bounds equal to the initial value
+! must still produce one entry. Constant empty ranges are tested below.
+subroutine depend_empty_positive(a, m, d)
+ integer :: a(8), m, d
+ !$omp task depend(iterator(i=3:m), in: a(i/d))
+ !$omp end task
+end
+! CHECK-LABEL: define {{.*}} @depend_empty_positive_(
+! CHECK: [[M:%.*]] = load i32, ptr
+! CHECK: [[WIDE:%.*]] = sext i32 [[M]] to i64
+! CHECK: [[EMPTY:%.*]] = icmp slt i32 [[M]], 3
+! CHECK: [[NONEMPTY:%.*]] = add nsw i64 [[WIDE]], -2
+! CHECK: [[COUNT:%.*]] = select i1 [[EMPTY]], i64 0, i64 [[NONEMPTY]]
+! CHECK: [[SIZE:%.*]] = mul {{.*}}i64 [[COUNT]], 24
+! CHECK: [[LIST:%.*]] = {{.*}}call ptr @malloc(i64 [[SIZE]])
+! CHECK: [[ZERO:%.*]] = icmp eq i64 [[COUNT]], 0
+! CHECK-NEXT: br i1 [[ZERO]], label %[[CONT:[^,]+]], label %[[BODY:.*]]
+! CHECK: [[BODY]]:
+! CHECK: sdiv i32
+! CHECK: [[CONT]]:
+! CHECK: [[RUNTIME_COUNT:%.*]] = trunc i64 [[COUNT]] to i32
+! CHECK: call i32 @__kmpc_omp_task_with_deps(
+! CHECK-SAME: ptr {{[^,]+}}, i32 {{[^,]+}}, ptr {{[^,]+}},
+! CHECK-SAME: i32 [[RUNTIME_COUNT]], ptr {{[^,)]*}}[[LIST]]
+
+subroutine affinity_empty_positive(a, m, d)
+ integer :: a(8), m, d
+ !$omp task affinity(iterator(i=3:m): a(i/d))
+ !$omp end task
+end
+! CHECK-LABEL: define {{.*}} @affinity_empty_positive_(
+! CHECK: [[M:%.*]] = load i32, ptr
+! CHECK: [[WIDE:%.*]] = sext i32 [[M]] to i64
+! CHECK: [[EMPTY:%.*]] = icmp slt i32 [[M]], 3
+! CHECK: [[NONEMPTY:%.*]] = add nsw i64 [[WIDE]], -2
+! CHECK: [[COUNT:%.*]] = select i1 [[EMPTY]], i64 0, i64 [[NONEMPTY]]
+! CHECK: [[LIST:%.*]] = alloca { i64, i64, i32 }, i64 [[COUNT]]
+! CHECK: [[ZERO:%.*]] = icmp eq i64 [[COUNT]], 0
+! CHECK-NEXT: br i1 [[ZERO]], label %[[CONT:[^,]+]], label %[[BODY:.*]]
+! CHECK: [[BODY]]:
+! CHECK: sdiv i32
+! CHECK: [[CONT]]:
+! CHECK: [[RUNTIME_COUNT:%.*]] = trunc i64 [[COUNT]] to i32
+! CHECK: call i32 @__kmpc_omp_reg_task_with_affinity(
+! CHECK-SAME: ptr {{[^,]+}}, i32 {{[^,]+}}, ptr {{[^,]+}},
+! CHECK-SAME: i32 [[RUNTIME_COUNT]], ptr {{[^,)]*}}[[LIST]]
+
+subroutine depend_empty_negative(a, m, d)
+ integer :: a(8), m, d
+ !$omp task depend(iterator(i=3:m:-2), in: a(i/d))
+ !$omp end task
+end
+! CHECK-LABEL: define {{.*}} @depend_empty_negative_(
+! CHECK: [[M:%.*]] = load i32, ptr
+! CHECK: [[WIDE:%.*]] = sext i32 [[M]] to i65
+! CHECK: [[SPAN:%.*]] = sub nsw i65 3, [[WIDE]]
+! CHECK: [[EMPTY:%.*]] = icmp sgt i32 [[M]], 3
+! CHECK: [[HALF:%.*]] = lshr i65 [[SPAN]], 1
+! CHECK: [[HALF64:%.*]] = trunc {{.*}}i65 [[HALF]] to i64
+! CHECK: [[NONEMPTY:%.*]] = add i64 [[HALF64]], 1
+! CHECK: [[COUNT:%.*]] = select i1 [[EMPTY]], i64 0, i64 [[NONEMPTY]]
+! CHECK: [[SIZE:%.*]] = mul {{.*}}i64 [[COUNT]], 24
+! CHECK: [[LIST:%.*]] = {{.*}}call ptr @malloc(i64 [[SIZE]])
+! CHECK: [[ZERO:%.*]] = icmp eq i64 [[COUNT]], 0
+! CHECK-NEXT: br i1 [[ZERO]], label %[[CONT:[^,]+]], label %[[BODY:.*]]
+! CHECK: [[BODY]]:
+! CHECK: sdiv i32
+! CHECK: [[CONT]]:
+! CHECK: [[RUNTIME_COUNT:%.*]] = trunc i64 [[COUNT]] to i32
+! CHECK: call i32 @__kmpc_omp_task_with_deps(
+! CHECK-SAME: ptr {{[^,]+}}, i32 {{[^,]+}}, ptr {{[^,]+}},
+! CHECK-SAME: i32 [[RUNTIME_COUNT]], ptr {{[^,)]*}}[[LIST]]
+
+subroutine affinity_empty_negative(a, m, d)
+ integer :: a(8), m, d
+ !$omp task affinity(iterator(i=3:m:-2): a(i/d))
+ !$omp end task
+end
+! CHECK-LABEL: define {{.*}} @affinity_empty_negative_(
+! CHECK: [[M:%.*]] = load i32, ptr
+! CHECK: [[WIDE:%.*]] = sext i32 [[M]] to i65
+! CHECK: [[SPAN:%.*]] = sub nsw i65 3, [[WIDE]]
+! CHECK: [[EMPTY:%.*]] = icmp sgt i32 [[M]], 3
+! CHECK: [[HALF:%.*]] = lshr i65 [[SPAN]], 1
+! CHECK: [[HALF64:%.*]] = trunc {{.*}}i65 [[HALF]] to i64
+! CHECK: [[NONEMPTY:%.*]] = add i64 [[HALF64]], 1
+! CHECK: [[COUNT:%.*]] = select i1 [[EMPTY]], i64 0, i64 [[NONEMPTY]]
+! CHECK: [[LIST:%.*]] = alloca { i64, i64, i32 }, i64 [[COUNT]]
+! CHECK: [[ZERO:%.*]] = icmp eq i64 [[COUNT]], 0
+! CHECK-NEXT: br i1 [[ZERO]], label %[[CONT:[^,]+]], label %[[BODY:.*]]
+! CHECK: [[BODY]]:
+! CHECK: sdiv i32
+! CHECK: [[CONT]]:
+! CHECK: [[RUNTIME_COUNT:%.*]] = trunc i64 [[COUNT]] to i32
+! CHECK: call i32 @__kmpc_omp_reg_task_with_affinity(
+! CHECK-SAME: ptr {{[^,]+}}, i32 {{[^,]+}}, ptr {{[^,]+}},
+! CHECK-SAME: i32 [[RUNTIME_COUNT]], ptr {{[^,)]*}}[[LIST]]
+
+! A zero count in either retained dimension must suppress the entire locator.
+subroutine depend_empty_product(a, m, n, d)
+ integer :: a(8,8), m, n, d
+ !$omp task depend(iterator(i=3:m, j=1:n), in: a(i/d,j))
+ !$omp end task
+end
+! CHECK-LABEL: define {{.*}} @depend_empty_product_(
+! CHECK: [[M:%.*]] = load i32, ptr
+! CHECK: [[N:%.*]] = load i32, ptr
+! CHECK: [[WIDE:%.*]] = sext i32 [[M]] to i64
+! CHECK: [[EMPTY:%.*]] = icmp slt i32 [[M]], 3
+! CHECK: [[NONEMPTY:%.*]] = add nsw i64 [[WIDE]], -2
+! CHECK: [[COUNT:%.*]] = select i1 [[EMPTY]], i64 0, i64 [[NONEMPTY]]
+! CHECK: [[NCOUNT:%.*]] = {{.*}}call i32 @llvm.smax.i32(i32 [[N]], i32 0)
+! CHECK: [[N64:%.*]] = zext {{.*}}i32 [[NCOUNT]] to i64
+! CHECK: [[TOTAL:%.*]] = mul {{.*}}i64 [[COUNT]], [[N64]]
+! CHECK: [[SIZE:%.*]] = mul {{.*}}i64 [[TOTAL]], 24
+! CHECK: [[LIST:%.*]] = {{.*}}call ptr @malloc(i64 [[SIZE]])
+! CHECK: [[ZERO:%.*]] = icmp eq i64 [[TOTAL]], 0
+! CHECK-NEXT: br i1 [[ZERO]], label %[[CONT:[^,]+]], label %[[BODY:.*]]
+! CHECK: [[BODY]]:
+! CHECK: sdiv i32
+! CHECK: [[CONT]]:
+! CHECK: [[RUNTIME_COUNT:%.*]] = trunc i64 [[TOTAL]] to i32
+! CHECK: call i32 @__kmpc_omp_task_with_deps(
+! CHECK-SAME: ptr {{[^,]+}}, i32 {{[^,]+}}, ptr {{[^,]+}},
+! CHECK-SAME: i32 [[RUNTIME_COUNT]], ptr {{[^,)]*}}[[LIST]]
+
+subroutine affinity_empty_product(a, m, n, d)
+ integer :: a(8,8), m, n, d
+ !$omp task affinity(iterator(i=3:m, j=1:n): a(i/d,j))
+ !$omp end task
+end
+! CHECK-LABEL: define {{.*}} @affinity_empty_product_(
+! CHECK: [[M:%.*]] = load i32, ptr
+! CHECK: [[N:%.*]] = load i32, ptr
+! CHECK: [[WIDE:%.*]] = sext i32 [[M]] to i64
+! CHECK: [[EMPTY:%.*]] = icmp slt i32 [[M]], 3
+! CHECK: [[NONEMPTY:%.*]] = add nsw i64 [[WIDE]], -2
+! CHECK: [[COUNT:%.*]] = select i1 [[EMPTY]], i64 0, i64 [[NONEMPTY]]
+! CHECK: [[NCOUNT:%.*]] = {{.*}}call i32 @llvm.smax.i32(i32 [[N]], i32 0)
+! CHECK: [[N64:%.*]] = zext {{.*}}i32 [[NCOUNT]] to i64
+! CHECK: [[TOTAL:%.*]] = mul {{.*}}i64 [[COUNT]], [[N64]]
+! CHECK: [[LIST:%.*]] = alloca { i64, i64, i32 }, i64 [[TOTAL]]
+! CHECK: [[ZERO:%.*]] = icmp eq i64 [[TOTAL]], 0
+! CHECK-NEXT: br i1 [[ZERO]], label %[[CONT:[^,]+]], label %[[BODY:.*]]
+! CHECK: [[BODY]]:
+! CHECK: sdiv i32
+! CHECK: [[CONT]]:
+! CHECK: [[RUNTIME_COUNT:%.*]] = trunc i64 [[TOTAL]] to i32
+! CHECK: call i32 @__kmpc_omp_reg_task_with_affinity(
+! CHECK-SAME: ptr {{[^,]+}}, i32 {{[^,]+}}, ptr {{[^,]+}},
+! CHECK-SAME: i32 [[RUNTIME_COUNT]], ptr {{[^,)]*}}[[LIST]]
+
+! Unused iterator ranges must not affect locator counts.
+
+! The unused j range must not affect the number of dependences, including
+! when m < 3 makes that range empty.
+subroutine depend_unused_iterator(a, m)
+ integer :: a(2), m
+
+ !$omp task depend(iterator(i = 1:2, j = 3:m), in: a(i))
+ !$omp end task
+end subroutine
+
+! CHECK-LABEL: define {{.*}} @depend_unused_iterator_(
+! CHECK: call i32 @__kmpc_omp_task_with_deps(
+! CHECK-SAME: ptr {{[^,]+}}, i32 {{[^,]+}}, ptr {{[^,]+}}, i32 2,
+
+! Affinity uses the same per-locator selection and must also ignore empty j.
+subroutine affinity_unused_iterator(a, m)
+ integer :: a(2), m
+
+ !$omp task affinity(iterator(i = 1:2, j = 3:m): a(i))
+ !$omp end task
+end subroutine
+
+! CHECK-LABEL: define {{.*}} @affinity_unused_iterator_(
+! CHECK: call i32 @__kmpc_omp_reg_task_with_affinity(
+! CHECK-SAME: ptr {{[^,]+}}, i32 {{[^,]+}}, ptr {{[^,]+}}, i32 2,
+
+! Source references lost during folding must still control evaluation.
+
+! The folded-away i occurrence still makes an empty i range suppress the
+! locator, including its division by d. Test both consumers of omp.iterator.
+subroutine depend_folded_empty(a, m, d)
+ integer :: a(2), m, d
+ !$omp task depend(iterator(i = 1:m, j = 1:2), in: a(j/d + 0*i))
+ !$omp end task
+end subroutine
+
+! CHECK-LABEL: define {{.*}} @depend_folded_empty_(
+! CHECK: %[[M:.*]] = load i32,
+! CHECK: %[[N:.*]] = {{.*}}call i32 @llvm.smax.i32(i32 %[[M]], i32 0)
+! CHECK: %[[COUNT:.*]] = shl{{.*}} i32 %[[N]], 1
+! CHECK: %[[TOTAL:.*]] = zext i32 %[[COUNT]] to i64
+! CHECK: %[[SIZE:.*]] = mul{{.*}} i64 %[[TOTAL]], {{[0-9]+}}
+! CHECK: call ptr @malloc(i64 %[[SIZE]])
+! CHECK-NOT: sdiv
+! CHECK: %[[EMPTY:.*]] = icmp slt i32 %[[M]], 1
+! CHECK: br i1 %[[EMPTY]], label %[[EXIT:.*]], label %[[PRE:.*]]
+! CHECK: [[PRE]]:
+! CHECK: %[[D:.*]] = load i32,
+! CHECK: br label %[[BODY:.*]]
+! CHECK: [[BODY]]:
+! CHECK: sdiv i32 %{{.*}}, %[[D]]
+! CHECK: [[EXIT]]:
+! CHECK: call i32 @__kmpc_omp_task_with_deps(
+! CHECK-SAME: ptr {{[^,]+}}, i32 {{[^,]+}}, ptr {{[^,]+}}, i32 %[[COUNT]],
+
+! A statically empty referenced range must also skip locator evaluation.
+subroutine depend_folded_zero(a, d)
+ integer :: a(2), d
+ !$omp task depend(iterator(i = 1:0, j = 1:2), in: a(j/d + 0*i))
+ !$omp end task
+end subroutine
+
+! CHECK-LABEL: define {{.*}} @depend_folded_zero_(
+! CHECK-NOT: sdiv
+! CHECK: call i32 @__kmpc_omp_task_with_deps(
+! CHECK-SAME: ptr {{[^,]+}}, i32 {{[^,]+}}, ptr {{[^,]+}}, i32 0,
+! CHECK-NOT: sdiv
+! CHECK: ret void
+
+subroutine affinity_folded_zero(a, d)
+ integer :: a(2), d
+ !$omp task affinity(iterator(i = 1:0, j = 1:2): a(j/d + 0*i))
+ !$omp end task
+end subroutine
+
+! CHECK-LABEL: define {{.*}} @affinity_folded_zero_(
+! CHECK-NOT: sdiv
+! CHECK: call i32 @__kmpc_omp_reg_task_with_affinity(
+! CHECK-SAME: ptr {{[^,]+}}, i32 {{[^,]+}}, ptr {{[^,]+}}, i32 0,
+! CHECK-NOT: sdiv
+! CHECK: ret void
+
+subroutine affinity_folded_empty(a, m, d)
+ integer :: a(2), m, d
+ !$omp task affinity(iterator(i = 1:m, j = 1:2): a(j/d + 0*i))
+ !$omp end task
+end subroutine
+
+! CHECK-LABEL: define {{.*}} @affinity_folded_empty_(
+! CHECK: %[[M:.*]] = load i32,
+! CHECK: %[[N:.*]] = {{.*}}call i32 @llvm.smax.i32(i32 %[[M]], i32 0)
+! CHECK: %[[COUNT:.*]] = shl{{.*}} i32 %[[N]], 1
+! CHECK: %[[TOTAL:.*]] = zext i32 %[[COUNT]] to i64
+! CHECK: alloca {{.*}}, i64 %[[TOTAL]]
+! CHECK-NOT: sdiv
+! CHECK: %[[EMPTY:.*]] = icmp slt i32 %[[M]], 1
+! CHECK: br i1 %[[EMPTY]], label %[[EXIT:.*]], label %[[PRE:.*]]
+! CHECK: [[PRE]]:
+! CHECK: %[[D:.*]] = load i32,
+! CHECK: br label %[[BODY:.*]]
+! CHECK: [[BODY]]:
+! CHECK: sdiv i32 %{{.*}}, %[[D]]
+! CHECK: [[EXIT]]:
+! CHECK: call i32 @__kmpc_omp_reg_task_with_affinity(
+! CHECK-SAME: ptr {{[^,]+}}, i32 {{[^,]+}}, ptr {{[^,]+}}, i32 %[[COUNT]],
+
+! An unused j must not mask an empty retained i.
+subroutine depend_retained_empty(a, m, n)
+ integer :: a(8), m, n
+ !$omp task depend(iterator(i = 3:m, j = 1:n), in: a(i))
+ !$omp end task
+end subroutine
+
+! CHECK-LABEL: define {{.*}} @depend_retained_empty_(
+! CHECK: %[[EMPTY:.*]] = icmp slt i32 %{{.*}}, 3
+! CHECK: %[[TRIPS:.*]] = select i1 %[[EMPTY]], i64 0, i64 %{{.*}}
+! CHECK: %[[SIZE:.*]] = mul{{.*}} i64 %[[TRIPS]], {{[0-9]+}}
+! CHECK: call ptr @malloc(i64 %[[SIZE]])
+! CHECK: %[[ZERO:.*]] = icmp eq i64 %[[TRIPS]], 0
+! CHECK: br i1 %[[ZERO]], label %[[EXIT:.*]], label %[[BODY:.*]]
+! CHECK: [[BODY]]:
+! CHECK: [[EXIT]]:
+! CHECK: %[[COUNT:.*]] = trunc i64 %[[TRIPS]] to i32
+! CHECK: call i32 @__kmpc_omp_task_with_deps(
+! CHECK-SAME: ptr {{[^,]+}}, i32 {{[^,]+}}, ptr {{[^,]+}}, i32 %[[COUNT]],
diff --git a/flang/test/Lower/OpenMP/iterator-source-occurrences.f90 b/flang/test/Lower/OpenMP/iterator-source-occurrences.f90
new file mode 100644
index 0000000000000..7387a54495066
--- /dev/null
+++ b/flang/test/Lower/OpenMP/iterator-source-occurrences.f90
@@ -0,0 +1,149 @@
+! RUN: bbc -emit-hlfir -fopenmp -fopenmp-version=52 -o - %s \
+! RUN: | FileCheck %s
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=52 -o - %s \
+! RUN: | FileCheck %s
+
+! Range selection follows resolved source occurrences, even when 0*i folds.
+! The enclosing i is distinct from the iterator i in the first clause.
+
+subroutine depend_folded(a, m, d, i)
+ integer :: a(2), m, d, i
+ !$omp task depend(iterator(i = 1:m, j = 1:2), &
+ !$omp& in: a(j/d + 0*i), a(1 + 0*i), a(j), a(1))
+ !$omp end task
+end subroutine
+
+! CHECK-LABEL: func.func @_QPdepend_folded(
+! CHECK: omp.iterator(%{{.*}}: index, %{{.*}}: index) =
+! CHECK: arith.divsi
+! CHECK: omp.yield
+! CHECK: omp.iterator(%{{[^,:]+}}: index) =
+! CHECK: omp.yield
+! CHECK: omp.iterator(%{{[^,:]+}}: index) =
+! CHECK: omp.yield
+! CHECK-NOT: omp.iterator
+! CHECK: omp.task
+! CHECK: return
+
+! The host i in the second clause must not be confused with iterator j.
+subroutine depend_shadowed(a, b, m, i)
+ integer :: a(2), b(2), m, i
+ !$omp task depend(iterator(i = 1:m), in: a(1 + 0*i)) &
+ !$omp& depend(iterator(j = 1:m), in: b(1 + 0*i))
+ !$omp end task
+end subroutine
+
+! CHECK-LABEL: func.func @_QPdepend_shadowed(
+! CHECK: omp.iterator(%{{[^,:]+}}: index) =
+! CHECK: omp.yield
+! CHECK-NOT: omp.iterator
+! CHECK: omp.task
+! CHECK: return
+
+subroutine affinity_folded(a, m, d, i)
+ integer :: a(2), m, d, i
+ !$omp task affinity(iterator(i = 1:m, j = 1:2): &
+ !$omp& a(j/d + 0*i), a(1 + 0*i), a(j), a(1))
+ !$omp end task
+end subroutine
+
+! CHECK-LABEL: func.func @_QPaffinity_folded(
+! CHECK: omp.iterator(%{{.*}}: index, %{{.*}}: index) =
+! CHECK: arith.divsi
+! CHECK: omp.yield
+! CHECK: omp.iterator(%{{[^,:]+}}: index) =
+! CHECK: omp.yield
+! CHECK: omp.iterator(%{{[^,:]+}}: index) =
+! CHECK: omp.yield
+! CHECK-NOT: omp.iterator
+! CHECK: omp.task
+! CHECK: return
+
+! The host i in the second task must not be confused with iterator j.
+! OpenMP 5.2 permits only one affinity clause per task directive.
+subroutine affinity_shadowed(a, b, m, i)
+ integer :: a(2), b(2), m, i
+ !$omp task affinity(iterator(i = 1:m): a(1 + 0*i))
+ !$omp end task
+ !$omp task affinity(iterator(j = 1:m): b(1 + 0*i))
+ !$omp end task
+end subroutine
+
+! CHECK-LABEL: func.func @_QPaffinity_shadowed(
+! CHECK: omp.iterator(%{{[^,:]+}}: index) =
+! CHECK: omp.yield
+! CHECK-NOT: omp.iterator
+! CHECK: omp.task
+! CHECK-NOT: omp.iterator
+! CHECK: omp.task
+! CHECK-NOT: omp.iterator
+! CHECK: return
+
+! These locators have equal folded designators but distinct source references.
+! The last one references no iterator; the middle one references both even
+! though all of its iterator references disappear during folding.
+subroutine depend_equal_designators(a, m)
+ integer :: a(2), m
+ !$omp task depend(iterator(i=1:m, j=1:2), in: a(1+0*j), a(1+0*j+0*i), a(1))
+ !$omp end task
+end
+! CHECK-LABEL: func.func @_QPdepend_equal_designators(
+! CHECK: omp.iterator(%{{[^:]+}}: index) =
+! CHECK: omp.yield
+! CHECK: omp.iterator(%{{[^:]+}}: index, %{{[^:]+}}: index) =
+! CHECK: omp.yield
+! CHECK-NOT: omp.iterator
+! CHECK: omp.task depend(
+
+subroutine affinity_equal_designators(a, m)
+ integer :: a(2), m
+ !$omp task affinity(iterator(i=1:m, j=1:2): a(1+0*j), a(1+0*j+0*i), a(1))
+ !$omp end task
+end
+! CHECK-LABEL: func.func @_QPaffinity_equal_designators(
+! CHECK: omp.iterator(%{{[^:]+}}: index) =
+! CHECK: omp.yield
+! CHECK: omp.iterator(%{{[^:]+}}: index, %{{[^:]+}}: index) =
+! CHECK: omp.yield
+! CHECK-NOT: omp.iterator
+! CHECK: omp.task affinity(
+
+! Identically spelled iterator names in different clauses have distinct scopes.
+subroutine depend_scoped_references(a, m)
+ integer :: a(2), m
+ !$omp task depend(iterator(i=1:m), in: a(1+0*i)) &
+ !$omp& depend(iterator(i=1:2), out: a(i))
+ !$omp end task
+end
+! CHECK-LABEL: func.func @_QPdepend_scoped_references(
+! CHECK: omp.iterator(%{{[^:]+}}: index) =
+! CHECK: omp.yield
+! CHECK: omp.iterator(%{{[^:]+}}: index) =
+! CHECK: omp.yield
+! CHECK: omp.task depend(
+
+! Per-locator source metadata must also survive target clause decomposition.
+subroutine target_folded_reference(a, m)
+ integer :: a(2), m
+ !$omp target parallel do map(tofrom:a) depend(iterator(i=1:m), in: a(1+0*i))
+ do k=1,2
+ a(k)=k
+ end do
+ !$omp end target parallel do
+ !$omp target enter data map(to:a) depend(iterator(i=1:m), in: a(1+0*i))
+ !$omp target update to(a) depend(iterator(i=1:m), in: a(1+0*i))
+ !$omp target exit data map(from:a) depend(iterator(i=1:m), in: a(1+0*i))
+end
+! CHECK-LABEL: func.func @_QPtarget_folded_reference(
+! CHECK: omp.iterator(%{{[^:]+}}: index) =
+! CHECK: omp.yield
+! CHECK: omp.target
+! CHECK: omp.iterator(%{{[^:]+}}: index) =
+! CHECK: omp.yield
+! CHECK: omp.target_enter_data
+! CHECK: omp.iterator(%{{[^:]+}}: index) =
+! CHECK: omp.yield
+! CHECK: omp.target_update
+! CHECK: omp.iterator(%{{[^:]+}}: index) =
+! CHECK: omp.yield
+! CHECK: omp.target_exit_data
diff --git a/flang/test/Lower/OpenMP/task-affinity.f90 b/flang/test/Lower/OpenMP/task-affinity.f90
index 0c185585627e2..17e26454add65 100644
--- a/flang/test/Lower/OpenMP/task-affinity.f90
+++ b/flang/test/Lower/OpenMP/task-affinity.f90
@@ -266,6 +266,112 @@ subroutine task_affinity_poly()
! Iterator tests
+! The unused j range must not suppress a(i) when m < 3.
+subroutine affinity_unused_iterator(m)
+ integer :: m
+ integer :: a(4)
+
+ !$omp task affinity(iterator(i = 1:2, j = 3:m) : a(i))
+ !$omp end task
+end subroutine
+
+! CHECK-LABEL: func.func @_QPaffinity_unused_iterator(
+! CHECK: %[[A:.*]]:2 = hlfir.declare
+! CHECK-SAME: uniq_name("_QFaffinity_unused_iteratorEa")
+! CHECK: %[[M:.*]]:2 = hlfir.declare
+! CHECK-SAME: uniq_name("_QFaffinity_unused_iteratorEm")
+! CHECK: %[[I_LB32:.*]] = arith.constant 1 : i32
+! CHECK: %[[I_UB32:.*]] = arith.constant 2 : i32
+! CHECK: %[[I_LB:.*]] = fir.convert %[[I_LB32]] : (i32) -> index
+! CHECK: %[[I_UB:.*]] = fir.convert %[[I_UB32]] : (i32) -> index
+! CHECK: %[[I_STEP:.*]] = arith.constant 1 : index
+! CHECK: %[[IT_I:.*]] = omp.iterator(%[[IV_I:.*]]: index) =
+! CHECK-SAME: (%[[I_LB]] to %[[I_UB]] step %[[I_STEP]]) {
+! CHECK: %[[V32_I:.*]] = fir.convert %[[IV_I]] : (index) -> i32
+! CHECK: fir.store %[[V32_I]] to %[[MEM_I:.*]] : !fir.ref<i32>
+! CHECK: %[[DECL_I:.*]]:2 = hlfir.declare %[[MEM_I]]
+! CHECK: %[[LD_I:.*]] = fir.load %[[DECL_I]]#0 : !fir.ref<i32>
+! CHECK: %[[IDX_I:.*]] = fir.convert %[[LD_I]] : (i32) -> i64
+! CHECK: %[[COOR_I:.*]] = fir.array_coor %[[A]]#0(%{{.*}}) %[[IDX_I]]
+! CHECK: %[[SIZE_I:.*]] = arith.constant 4 : i64
+! CHECK: %[[PTR_I:.*]] = fir.convert %[[COOR_I]]
+! CHECK-SAME: (!fir.ref<i32>) -> !fir.ref<i8>
+! CHECK: %[[ENTRY_I:.*]] = omp.affinity_entry %[[PTR_I]], %[[SIZE_I]]
+! CHECK: omp.yield(%[[ENTRY_I]] :
+! CHECK-SAME: !omp.affinity_entry_ty<!fir.ref<i8>, i64>)
+! CHECK: } -> !omp.iterated<!omp.affinity_entry_ty<!fir.ref<i8>, i64>>
+! CHECK-NOT: omp.iterator
+! CHECK: omp.task affinity(%[[IT_I]] :
+! CHECK-SAME: !omp.iterated<!omp.affinity_entry_ty<!fir.ref<i8>, i64>>) {
+
+! Each locator uses its own iterator subset; c remains non-iterated.
+subroutine affinity_per_locator(m)
+ integer :: m
+ integer :: a(4), b(4), c
+
+ !$omp task affinity(iterator(i = 1:2, j = 3:m) : a(i), b(j), c)
+ !$omp end task
+end subroutine
+
+! CHECK-LABEL: func.func @_QPaffinity_per_locator(
+! CHECK: %[[A:.*]]:2 = hlfir.declare
+! CHECK-SAME: uniq_name("_QFaffinity_per_locatorEa")
+! CHECK: %[[B:.*]]:2 = hlfir.declare
+! CHECK-SAME: uniq_name("_QFaffinity_per_locatorEb")
+! CHECK: %[[C:.*]]:2 = hlfir.declare
+! CHECK-SAME: uniq_name("_QFaffinity_per_locatorEc")
+! CHECK: %[[M:.*]]:2 = hlfir.declare
+! CHECK-SAME: uniq_name("_QFaffinity_per_locatorEm")
+! CHECK: %[[I_LB32:.*]] = arith.constant 1 : i32
+! CHECK: %[[I_UB32:.*]] = arith.constant 2 : i32
+! CHECK: %[[I_LB:.*]] = fir.convert %[[I_LB32]] : (i32) -> index
+! CHECK: %[[I_UB:.*]] = fir.convert %[[I_UB32]] : (i32) -> index
+! CHECK: %[[I_STEP:.*]] = arith.constant 1 : index
+! CHECK: %[[J_LB32:.*]] = arith.constant 3 : i32
+! CHECK: %[[J_UB32:.*]] = fir.load %[[M]]#0 : !fir.ref<i32>
+! CHECK: %[[J_LB:.*]] = fir.convert %[[J_LB32]] : (i32) -> index
+! CHECK: %[[J_UB:.*]] = fir.convert %[[J_UB32]] : (i32) -> index
+! CHECK: %[[J_STEP:.*]] = arith.constant 1 : index
+! CHECK: %[[IT_I:.*]] = omp.iterator(%[[IV_I:.*]]: index) =
+! CHECK-SAME: (%[[I_LB]] to %[[I_UB]] step %[[I_STEP]]) {
+! CHECK: %[[V32_I:.*]] = fir.convert %[[IV_I]] : (index) -> i32
+! CHECK: fir.store %[[V32_I]] to %[[MEM_I:.*]] : !fir.ref<i32>
+! CHECK: %[[DECL_I:.*]]:2 = hlfir.declare %[[MEM_I]]
+! CHECK: %[[LD_I:.*]] = fir.load %[[DECL_I]]#0 : !fir.ref<i32>
+! CHECK: %[[IDX_I:.*]] = fir.convert %[[LD_I]] : (i32) -> i64
+! CHECK: %[[COOR_I:.*]] = fir.array_coor %[[A]]#0(%{{.*}}) %[[IDX_I]]
+! CHECK: %[[SIZE_I:.*]] = arith.constant 4 : i64
+! CHECK: %[[PTR_I:.*]] = fir.convert %[[COOR_I]]
+! CHECK-SAME: (!fir.ref<i32>) -> !fir.ref<i8>
+! CHECK: %[[ENTRY_I:.*]] = omp.affinity_entry %[[PTR_I]], %[[SIZE_I]]
+! CHECK: omp.yield(%[[ENTRY_I]] :
+! CHECK-SAME: !omp.affinity_entry_ty<!fir.ref<i8>, i64>)
+! CHECK: } -> !omp.iterated<!omp.affinity_entry_ty<!fir.ref<i8>, i64>>
+! CHECK: %[[IT_J:.*]] = omp.iterator(%[[IV_J:.*]]: index) =
+! CHECK-SAME: (%[[J_LB]] to %[[J_UB]] step %[[J_STEP]]) {
+! CHECK: %[[V32_J:.*]] = fir.convert %[[IV_J]] : (index) -> i32
+! CHECK: fir.store %[[V32_J]] to %[[MEM_J:.*]] : !fir.ref<i32>
+! CHECK: %[[DECL_J:.*]]:2 = hlfir.declare %[[MEM_J]]
+! CHECK: %[[LD_J:.*]] = fir.load %[[DECL_J]]#0 : !fir.ref<i32>
+! CHECK: %[[IDX_J:.*]] = fir.convert %[[LD_J]] : (i32) -> i64
+! CHECK: %[[COOR_J:.*]] = fir.array_coor %[[B]]#0(%{{.*}}) %[[IDX_J]]
+! CHECK: %[[SIZE_J:.*]] = arith.constant 4 : i64
+! CHECK: %[[PTR_J:.*]] = fir.convert %[[COOR_J]]
+! CHECK-SAME: (!fir.ref<i32>) -> !fir.ref<i8>
+! CHECK: %[[ENTRY_J:.*]] = omp.affinity_entry %[[PTR_J]], %[[SIZE_J]]
+! CHECK: omp.yield(%[[ENTRY_J]] :
+! CHECK-SAME: !omp.affinity_entry_ty<!fir.ref<i8>, i64>)
+! CHECK: } -> !omp.iterated<!omp.affinity_entry_ty<!fir.ref<i8>, i64>>
+! CHECK: %[[C_PTR:.*]] = fir.convert %[[C]]#0
+! CHECK-SAME: (!fir.ref<i32>) -> !fir.ref<i8>
+! CHECK: %[[C_ENTRY:.*]] = omp.affinity_entry %[[C_PTR]],
+! CHECK-NOT: omp.iterator
+! CHECK: omp.task affinity(%[[IT_I]] :
+! CHECK-SAME: !omp.iterated<!omp.affinity_entry_ty<!fir.ref<i8>, i64>>,
+! CHECK-SAME: %[[IT_J]] :
+! CHECK-SAME: !omp.iterated<!omp.affinity_entry_ty<!fir.ref<i8>, i64>>,
+! CHECK-SAME: %[[C_ENTRY]] : !omp.affinity_entry_ty<!fir.ref<i8>, i64>) {
+
subroutine task_affinity_iterator_simple()
integer, parameter :: n = 16
integer :: a(n)
diff --git a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
index a46ae84df1784..c7dd250e06661 100644
--- a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
+++ b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
@@ -5772,28 +5772,9 @@ LogicalResult IteratorOp::verify() {
<< "range argument type does not match corresponding IV type";
}
- for (auto [lb, ub, step] : llvm::zip_equal(
- getLoopLowerBounds(), getLoopUpperBounds(), getLoopSteps())) {
+ for (Value step : getLoopSteps()) {
if (matchPattern(step, m_Zero()))
return emitOpError() << "loop step must not be zero";
-
- IntegerAttr lbAttr;
- IntegerAttr ubAttr;
- IntegerAttr stepAttr;
- if (!matchPattern(lb, m_Constant(&lbAttr)) ||
- !matchPattern(ub, m_Constant(&ubAttr)) ||
- !matchPattern(step, m_Constant(&stepAttr)))
- continue;
-
- const APInt &lbVal = lbAttr.getValue();
- const APInt &ubVal = ubAttr.getValue();
- const APInt &stepVal = stepAttr.getValue();
- if (stepVal.isStrictlyPositive() && lbVal.sgt(ubVal))
- return emitOpError() << "positive loop step requires lower bound to be "
- "less than or equal to upper bound";
- if (stepVal.isNegative() && lbVal.slt(ubVal))
- return emitOpError() << "negative loop step requires lower bound to be "
- "greater than or equal to upper bound";
}
YieldOp yield = getYieldOp();
diff --git a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
index 1e953bd071e62..80be348fe5687 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
@@ -2892,14 +2892,18 @@ class IteratorInfo {
upperBounds[d] = ub;
steps[d] = st;
- // trips = ((ub - lb) / step) + 1 (inclusive ub, assume positive step)
- llvm::Type *i64Ty = builder.getInt64Ty();
- llvm::Value *lb64 = builder.CreateSExtOrTrunc(lb, i64Ty);
- llvm::Value *ub64 = builder.CreateSExtOrTrunc(ub, i64Ty);
- llvm::Value *st64 = builder.CreateSExtOrTrunc(st, i64Ty);
- llvm::Value *diff = builder.CreateSub(ub64, lb64);
- llvm::Value *div = builder.CreateSDiv(diff, st64);
- trips[d] = builder.CreateAdd(div, llvm::ConstantInt::get(i64Ty, 1));
+ // Use a direction-aware count so an empty range contributes no entries.
+ // Widen by one bit so the span between the bounds cannot overflow.
+ llvm::Type *countTy =
+ builder.getIntNTy(lb->getType()->getIntegerBitWidth() + 1);
+ llvm::Value *start = builder.CreateSExt(lb, countTy);
+ llvm::Value *stop = builder.CreateSExt(ub, countTy);
+ llvm::Value *step = builder.CreateSExt(st, countTy);
+ llvm::Value *count =
+ moduleTranslation.getOpenMPBuilder()->calculateCanonicalLoopTripCount(
+ builder, start, stop, step, /*IsSigned=*/true,
+ /*InclusiveStop=*/true);
+ trips[d] = builder.CreateZExtOrTrunc(count, builder.getInt64Ty());
}
totalTrips = llvm::ConstantInt::get(builder.getInt64Ty(), 1);
diff --git a/mlir/test/Dialect/OpenMP/invalid.mlir b/mlir/test/Dialect/OpenMP/invalid.mlir
index 1f0a09fad85a6..bf586abf6222f 100644
--- a/mlir/test/Dialect/OpenMP/invalid.mlir
+++ b/mlir/test/Dialect/OpenMP/invalid.mlir
@@ -4929,34 +4929,6 @@ func.func @iterator_zero_step(%s2 : !llvm.struct<(ptr, i64)>) {
// -----
-func.func @iterator_positive_step_wrong_direction(%s2 : !llvm.struct<(ptr, i64)>) {
- %lb = arith.constant 1000 : index
- %ub = arith.constant -1 : index
- %st = arith.constant 10 : index
-
- // expected-error at +1 {{positive loop step requires lower bound to be less than or equal to upper bound}}
- %0 = omp.iterator(%iv: index) = (%lb to %ub step %st) {
- omp.yield(%s2 : !llvm.struct<(ptr, i64)>)
- } -> !omp.iterated<!llvm.struct<(ptr, i64)>>
- return
-}
-
-// -----
-
-func.func @iterator_negative_step_wrong_direction(%s2 : !llvm.struct<(ptr, i64)>) {
- %lb = arith.constant -1000 : index
- %ub = arith.constant 4 : index
- %st = arith.constant -999 : index
-
- // expected-error at +1 {{negative loop step requires lower bound to be greater than or equal to upper bound}}
- %0 = omp.iterator(%iv: index) = (%lb to %ub step %st) {
- omp.yield(%s2 : !llvm.struct<(ptr, i64)>)
- } -> !omp.iterated<!llvm.struct<(ptr, i64)>>
- return
-}
-
-// -----
-
func.func @iterator_missing_yield(%lb : index, %ub : index, %st : index) {
// expected-error at +1 {{region must be terminated by omp.yield}}
%0 = omp.iterator(%i: index) = (%lb to %ub step %st) {
diff --git a/mlir/test/Dialect/OpenMP/iterator-empty.mlir b/mlir/test/Dialect/OpenMP/iterator-empty.mlir
new file mode 100644
index 0000000000000..c1d8e27571e97
--- /dev/null
+++ b/mlir/test/Dialect/OpenMP/iterator-empty.mlir
@@ -0,0 +1,18 @@
+// RUN: mlir-opt %s | mlir-opt | FileCheck %s
+
+// A range pointing away from its endpoint is valid and produces no entries.
+// CHECK-LABEL: func.func @empty_ranges
+func.func @empty_ranges(%x: !llvm.ptr) {
+ %c1 = arith.constant 1 : index
+ %c3 = arith.constant 3 : index
+ %neg = arith.constant -1 : index
+ // CHECK: omp.iterator
+ %positive = omp.iterator(%i: index) = (%c3 to %c1 step %c1) {
+ omp.yield(%x : !llvm.ptr)
+ } -> !omp.iterated<!llvm.ptr>
+ // CHECK: omp.iterator
+ %negative = omp.iterator(%i: index) = (%c1 to %c3 step %neg) {
+ omp.yield(%x : !llvm.ptr)
+ } -> !omp.iterated<!llvm.ptr>
+ return
+}
diff --git a/mlir/test/Target/LLVMIR/openmp-iterator-empty.mlir b/mlir/test/Target/LLVMIR/openmp-iterator-empty.mlir
new file mode 100644
index 0000000000000..794f1e2e50e2a
--- /dev/null
+++ b/mlir/test/Target/LLVMIR/openmp-iterator-empty.mlir
@@ -0,0 +1,54 @@
+// RUN: mlir-translate --mlir-to-llvmir %s | FileCheck %s
+
+// Inclusive ranges must be checked before dividing: (2 - 3) / 2 + 1
+// truncates to one even though the range is empty.
+llvm.func @empty_positive(%x: !llvm.ptr) {
+ %c2 = llvm.mlir.constant(2 : i64) : i64
+ %c3 = llvm.mlir.constant(3 : i64) : i64
+ %it = omp.iterator(%i: i64) = (%c3 to %c2 step %c2) {
+ omp.yield(%x : !llvm.ptr)
+ } -> !omp.iterated<!llvm.ptr>
+ omp.taskwait depend(taskdependin -> %it : !omp.iterated<!llvm.ptr>)
+ llvm.return
+}
+
+// CHECK-LABEL: define void @empty_positive(
+// CHECK: call ptr @malloc(i64 0)
+// CHECK: icmp ult i64 %{{.*}}, 0
+// CHECK: call void @__kmpc_omp_taskwait_deps_51(
+// CHECK-SAME: i32 0, ptr %{{.*}}, i32 0, ptr null, i32 0)
+
+llvm.func @empty_negative(%x: !llvm.ptr) {
+ %c2 = llvm.mlir.constant(2 : i64) : i64
+ %c3 = llvm.mlir.constant(3 : i64) : i64
+ %step = llvm.mlir.constant(-2 : i64) : i64
+ %it = omp.iterator(%i: i64) = (%c2 to %c3 step %step) {
+ omp.yield(%x : !llvm.ptr)
+ } -> !omp.iterated<!llvm.ptr>
+ omp.taskwait depend(taskdependin -> %it : !omp.iterated<!llvm.ptr>)
+ llvm.return
+}
+
+// CHECK-LABEL: define void @empty_negative(
+// CHECK: call ptr @malloc(i64 0)
+// CHECK: icmp ult i64 %{{.*}}, 0
+// CHECK: call void @__kmpc_omp_taskwait_deps_51(
+// CHECK-SAME: i32 0, ptr %{{.*}}, i32 0, ptr null, i32 0)
+
+// Two negative counts must not multiply into a nonempty iteration space.
+llvm.func @empty_product(%x: !llvm.ptr) {
+ %c1 = llvm.mlir.constant(1 : i64) : i64
+ %c3 = llvm.mlir.constant(3 : i64) : i64
+ %it = omp.iterator(%i: i64, %j: i64) =
+ (%c3 to %c1 step %c1, %c3 to %c1 step %c1) {
+ omp.yield(%x : !llvm.ptr)
+ } -> !omp.iterated<!llvm.ptr>
+ omp.taskwait depend(taskdependin -> %it : !omp.iterated<!llvm.ptr>)
+ llvm.return
+}
+
+// CHECK-LABEL: define void @empty_product(
+// CHECK: call ptr @malloc(i64 0)
+// CHECK: icmp ult i64 %{{.*}}, 0
+// CHECK: call void @__kmpc_omp_taskwait_deps_51(
+// CHECK-SAME: i32 0, ptr %{{.*}}, i32 0, ptr null, i32 0)
diff --git a/mlir/test/Target/LLVMIR/openmp-iterator-multi-block.mlir b/mlir/test/Target/LLVMIR/openmp-iterator-multi-block.mlir
index b131b55a0f061..3487897912eb5 100644
--- a/mlir/test/Target/LLVMIR/openmp-iterator-multi-block.mlir
+++ b/mlir/test/Target/LLVMIR/openmp-iterator-multi-block.mlir
@@ -172,3 +172,35 @@ llvm.func @depend_narrow(%x : !llvm.ptr) {
// CHECK: %[[IV:.*]] = add i32 1, %[[OFF]]
// CHECK: %[[V:.*]] = phi i32 [ %[[IV]], %omp.iterator.region ]
// CHECK: store i32 %[[V]], ptr
+
+// An empty dynamic range, e.g. m = 2, must not evaluate the region.
+llvm.func @depend_empty_dynamic(%a : !llvm.ptr, %m : i32, %d : i32) {
+ %c2 = llvm.mlir.constant(2 : i32) : i32
+ %c3 = llvm.mlir.constant(3 : i32) : i32
+ %it = omp.iterator(%i: i32) = (%c3 to %m step %c2) {
+ %q = llvm.sdiv %i, %d : i32
+ llvm.br ^bb1(%q : i32)
+ ^bb1(%k : i32):
+ %p = llvm.getelementptr %a[%k] : (!llvm.ptr, i32) -> !llvm.ptr, i32
+ omp.yield(%p : !llvm.ptr)
+ } -> !omp.iterated<!llvm.ptr>
+ omp.task depend(taskdependin -> %it : !omp.iterated<!llvm.ptr>) {
+ omp.terminator
+ }
+ llvm.return
+}
+
+// CHECK-LABEL: define void @depend_empty_dynamic
+// CHECK-SAME: (ptr %{{.*}}, i32 %[[M:[0-9]+]], i32 %{{.*}})
+// CHECK: %[[STOP:.*]] = sext i32 %[[M]] to i33
+// CHECK: %[[LB:.*]] = select i1 false, i33 %[[STOP]], i33 3
+// CHECK: %[[UB:.*]] = select i1 false, i33 3, i33 %[[STOP]]
+// CHECK: %[[EMPTY:.*]] = icmp slt i33 %[[UB]], %[[LB]]
+// CHECK: %[[COUNT:.*]] = select i1 %[[EMPTY]], i33 0, i33 %{{.*}}
+// CHECK: %[[TRIPS:.*]] = zext i33 %[[COUNT]] to i64
+// CHECK: %[[TOTAL:.*]] = mul i64 1, %[[TRIPS]]
+// CHECK: omp_dep_iterator.cond:
+// CHECK: icmp ult i64 %omp_dep_iterator.iv, %[[TOTAL]]
+// CHECK: omp_dep_iterator.body:
+// CHECK: omp.iterator.region:
+// CHECK: sdiv i32 %omp.it.phys_iv,
diff --git a/mlir/test/Target/LLVMIR/openmp-iterator-wide.mlir b/mlir/test/Target/LLVMIR/openmp-iterator-wide.mlir
index 70fca4ce3ea1d..bf4405d8c1d29 100644
--- a/mlir/test/Target/LLVMIR/openmp-iterator-wide.mlir
+++ b/mlir/test/Target/LLVMIR/openmp-iterator-wide.mlir
@@ -12,6 +12,14 @@ llvm.func @dynamic(%x: !llvm.ptr, %lb: i128, %ub: i128, %st: i128) {
}
// CHECK-LABEL: define void @dynamic(
// CHECK-SAME: i128 %[[LB:[0-9]+]], i128 %{{[0-9]+}}, i128 %[[ST:[0-9]+]])
+// CHECK: sext i128 %{{.*}} to i129
+// CHECK: sext i128 %{{.*}} to i129
+// CHECK: sext i128 %{{.*}} to i129
+// CHECK: icmp slt i129
+// CHECK: sub nsw i129
+// CHECK: udiv i129
+// CHECK: select i1 %{{.*}}, i129 0, i129 %{{.*}}
+// CHECK: trunc i129 %{{.*}} to i64
// CHECK: %[[IDX:.*]] = zext i64 %{{.*}} to i128
// CHECK: %[[OFFSET:.*]] = mul i128 %[[IDX]], %[[ST]]
// CHECK: %[[IV:.*]] = add i128 %[[LB]], %[[OFFSET]]
@@ -28,6 +36,8 @@ llvm.func @narrow(%x: !llvm.ptr, %lb: i32, %ub: i32, %st: i32) {
}
// CHECK-LABEL: define void @narrow(
// CHECK-SAME: i32 %[[LB:[0-9]+]], i32 %{{[0-9]+}}, i32 %[[ST:[0-9]+]])
+// CHECK: sext i32 %{{.*}} to i33
+// CHECK: zext i33 %{{.*}} to i64
// CHECK: %[[IDX:.*]] = trunc i64 %{{.*}} to i32
// CHECK: %[[OFFSET:.*]] = mul i32 %[[IDX]], %[[ST]]
// CHECK: %[[IV:.*]] = add i32 %[[LB]], %[[OFFSET]]
@@ -72,3 +82,23 @@ llvm.func @nonempty_negative(%x: !llvm.ptr) {
// CHECK: store i128 %[[IV]], ptr
// CHECK: call void @__kmpc_omp_taskwait_deps_51(
// CHECK-SAME: i32 3, ptr %{{.*}}, i32 0, ptr null, i32 0)
+
+llvm.func @wide_step(%x: !llvm.ptr) {
+ %lb = llvm.mlir.constant(0 : i128) : i128
+ %ub = llvm.mlir.constant(36893488147419103232 : i128) : i128
+ %st = llvm.mlir.constant(18446744073709551616 : i128) : i128
+ %it = omp.iterator(%i: i128) = (%lb to %ub step %st) {
+ llvm.store %i, %x : i128, !llvm.ptr
+ omp.yield(%x : !llvm.ptr)
+ } -> !omp.iterated<!llvm.ptr>
+ omp.taskwait depend(taskdependin -> %it : !omp.iterated<!llvm.ptr>)
+ llvm.return
+}
+// CHECK-LABEL: define void @wide_step(
+// CHECK: icmp ult i64 %{{.*}}, 3
+// CHECK: %[[IDX:.*]] = zext i64 %{{.*}} to i128
+// CHECK: %[[OFFSET:.*]] = mul i128 %[[IDX]], 18446744073709551616
+// CHECK: %[[IV:.*]] = add i128 0, %[[OFFSET]]
+// CHECK: store i128 %[[IV]], ptr
+// CHECK: call void @__kmpc_omp_taskwait_deps_51(
+// CHECK-SAME: i32 3, ptr %{{.*}}, i32 0, ptr null, i32 0)
diff --git a/mlir/test/Target/LLVMIR/openmp-iterator.mlir b/mlir/test/Target/LLVMIR/openmp-iterator.mlir
index 7fdc6f15b0311..ad8d603d7d266 100644
--- a/mlir/test/Target/LLVMIR/openmp-iterator.mlir
+++ b/mlir/test/Target/LLVMIR/openmp-iterator.mlir
@@ -260,9 +260,12 @@ llvm.func @task_affinity_iterator_dynamic_tripcount(
}
// CHECK-LABEL: define internal void @task_affinity_iterator_dynamic_tripcount
-// CHECK: [[DIFF:%.*]] = sub i64 {{.*}}, {{.*}}
-// CHECK: [[DIV:%.*]] = sdiv i64 [[DIFF]], {{.*}}
-// CHECK: [[TRIPS:%.*]] = add i64 [[DIV]], 1
+// CHECK: [[DIFF:%.*]] = sub nsw i65 {{.*}}, {{.*}}
+// CHECK: [[EMPTY:%.*]] = icmp slt i65 {{.*}}, {{.*}}
+// CHECK: [[DIV:%.*]] = udiv i65 [[DIFF]], {{.*}}
+// CHECK: [[COUNT:%.*]] = add i65 [[DIV]], 1
+// CHECK: [[CLAMPED:%.*]] = select i1 [[EMPTY]], i65 0, i65 [[COUNT]]
+// CHECK: [[TRIPS:%.*]] = trunc i65 [[CLAMPED]] to i64
// CHECK: [[SCALED:%.*]] = mul i64 1, [[TRIPS]]
// CHECK: [[AFFLIST:%.*]] = alloca { i64, i64, i32 }, i64 [[SCALED]]
@@ -409,9 +412,20 @@ llvm.func @omp_task_depend_iterator_dynamic(%addr : !llvm.ptr,
// CHECK-LABEL: define void @omp_task_depend_iterator_dynamic
//
// Tripcount computation from dynamic bounds
-// CHECK: %[[DIFF:.*]] = sub i64 %{{.*}}, %{{.*}}
-// CHECK: %[[DIV:.*]] = sdiv i64 %[[DIFF]], %{{.*}}
-// CHECK: %[[TRIPS:.*]] = add i64 %[[DIV]], 1
+// CHECK: %[[START:.*]] = sext i64 %{{.*}} to i65
+// CHECK: %[[STOP:.*]] = sext i64 %{{.*}} to i65
+// CHECK: %[[STEP:.*]] = sext i64 %{{.*}} to i65
+// CHECK: %[[NEG:.*]] = icmp slt i65 %[[STEP]], 0
+// CHECK: %[[MAG:.*]] = sub i65 0, %[[STEP]]
+// CHECK: %[[INCR:.*]] = select i1 %[[NEG]], i65 %[[MAG]], i65 %[[STEP]]
+// CHECK: %[[LOW:.*]] = select i1 %[[NEG]], i65 %[[STOP]], i65 %[[START]]
+// CHECK: %[[HIGH:.*]] = select i1 %[[NEG]], i65 %[[START]], i65 %[[STOP]]
+// CHECK: %[[DIFF:.*]] = sub nsw i65 %[[HIGH]], %[[LOW]]
+// CHECK: %[[EMPTY:.*]] = icmp slt i65 %[[HIGH]], %[[LOW]]
+// CHECK: %[[DIV:.*]] = udiv i65 %[[DIFF]], %[[INCR]]
+// CHECK: %[[COUNT:.*]] = add i65 %[[DIV]], 1
+// CHECK: %[[CLAMPED:.*]] = select i1 %[[EMPTY]], i65 0, i65 %[[COUNT]]
+// CHECK: %[[TRIPS:.*]] = trunc i65 %[[CLAMPED]] to i64
// CHECK: %[[SCALED:.*]] = mul i64 1, %[[TRIPS]]
// Dynamic total = 0 + scaled trip count
// CHECK: %[[TOTAL:.*]] = add i64 0, %[[SCALED]]
@@ -453,6 +467,47 @@ llvm.func @omp_task_depend_iterator_dynamic_mixed(%addr : !llvm.ptr,
// CHECK: call i32 @__kmpc_omp_task_with_deps(ptr @{{.*}}, i32 %{{.*}}, ptr %{{.*}}, i32 %[[NDEPS2]], ptr %[[DEP_ARR2]], i32 0, ptr null)
// CHECK: tail call void @free(ptr %[[DEP_ARR2]])
+// A signed i64 subtraction cannot represent this span. The two iterator
+// values are INT64_MIN and -1. The final increment to INT64_MAX - 1 is also
+// representable, as required by OpenMP 5.2 section 3.2.6.
+llvm.func @omp_task_depend_iterator_wide_span(%addr : !llvm.ptr) {
+ %min = llvm.mlir.constant(-9223372036854775808 : i64) : i64
+ %zero = llvm.mlir.constant(0 : i64) : i64
+ %max = llvm.mlir.constant(9223372036854775807 : i64) : i64
+ %it = omp.iterator(%iv: i64) = (%min to %zero step %max) {
+ omp.yield(%addr : !llvm.ptr)
+ } -> !omp.iterated<!llvm.ptr>
+ omp.task depend(taskdependin -> %it : !omp.iterated<!llvm.ptr>) {
+ omp.terminator
+ }
+ llvm.return
+}
+// CHECK-LABEL: define void @omp_task_depend_iterator_wide_span
+// CHECK: call ptr @malloc(i64 40)
+// CHECK: icmp ult i64 {{.*}}, 2
+// CHECK: call i32 @__kmpc_omp_task_with_deps(
+// CHECK-SAME: ptr {{.*}}, i32 {{.*}}, ptr {{.*}}, i32 2,
+
+// Exercise the most negative step with one iterator value, zero. The final
+// increment to INT64_MIN remains representable in the iterator type.
+llvm.func @omp_task_depend_iterator_min_step(%addr : !llvm.ptr) {
+ %zero = llvm.mlir.constant(0 : i64) : i64
+ %end = llvm.mlir.constant(-1 : i64) : i64
+ %min = llvm.mlir.constant(-9223372036854775808 : i64) : i64
+ %it = omp.iterator(%iv: i64) = (%zero to %end step %min) {
+ omp.yield(%addr : !llvm.ptr)
+ } -> !omp.iterated<!llvm.ptr>
+ omp.task depend(taskdependin -> %it : !omp.iterated<!llvm.ptr>) {
+ omp.terminator
+ }
+ llvm.return
+}
+// CHECK-LABEL: define void @omp_task_depend_iterator_min_step
+// CHECK: call ptr @malloc(i64 20)
+// CHECK: icmp ult i64 {{.*}}, 1
+// CHECK: call i32 @__kmpc_omp_task_with_deps(
+// CHECK-SAME: ptr {{.*}}, i32 {{.*}}, ptr {{.*}}, i32 1,
+
//--- target.mlir
// --------------------------------------------------------------------
>From 066d3db3376a054a7acd04cf344e449918e46bf8 Mon Sep 17 00:00:00 2001
From: "Chi-Chun, Chen" <chichun.chen at hpe.com>
Date: Mon, 5 Oct 2026 01:01:06 -0500
Subject: [PATCH 3/8] Fix per-locator iterator lowering regressions
Reuse ordinary locator lowering inside depend and affinity iterators to
preserve component and vector-subscript dependence support. Keep locator
evaluation and temporary cleanup inside the iterator region so empty
selected ranges suppress evaluation. Preserve affinity section lengths.
Reject iterated dependences on unsupported target-data operations during
translation.
Bind source-occurrence checks to each locator's ranges and yielded value.
Add locator, wide-range, empty-range, and target-data diagnostic coverage,
plus locators whose lowering adds control flow to the iterator region
(LEN_TRIM, allocatable function results, and SUM inlined at -O1).
---
flang/lib/Lower/OpenMP/ClauseProcessor.cpp | 84 ++----
flang/lib/Lower/OpenMP/Utils.cpp | 111 --------
flang/lib/Lower/OpenMP/Utils.h | 9 -
.../OpenMP/iterator-locator-control-flow.f90 | 104 ++++++++
flang/test/Lower/OpenMP/depend-iterator.f90 | 62 ++---
flang/test/Lower/OpenMP/iterator-locators.f90 | 246 ++++++++++++++++++
.../OpenMP/iterator-source-occurrences.f90 | 86 +++++-
.../Lower/OpenMP/iterator-target-data.f90 | 66 +++++
flang/test/Lower/OpenMP/task-affinity.f90 | 73 +++---
.../OpenMP/OpenMPToLLVMIRTranslation.cpp | 3 +-
.../Target/LLVMIR/openmp-iterator-wide.mlir | 32 +++
mlir/test/Target/LLVMIR/openmp-todo.mlir | 47 ++++
12 files changed, 661 insertions(+), 262 deletions(-)
create mode 100644 flang/test/Integration/OpenMP/iterator-locator-control-flow.f90
create mode 100644 flang/test/Lower/OpenMP/iterator-locators.f90
create mode 100644 flang/test/Lower/OpenMP/iterator-target-data.f90
diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
index 6d235c4279171..e99c803fff5d7 100644
--- a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
+++ b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
@@ -1048,9 +1048,29 @@ bool ClauseProcessor::processAffinity(
TodoLocators(clauseLocation, objects);
- for (const omp::Object &object : objects) {
+ auto genEntry = [&](const omp::Object &object,
+ lower::StatementContext &localStmtCtx) {
+ mlir::Value addr =
+ genAffinityAddr(converter, object, localStmtCtx, clauseLocation);
llvm::SmallVector<mlir::Value> bounds;
std::stringstream asFortran;
+ fir::factory::AddrAndBoundsInfo info =
+ lower::gatherDataOperandAddrAndBounds<mlir::omp::MapBoundsOp,
+ mlir::omp::MapBoundsType>(
+ converter, builder, semaCtx, localStmtCtx, *object.sym(),
+ object.ref(), clauseLocation, asFortran, bounds,
+ treatIndexAsSection);
+ hlfir::Entity entity{info.addr};
+ mlir::Value len =
+ object.ref() && object.ref()->Rank() == 0
+ ? genElementSizeInBytes(builder, clauseLocation,
+ builder.getDataLayout(), entity)
+ : genAffinityLen(builder, clauseLocation,
+ builder.getDataLayout(), entity, bounds);
+ return makeAffinityEntry(builder, clauseLocation, entryTy, addr, len);
+ };
+
+ for (const omp::Object &object : objects) {
llvm::SmallVector<IteratorRange> objectRanges =
getIteratorRangesForObject(object, iteratorRanges);
if (!objectRanges.empty()) {
@@ -1059,43 +1079,11 @@ bool ClauseProcessor::processAffinity(
[&](fir::FirOpBuilder &builder, mlir::Location loc,
llvm::ArrayRef<mlir::Value> /*ivs*/) -> mlir::Value {
lower::StatementContext iterStmtCtx;
-
- if (std::optional<llvm::SmallVector<mlir::Value>>
- loweredIndices = getIteratorElementIndices(
- converter, object, iterStmtCtx, loc)) {
- const Fortran::semantics::Symbol *sym = object.sym();
- assert(sym && "expected symbol for iterator object");
- fir::factory::AddrAndBoundsInfo info =
- Fortran::lower::getDataOperandBaseAddr(
- converter, builder, *sym, loc,
- /*unwrapFirBox=*/false);
- hlfir::Entity entity{info.addr};
- mlir::Value iteratedAddr = genIteratorCoordinate(
- converter, entity, *loweredIndices, loc);
- mlir::Value len = genElementSizeInBytes(
- builder, loc, builder.getDataLayout(), entity);
- return makeAffinityEntry(builder, loc, entryTy,
- iteratedAddr, len);
- }
-
- TODO(loc, "object type not supported by iterator modifier");
+ return genEntry(object, iterStmtCtx);
});
result.iterated.push_back(iterHandle);
} else {
- mlir::Value addr =
- genAffinityAddr(converter, object, stmtCtx, clauseLocation);
- // get hlfir.declare for length calculation
- fir::factory::AddrAndBoundsInfo info =
- lower::gatherDataOperandAddrAndBounds<mlir::omp::MapBoundsOp,
- mlir::omp::MapBoundsType>(
- converter, builder, semaCtx, stmtCtx, *object.sym(),
- object.ref(), clauseLocation, asFortran, bounds,
- treatIndexAsSection);
- mlir::Value len =
- genAffinityLen(builder, clauseLocation, builder.getDataLayout(),
- hlfir::Entity{info.addr}, bounds);
- result.affinityVars.push_back(
- makeAffinityEntry(builder, clauseLocation, entryTy, addr, len));
+ result.affinityVars.push_back(genEntry(object, stmtCtx));
}
}
@@ -1519,29 +1507,9 @@ bool ClauseProcessor::processDepend(lower::SymMap &symMap,
[&](fir::FirOpBuilder &builder, mlir::Location loc,
llvm::ArrayRef<mlir::Value> /*ivs*/) -> mlir::Value {
lower::StatementContext iterStmtCtx;
- if (std::optional<llvm::SmallVector<mlir::Value>> loweredIndices =
- getIteratorElementIndices(converter, object, iterStmtCtx,
- loc)) {
- const Fortran::semantics::Symbol *sym = object.sym();
- assert(sym && "expected symbol for iterator object");
- // genDependVar is not reused here: getIteratorElementIndices
- // has already lowered each subscript to a FIR-level index
- // value, so the element coordinate is computed directly from
- // the base address and those indices rather than re-lowering
- // the whole designator.
- fir::factory::AddrAndBoundsInfo info =
- Fortran::lower::getDataOperandBaseAddr(
- converter, builder, *sym, loc,
- /*unwrapFirBox=*/false);
- hlfir::Entity entity{info.addr};
- mlir::Value iteratedAddr = genIteratorCoordinate(
- converter, entity, *loweredIndices, loc);
- // Convert to !llvm.ptr for the omp.yield
- return fir::ConvertOp::create(builder, loc, ptrTy,
- iteratedAddr);
- }
-
- TODO(loc, "object type not supported by iterator modifier");
+ mlir::Value addr =
+ genDependVar(object, converter.getSymbolMap(), iterStmtCtx);
+ return fir::ConvertOp::create(builder, loc, ptrTy, addr);
});
result.dependIterated.push_back(iterHandle);
result.dependIteratedKinds.push_back(dependTypeOperand);
diff --git a/flang/lib/Lower/OpenMP/Utils.cpp b/flang/lib/Lower/OpenMP/Utils.cpp
index f53429a615a39..9e37c02eac3f1 100644
--- a/flang/lib/Lower/OpenMP/Utils.cpp
+++ b/flang/lib/Lower/OpenMP/Utils.cpp
@@ -1288,117 +1288,6 @@ mlir::FlatSymbolRefAttr resolveMapperId(
return mapperId;
}
-// Build the array coordinate for an object that uses iterator variables.
-// If the object is a section, use the first element of that section
-// as the coordinate. Currently only support top-level ArrayRef designators.
-//
-// Examples:
-// a(i, j) -> coordinates for a(i, j)
-// a(i:i+1, j+2) -> coordinates for a(i, j+2)
-std::optional<llvm::SmallVector<mlir::Value>> getIteratorElementIndices(
- Fortran::lower::AbstractConverter &converter, const omp::Object &object,
- Fortran::lower::StatementContext &stmtCtx, mlir::Location loc) {
- const std::optional<ExprTy> &ref = object.ref();
- assert(ref && "expected iterator-dependent object to have a reference");
-
- std::optional<Fortran::evaluate::DataRef> dataRef =
- Fortran::evaluate::ExtractDataRef(*ref);
- if (!dataRef)
- return std::nullopt;
- const auto *arrayRef = std::get_if<Fortran::evaluate::ArrayRef>(&dataRef->u);
- if (!arrayRef || arrayRef->subscript().empty())
- return std::nullopt;
-
- auto &builder = converter.getFirOpBuilder();
- const Fortran::semantics::Symbol *sym = object.sym();
- assert(sym && "expected symbol for iterator-dependent object");
- fir::ExtendedValue dataExv = converter.getSymbolExtendedValue(*sym);
- mlir::Value one =
- builder.createIntegerConstant(loc, builder.getIndexType(), 1);
- llvm::SmallVector<mlir::Value> indices;
- indices.reserve(arrayRef->subscript().size());
-
- for (const auto &[dim, subscript] : llvm::enumerate(arrayRef->subscript())) {
- mlir::Value idx;
- if (const auto *triplet =
- std::get_if<Fortran::evaluate::Triplet>(&subscript.u)) {
- // Sections use the first element of the section as the base address, so
- // the coordinate for this dimension comes from the triplet lower bound.
- std::optional<
- Fortran::evaluate::Expr<Fortran::evaluate::SubscriptInteger>>
- lowerBound = triplet->lower();
- if (!lowerBound) {
- // Get lower bound if not provided by user.
- // For example: !$omp task affinity(iterator(i = 1:n, j = 1:m) : a(:i+1,
- // j+2))
- idx = fir::factory::readLowerBound(builder, loc, dataExv, dim, one);
- } else {
- idx = fir::getBase(
- converter.genExprValue(toEvExpr(*lowerBound), stmtCtx, &loc));
- }
- } else {
- // Not handling vector subscripts for now.
- if (subscript.Rank() > 0)
- return std::nullopt;
-
- const auto *indirect =
- std::get_if<Fortran::evaluate::IndirectSubscriptIntegerExpr>(
- &subscript.u);
- assert(indirect && "expected non-triplet subscript");
-
- // Scalar subscripts, including reordered indices and expressions like
- // i+1 or j+2, lower directly through expression lowering.
- idx = fir::getBase(
- converter.genExprValue(toEvExpr(indirect->value()), stmtCtx, &loc));
- }
- indices.push_back(idx);
- }
-
- return indices;
-}
-
-// Build the element address for an iterator-dependent affinity object from a
-// base entity and lowered indices.
-mlir::Value genIteratorCoordinate(Fortran::lower::AbstractConverter &converter,
- hlfir::Entity entity,
- llvm::ArrayRef<mlir::Value> ivs,
- mlir::Location loc) {
- auto &builder = converter.getFirOpBuilder();
- mlir::Value base = entity.getBase();
-
- // If base is a reference-to-box, load it so array_coor sees the box value
- if (auto refTy = mlir::dyn_cast<fir::ReferenceType>(base.getType())) {
- if (mlir::isa<fir::BoxType>(refTy.getEleTy()))
- base = fir::LoadOp::create(builder, loc, base);
- }
-
- // Build shape from the entity extents
- mlir::Value shape;
- auto extents = hlfir::genExtentsVector(loc, builder, entity);
- assert(extents.size() == ivs.size() &&
- "expected the number of extents and iteration variables to match for "
- "iterator");
- if (entity.mayHaveNonDefaultLowerBounds()) {
- llvm::SmallVector<mlir::Value> lowerBounds;
- lowerBounds.reserve(ivs.size());
- for (unsigned dim = 0; dim < ivs.size(); ++dim)
- lowerBounds.push_back(hlfir::genLBound(loc, builder, entity, dim));
- shape = builder.genShape(loc, lowerBounds, extents);
- } else {
- shape = fir::ShapeOp::create(builder, loc, extents);
- }
-
- mlir::Type elementToRefTy =
- fir::ReferenceType::get(entity.getFortranElementType());
-
- return fir::ArrayCoorOp::create(builder, loc, elementToRefTy,
- /*memref=*/base,
- /*shape=*/shape,
- /*slice=*/mlir::Value{},
- /*indices=*/ivs,
- /*typeparams=*/mlir::ValueRange{});
-}
-
// ---------------------------------------------------------------------------
// OpenMP variant-matching context construction from an MLIR module
// ---------------------------------------------------------------------------
diff --git a/flang/lib/Lower/OpenMP/Utils.h b/flang/lib/Lower/OpenMP/Utils.h
index 3228905fd57c4..c769380aabbb0 100644
--- a/flang/lib/Lower/OpenMP/Utils.h
+++ b/flang/lib/Lower/OpenMP/Utils.h
@@ -231,11 +231,6 @@ getIteratorRangesForObject(const omp::Object &object,
void defaultMangler(Fortran::lower::AbstractConverter &converter,
std::string &mapperIdName, llvm::StringRef memberName);
-mlir::Value genIteratorCoordinate(Fortran::lower::AbstractConverter &converter,
- hlfir::Entity entity,
- llvm::ArrayRef<mlir::Value> ivs,
- mlir::Location loc);
-
/// Resolve the declare mapper symbol to attach to a mapped object.
///
/// The default mapper path first looks for a user-defined mapper. If none
@@ -257,10 +252,6 @@ mlir::FlatSymbolRefAttr resolveMapperId(
const omp::Object &object, llvm::StringRef mapperIdName,
mlir::omp::ClauseMapFlags mapTypeBits, llvm::omp::Directive directive);
-std::optional<llvm::SmallVector<mlir::Value>> getIteratorElementIndices(
- Fortran::lower::AbstractConverter &converter, const omp::Object &object,
- Fortran::lower::StatementContext &stmtCtx, mlir::Location loc);
-
/// Walk the already-emitted MLIR parent operations starting from \p op and
/// collect the implied OpenMP construct traits in outermost-to-innermost
/// order. Used by metadirective lowering and declare-variant call resolution
diff --git a/flang/test/Integration/OpenMP/iterator-locator-control-flow.f90 b/flang/test/Integration/OpenMP/iterator-locator-control-flow.f90
new file mode 100644
index 0000000000000..11a79a353ef00
--- /dev/null
+++ b/flang/test/Integration/OpenMP/iterator-locator-control-flow.f90
@@ -0,0 +1,104 @@
+!===----------------------------------------------------------------------===!
+! This directory can be used to add Integration tests involving multiple
+! stages of the compiler (for eg. from Fortran to LLVM IR). It should not
+! contain executable tests. We should only add tests here sparingly and only
+! if there is no other way to test. Repeat this message in each test that is
+! added to this directory and sub-directories.
+!===----------------------------------------------------------------------===!
+
+! Iterator locators are lowered inside the omp.iterator region. Lowering and
+! later passes can add control flow there, which only shows up after
+! control-flow conversion, so these cases are checked through LLVM IR.
+
+! RUN: %flang_fc1 -emit-llvm -fopenmp -fopenmp-version=52 -o - %s \
+! RUN: | FileCheck %s
+! RUN: %flang_fc1 -emit-llvm -O1 -fopenmp -fopenmp-version=52 -o - %s \
+! RUN: | FileCheck %s --check-prefix=O1
+
+module m
+contains
+ function fa(i) result(r)
+ integer, intent(in) :: i
+ integer, allocatable :: r
+ allocate(r)
+ r = i + 1
+ end function
+end module
+
+! LEN_TRIM in the section bound lowers to a loop.
+subroutine depend_section_len_trim(a, s, n)
+ integer :: a(10), n
+ character(*) :: s
+ !$omp task depend(iterator(i=1:n), in: a(i:len_trim(s)))
+ !$omp end task
+end
+
+! CHECK-LABEL: define void @depend_section_len_trim_(
+! CHECK-SAME: ptr {{[^%]*}}%[[A:[0-9]+]],
+! CHECK: omp.iterator.region:
+! CHECK: phi i64
+! CHECK: getelementptr [10 x i32], ptr %[[A]]
+! CHECK: %[[P:.*]] = load ptr, ptr
+! CHECK: omp.iterator.region.cont:
+! CHECK: %[[PI:.*]] = ptrtoint ptr %[[P]] to i64
+! CHECK: store i64 %[[PI]], ptr
+! CHECK: br label %omp_dep_iterator.inc
+! CHECK: call i32 @__kmpc_omp_task_with_deps(
+
+! The affinity length spans the section up to LEN_TRIM(s).
+subroutine affinity_section_len_trim(a, s, n)
+ integer :: a(10), n
+ character(*) :: s
+ !$omp task affinity(iterator(i=1:n): a(i:len_trim(s)))
+ !$omp end task
+end
+
+! CHECK-LABEL: define void @affinity_section_len_trim_(
+! CHECK-SAME: ptr {{[^%]*}}%[[A:[0-9]+]],
+! CHECK: omp.iterator.region:
+! CHECK: phi i64
+! CHECK: getelementptr [10 x i32], ptr %[[A]]
+! CHECK: %[[P:.*]] = load ptr, ptr
+! CHECK: %[[LEN:.*]] = mul i64 %{{.*}}, 4
+! CHECK: omp.iterator.region.cont:
+! CHECK: %[[PI:.*]] = ptrtoint ptr %[[P]] to i64
+! CHECK: store i64 %[[PI]], ptr
+! CHECK: store i64 %[[LEN]], ptr
+! CHECK: br label %omp_iterator.inc
+! CHECK: call i32 @__kmpc_omp_reg_task_with_affinity(
+
+! The allocatable function result is freed conditionally.
+subroutine depend_alloc_result(a, n)
+ use m
+ integer :: a(10), n
+ !$omp task depend(iterator(i=1:n), in: a(i:fa(i)))
+ !$omp end task
+end
+
+! CHECK-LABEL: define void @depend_alloc_result_(
+! CHECK-SAME: ptr {{[^%]*}}%[[A:[0-9]+]],
+! CHECK: omp.iterator.region:
+! CHECK: call void @_QMmPfa(
+! CHECK: getelementptr [10 x i32], ptr %[[A]]
+! CHECK: %[[P:.*]] = load ptr, ptr
+! CHECK: omp.iterator.region{{[0-9]+}}:
+! CHECK: call void @free(
+! CHECK: omp.iterator.region.cont:
+! CHECK: %[[PI:.*]] = ptrtoint ptr %[[P]] to i64
+! CHECK: store i64 %[[PI]], ptr
+! CHECK: call i32 @__kmpc_omp_task_with_deps(
+
+! At -O1, SUM is inlined into the region of a folded locator.
+subroutine depend_folded_sum(a, v, n)
+ integer :: a(10), v(3), n
+ !$omp task depend(iterator(i=1:n), in: a(sum(v)+0*i))
+ !$omp end task
+end
+
+! O1-LABEL: define void @depend_folded_sum_(
+! O1-SAME: ptr {{[^%]*}}%[[A:[0-9]+]], ptr {{[^%]*}}%[[V:[0-9]+]],
+! O1: omp.iterator.region{{[0-9]*}}:
+! O1: getelementptr {{.*}}ptr %[[V]]
+! O1: omp.iterator.region{{[0-9]*}}:
+! O1: getelementptr {{.*}}ptr %[[A]]
+! O1: call i32 @__kmpc_omp_task_with_deps(
diff --git a/flang/test/Lower/OpenMP/depend-iterator.f90 b/flang/test/Lower/OpenMP/depend-iterator.f90
index 47431fce1b1a7..bd83fdc8a01ad 100644
--- a/flang/test/Lower/OpenMP/depend-iterator.f90
+++ b/flang/test/Lower/OpenMP/depend-iterator.f90
@@ -36,7 +36,7 @@ subroutine depend_unused_iterator(m)
! CHECK: %[[DECL_I:.*]]:2 = hlfir.declare %[[MEM_I]]
! CHECK: %[[LD_I:.*]] = fir.load %[[DECL_I]]#0 : !fir.ref<i32>
! CHECK: %[[IDX_I:.*]] = fir.convert %[[LD_I]] : (i32) -> i64
-! CHECK: %[[COOR_I:.*]] = fir.array_coor %[[A]]#0(%{{.*}}) %[[IDX_I]]
+! CHECK: %[[COOR_I:.*]] = hlfir.designate %[[A]]#0 (%[[IDX_I]])
! CHECK: %[[PTR_I:.*]] = fir.convert %[[COOR_I]]
! CHECK-SAME: (!fir.ref<i32>) -> !llvm.ptr
! CHECK: omp.yield(%[[PTR_I]] : !llvm.ptr)
@@ -80,7 +80,7 @@ subroutine depend_per_locator(m)
! CHECK: %[[DECL_I:.*]]:2 = hlfir.declare %[[MEM_I]]
! CHECK: %[[LD_I:.*]] = fir.load %[[DECL_I]]#0 : !fir.ref<i32>
! CHECK: %[[IDX_I:.*]] = fir.convert %[[LD_I]] : (i32) -> i64
-! CHECK: %[[COOR_I:.*]] = fir.array_coor %[[A]]#0(%{{.*}}) %[[IDX_I]]
+! CHECK: %[[COOR_I:.*]] = hlfir.designate %[[A]]#0 (%[[IDX_I]])
! CHECK: %[[PTR_I:.*]] = fir.convert %[[COOR_I]]
! CHECK-SAME: (!fir.ref<i32>) -> !llvm.ptr
! CHECK: omp.yield(%[[PTR_I]] : !llvm.ptr)
@@ -92,7 +92,7 @@ subroutine depend_per_locator(m)
! CHECK: %[[DECL_J:.*]]:2 = hlfir.declare %[[MEM_J]]
! CHECK: %[[LD_J:.*]] = fir.load %[[DECL_J]]#0 : !fir.ref<i32>
! CHECK: %[[IDX_J:.*]] = fir.convert %[[LD_J]] : (i32) -> i64
-! CHECK: %[[COOR_J:.*]] = fir.array_coor %[[B]]#0(%{{.*}}) %[[IDX_J]]
+! CHECK: %[[COOR_J:.*]] = hlfir.designate %[[B]]#0 (%[[IDX_J]])
! CHECK: %[[PTR_J:.*]] = fir.convert %[[COOR_J]]
! CHECK-SAME: (!fir.ref<i32>) -> !llvm.ptr
! CHECK: omp.yield(%[[PTR_J]] : !llvm.ptr)
@@ -121,8 +121,7 @@ subroutine task_depend_iterator_simple()
! CHECK: %[[IV_DECL:.*]]:2 = hlfir.declare %[[IV_MEM]] uniq_name("_QQ{{.*}}.omp.iter")
! CHECK: %[[IV_LD:.*]] = fir.load %[[IV_DECL]]#0 : !fir.ref<i32>
! CHECK: %[[IV_I64:.*]] = fir.convert %[[IV_LD]] : (i32) -> i64
-! CHECK: %[[SHAPE:.*]] = fir.shape %c16 : (index) -> !fir.shape<1>
-! CHECK: %[[COOR:.*]] = fir.array_coor %[[A]]#0(%[[SHAPE]]) %[[IV_I64]] : (!fir.ref<!fir.array<16xi32>>, !fir.shape<1>, i64) -> !fir.ref<i32>
+! CHECK: %[[COOR:.*]] = hlfir.designate %[[A]]#0 (%[[IV_I64]])
! CHECK: %[[PTR:.*]] = fir.convert %[[COOR]] : (!fir.ref<i32>) -> !llvm.ptr
! CHECK: omp.yield(%[[PTR]] : !llvm.ptr)
! CHECK: } -> !omp.iterated<!llvm.ptr>
@@ -151,8 +150,7 @@ subroutine task_depend_iterator_2d()
! CHECK: %[[IV0_I64:.*]] = fir.convert %[[IV0_LD]] : (i32) -> i64
! CHECK: %[[IV1_LD:.*]] = fir.load %[[IV1_DECL]]#0 : !fir.ref<i32>
! CHECK: %[[IV1_I64:.*]] = fir.convert %[[IV1_LD]] : (i32) -> i64
-! CHECK: %[[SHAPE:.*]] = fir.shape %c4, %c6 : (index, index) -> !fir.shape<2>
-! CHECK: %[[COOR:.*]] = fir.array_coor %{{.*}}(%[[SHAPE]]) %[[IV0_I64]], %[[IV1_I64]] : (!fir.ref<!fir.array<4x6xi32>>, !fir.shape<2>, i64, i64) -> !fir.ref<i32>
+! CHECK: %[[COOR:.*]] = hlfir.designate %{{.*}} (%[[IV0_I64]], %[[IV1_I64]])
! CHECK: %[[PTR:.*]] = fir.convert %[[COOR]] : (!fir.ref<i32>) -> !llvm.ptr
! CHECK: omp.yield(%[[PTR]] : !llvm.ptr)
! CHECK: } -> !omp.iterated<!llvm.ptr>
@@ -209,12 +207,12 @@ subroutine task_depend_iterator_multi_obj()
! CHECK: %[[A:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) uniq_name("_QFtask_depend_iterator_multi_objEa")
! CHECK: %[[B:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) uniq_name("_QFtask_depend_iterator_multi_objEb")
! CHECK: %[[IT1:.*]] = omp.iterator(%[[IV1:.*]]: index) = ({{.*}} to {{.*}} step {{.*}}) {
-! CHECK: %[[COOR1:.*]] = fir.array_coor %[[A]]#0(%{{.*}}) %{{.*}} : (!fir.ref<!fir.array<16xi32>>, !fir.shape<1>, i64) -> !fir.ref<i32>
+! CHECK: %[[COOR1:.*]] = hlfir.designate %[[A]]#0 (%{{.*}})
! CHECK: %[[PTR1:.*]] = fir.convert %[[COOR1]] : (!fir.ref<i32>) -> !llvm.ptr
! CHECK: omp.yield(%[[PTR1]] : !llvm.ptr)
! CHECK: } -> !omp.iterated<!llvm.ptr>
! CHECK: %[[IT2:.*]] = omp.iterator(%[[IV2:.*]]: index) = ({{.*}} to {{.*}} step {{.*}}) {
-! CHECK: %[[COOR2:.*]] = fir.array_coor %[[B]]#0(%{{.*}}) %{{.*}} : (!fir.ref<!fir.array<16xi32>>, !fir.shape<1>, i64) -> !fir.ref<i32>
+! CHECK: %[[COOR2:.*]] = hlfir.designate %[[B]]#0 (%{{.*}})
! CHECK: %[[PTR2:.*]] = fir.convert %[[COOR2]] : (!fir.ref<i32>) -> !llvm.ptr
! CHECK: omp.yield(%[[PTR2]] : !llvm.ptr)
! CHECK: } -> !omp.iterated<!llvm.ptr>
@@ -243,13 +241,13 @@ subroutine task_depend_iterator_expr_subscript()
! CHECK: %[[IV1_DECL:.*]]:2 = hlfir.declare %[[IV1_MEM]]
! CHECK: %[[IV0_LD:.*]] = fir.load %[[IV0_DECL]]#0 : !fir.ref<i32>
! CHECK: %[[C1_I32:.*]] = arith.constant 1 : i32
-! CHECK: %[[SUB:.*]] = arith.subi %[[IV0_LD]], %[[C1_I32]] : i32
+! CHECK: %[[SUB:.*]] = arith.subi %[[IV0_LD]], %[[C1_I32]] overflow<nsw> : i32
! CHECK: %[[NOREASSOC:.*]] = hlfir.no_reassoc %[[SUB]] : i32
-! CHECK: %[[MUL:.*]] = arith.muli %{{.*}}, %[[NOREASSOC]] : i32
+! CHECK: %[[MUL:.*]] = arith.muli %{{.*}}, %[[NOREASSOC]] overflow<nsw> : i32
! CHECK: %[[IV1_LD:.*]] = fir.load %[[IV1_DECL]]#0 : !fir.ref<i32>
-! CHECK: %[[ADD:.*]] = arith.addi %[[MUL]], %[[IV1_LD]] : i32
+! CHECK: %[[ADD:.*]] = arith.addi %[[MUL]], %[[IV1_LD]] overflow<nsw> : i32
! CHECK: %[[IDX:.*]] = fir.convert %[[ADD]] : (i32) -> i64
-! CHECK: %[[COOR:.*]] = fir.array_coor %[[A]]#0(%{{.*}}) %[[IDX]] : (!fir.ref<!fir.array<16xi32>>, !fir.shape<1>, i64) -> !fir.ref<i32>
+! CHECK: %[[COOR:.*]] = hlfir.designate %[[A]]#0 (%[[IDX]])
! CHECK: %[[PTR:.*]] = fir.convert %[[COOR]] : (!fir.ref<i32>) -> !llvm.ptr
! CHECK: omp.yield(%[[PTR]] : !llvm.ptr)
! CHECK: } -> !omp.iterated<!llvm.ptr>
@@ -270,12 +268,12 @@ subroutine task_depend_multi_iter_clauses()
! CHECK: %[[A:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) uniq_name("_QFtask_depend_multi_iter_clausesEa")
! CHECK: %[[B:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) uniq_name("_QFtask_depend_multi_iter_clausesEb")
! CHECK: %[[IT1:.*]] = omp.iterator(%[[IV1:.*]]: index) = ({{.*}} to {{.*}} step {{.*}}) {
-! CHECK: %[[COOR1:.*]] = fir.array_coor %[[A]]#0(%{{.*}}) %{{.*}} : (!fir.ref<!fir.array<8xi32>>, !fir.shape<1>, i64) -> !fir.ref<i32>
+! CHECK: %[[COOR1:.*]] = hlfir.designate %[[A]]#0 (%{{.*}})
! CHECK: %[[PTR1:.*]] = fir.convert %[[COOR1]] : (!fir.ref<i32>) -> !llvm.ptr
! CHECK: omp.yield(%[[PTR1]] : !llvm.ptr)
! CHECK: } -> !omp.iterated<!llvm.ptr>
! CHECK: %[[IT2:.*]] = omp.iterator(%[[IV2:.*]]: index) = ({{.*}} to {{.*}} step {{.*}}) {
-! CHECK: %[[COOR2:.*]] = fir.array_coor %[[B]]#0(%{{.*}}) %{{.*}} : (!fir.ref<!fir.array<8xi32>>, !fir.shape<1>, i64) -> !fir.ref<i32>
+! CHECK: %[[COOR2:.*]] = hlfir.designate %[[B]]#0 (%{{.*}})
! CHECK: %[[PTR2:.*]] = fir.convert %[[COOR2]] : (!fir.ref<i32>) -> !llvm.ptr
! CHECK: omp.yield(%[[PTR2]] : !llvm.ptr)
! CHECK: } -> !omp.iterated<!llvm.ptr>
@@ -318,7 +316,7 @@ subroutine task_depend_iterator_mixed_within_clause()
! CHECK: %[[A:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) uniq_name("_QFtask_depend_iterator_mixed_within_clauseEa")
! CHECK: %[[A1:.*]] = hlfir.designate %[[A]]#0 (%{{.*}}) : (!fir.ref<!fir.array<16xi32>>, index) -> !fir.ref<i32>
! CHECK: %[[IT:.*]] = omp.iterator(%[[IV:.*]]: index) = ({{.*}} to {{.*}} step {{.*}}) {
-! CHECK: %[[COOR:.*]] = fir.array_coor %[[A]]#0(%{{.*}}) %{{.*}} : (!fir.ref<!fir.array<16xi32>>, !fir.shape<1>, i64) -> !fir.ref<i32>
+! CHECK: %[[COOR:.*]] = hlfir.designate %[[A]]#0 (%{{.*}})
! CHECK: %[[PTR:.*]] = fir.convert %[[COOR]] : (!fir.ref<i32>) -> !llvm.ptr
! CHECK: omp.yield(%[[PTR]] : !llvm.ptr)
! CHECK: } -> !omp.iterated<!llvm.ptr>
@@ -346,8 +344,7 @@ subroutine target_depend_iterator()
! CHECK: %[[IV_DECL:.*]]:2 = hlfir.declare %[[IV_MEM]]
! CHECK: %[[IV_LD:.*]] = fir.load %[[IV_DECL]]#0 : !fir.ref<i32>
! CHECK: %[[IV_I64:.*]] = fir.convert %[[IV_LD]] : (i32) -> i64
-! CHECK: %[[SHAPE:.*]] = fir.shape %c16 : (index) -> !fir.shape<1>
-! CHECK: %[[COOR:.*]] = fir.array_coor %[[A]]#0(%[[SHAPE]]) %[[IV_I64]] : (!fir.ref<!fir.array<16xi32>>, !fir.shape<1>, i64) -> !fir.ref<i32>
+! CHECK: %[[COOR:.*]] = hlfir.designate %[[A]]#0 (%[[IV_I64]])
! CHECK: %[[PTR:.*]] = fir.convert %[[COOR]] : (!fir.ref<i32>) -> !llvm.ptr
! CHECK: omp.yield(%[[PTR]] : !llvm.ptr)
! CHECK: } -> !omp.iterated<!llvm.ptr>
@@ -373,15 +370,15 @@ subroutine target_depend_iterator_multi()
! CHECK: %[[B:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) uniq_name("_QFtarget_depend_iterator_multiEb")
! CHECK: %[[C:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) uniq_name("_QFtarget_depend_iterator_multiEc")
! CHECK: %[[IT1:.*]] = omp.iterator(%{{.*}}: index) = ({{.*}} to {{.*}} step {{.*}}) {
-! CHECK: %[[COOR1:.*]] = fir.array_coor %[[A]]#0(%{{.*}}) %{{.*}} : (!fir.ref<!fir.array<8xi32>>, !fir.shape<1>, i64) -> !fir.ref<i32>
+! CHECK: %[[COOR1:.*]] = hlfir.designate %[[A]]#0 (%{{.*}})
! CHECK: omp.yield(%{{.*}} : !llvm.ptr)
! CHECK: } -> !omp.iterated<!llvm.ptr>
! CHECK: %[[IT2:.*]] = omp.iterator(%{{.*}}: index) = ({{.*}} to {{.*}} step {{.*}}) {
-! CHECK: %[[COOR2:.*]] = fir.array_coor %[[B]]#0(%{{.*}}) %{{.*}} : (!fir.ref<!fir.array<8xi32>>, !fir.shape<1>, i64) -> !fir.ref<i32>
+! CHECK: %[[COOR2:.*]] = hlfir.designate %[[B]]#0 (%{{.*}})
! CHECK: omp.yield(%{{.*}} : !llvm.ptr)
! CHECK: } -> !omp.iterated<!llvm.ptr>
! CHECK: %[[IT3:.*]] = omp.iterator(%{{.*}}: index) = ({{.*}} to {{.*}} step {{.*}}) {
-! CHECK: %[[COOR3:.*]] = fir.array_coor %[[C]]#0(%{{.*}}) %{{.*}} : (!fir.ref<!fir.array<8xi32>>, !fir.shape<1>, i64) -> !fir.ref<i32>
+! CHECK: %[[COOR3:.*]] = hlfir.designate %[[C]]#0 (%{{.*}})
! CHECK: omp.yield(%{{.*}} : !llvm.ptr)
! CHECK: } -> !omp.iterated<!llvm.ptr>
! CHECK: %[[MAP_A:.*]] = omp.map.info var_ptr(%[[A]]#1 : {{.*}}) map_clauses(tofrom) capture(ByRef) bounds({{.*}}) name("a") -> !fir.ref<!fir.array<8xi32>>
@@ -409,8 +406,7 @@ subroutine target_enter_data_depend_iterator()
! CHECK: %[[IV_DECL:.*]]:2 = hlfir.declare %[[IV_MEM]]
! CHECK: %[[IV_LD:.*]] = fir.load %[[IV_DECL]]#0 : !fir.ref<i32>
! CHECK: %[[IV_I64:.*]] = fir.convert %[[IV_LD]] : (i32) -> i64
-! CHECK: %[[SHAPE:.*]] = fir.shape %c16 : (index) -> !fir.shape<1>
-! CHECK: %[[COOR:.*]] = fir.array_coor %[[A]]#0(%[[SHAPE]]) %[[IV_I64]] : (!fir.ref<!fir.array<16xi32>>, !fir.shape<1>, i64) -> !fir.ref<i32>
+! CHECK: %[[COOR:.*]] = hlfir.designate %[[A]]#0 (%[[IV_I64]])
! CHECK: %[[PTR:.*]] = fir.convert %[[COOR]] : (!fir.ref<i32>) -> !llvm.ptr
! CHECK: omp.yield(%[[PTR]] : !llvm.ptr)
! CHECK: } -> !omp.iterated<!llvm.ptr>
@@ -440,11 +436,11 @@ subroutine target_enter_data_depend_iterator_expr()
! CHECK: %[[IV0_LD:.*]] = fir.load %[[IV0_DECL]]#0 : !fir.ref<i32>
! CHECK: %[[SUB:.*]] = arith.subi %[[IV0_LD]], %{{.*}} : i32
! CHECK: %[[NOREASSOC:.*]] = hlfir.no_reassoc %[[SUB]] : i32
-! CHECK: %[[MUL:.*]] = arith.muli %{{.*}}, %[[NOREASSOC]] : i32
+! CHECK: %[[MUL:.*]] = arith.muli %{{.*}}, %[[NOREASSOC]] overflow<nsw> : i32
! CHECK: %[[IV1_LD:.*]] = fir.load %[[IV1_DECL]]#0 : !fir.ref<i32>
-! CHECK: %[[ADD:.*]] = arith.addi %[[MUL]], %[[IV1_LD]] : i32
+! CHECK: %[[ADD:.*]] = arith.addi %[[MUL]], %[[IV1_LD]] overflow<nsw> : i32
! CHECK: %[[IDX:.*]] = fir.convert %[[ADD]] : (i32) -> i64
-! CHECK: %[[COOR:.*]] = fir.array_coor %[[A]]#0(%{{.*}}) %[[IDX]] : (!fir.ref<!fir.array<16xi32>>, !fir.shape<1>, i64) -> !fir.ref<i32>
+! CHECK: %[[COOR:.*]] = hlfir.designate %[[A]]#0 (%[[IDX]])
! CHECK: omp.yield(%{{.*}} : !llvm.ptr)
! CHECK: } -> !omp.iterated<!llvm.ptr>
! CHECK: %[[MAP:.*]] = omp.map.info var_ptr(%[[A]]#1 : {{.*}}) map_clauses(to) capture(ByRef) bounds({{.*}}) name("a") -> !fir.ref<!fir.array<16xi32>>
@@ -470,8 +466,7 @@ subroutine target_exit_data_depend_iterator()
! CHECK: %[[IV_DECL:.*]]:2 = hlfir.declare %[[IV_MEM]]
! CHECK: %[[IV_LD:.*]] = fir.load %[[IV_DECL]]#0 : !fir.ref<i32>
! CHECK: %[[IV_I64:.*]] = fir.convert %[[IV_LD]] : (i32) -> i64
-! CHECK: %[[SHAPE:.*]] = fir.shape %c16 : (index) -> !fir.shape<1>
-! CHECK: %[[COOR:.*]] = fir.array_coor %[[A]]#0(%[[SHAPE]]) %[[IV_I64]] : (!fir.ref<!fir.array<16xi32>>, !fir.shape<1>, i64) -> !fir.ref<i32>
+! CHECK: %[[COOR:.*]] = hlfir.designate %[[A]]#0 (%[[IV_I64]])
! CHECK: %[[PTR:.*]] = fir.convert %[[COOR]] : (!fir.ref<i32>) -> !llvm.ptr
! CHECK: omp.yield(%[[PTR]] : !llvm.ptr)
! CHECK: } -> !omp.iterated<!llvm.ptr>
@@ -497,11 +492,11 @@ subroutine target_exit_data_depend_iterator_multi()
! CHECK: %[[CM1_I32:.*]] = arith.constant -1 : i32
! CHECK: %[[STEP:.*]] = fir.convert %[[CM1_I32]] : (i32) -> index
! CHECK: %[[IT1:.*]] = omp.iterator(%{{.*}}: index) = (%[[LB]] to %[[UB]] step %[[STEP]]) {
-! CHECK: %[[COOR1:.*]] = fir.array_coor %[[A]]#0(%{{.*}}) %{{.*}} : (!fir.ref<!fir.array<16xi32>>, !fir.shape<1>, i64) -> !fir.ref<i32>
+! CHECK: %[[COOR1:.*]] = hlfir.designate %[[A]]#0 (%{{.*}})
! CHECK: omp.yield(%{{.*}} : !llvm.ptr)
! CHECK: } -> !omp.iterated<!llvm.ptr>
! CHECK: %[[IT2:.*]] = omp.iterator(%{{.*}}: index) = (%[[LB]] to %[[UB]] step %[[STEP]]) {
-! CHECK: %[[COOR2:.*]] = fir.array_coor %[[B]]#0(%{{.*}}) %{{.*}} : (!fir.ref<!fir.array<16xi32>>, !fir.shape<1>, i64) -> !fir.ref<i32>
+! CHECK: %[[COOR2:.*]] = hlfir.designate %[[B]]#0 (%{{.*}})
! CHECK: omp.yield(%{{.*}} : !llvm.ptr)
! CHECK: } -> !omp.iterated<!llvm.ptr>
! CHECK: %[[MAP_A:.*]] = omp.map.info var_ptr(%[[A]]#1 : {{.*}}) map_clauses(from) capture(ByRef) bounds({{.*}}) name("a") -> !fir.ref<!fir.array<16xi32>>
@@ -528,8 +523,7 @@ subroutine target_update_depend_iterator()
! CHECK: %[[IV_DECL:.*]]:2 = hlfir.declare %[[IV_MEM]]
! CHECK: %[[IV_LD:.*]] = fir.load %[[IV_DECL]]#0 : !fir.ref<i32>
! CHECK: %[[IV_I64:.*]] = fir.convert %[[IV_LD]] : (i32) -> i64
-! CHECK: %[[SHAPE:.*]] = fir.shape %c16 : (index) -> !fir.shape<1>
-! CHECK: %[[COOR:.*]] = fir.array_coor %[[A]]#0(%[[SHAPE]]) %[[IV_I64]] : (!fir.ref<!fir.array<16xi32>>, !fir.shape<1>, i64) -> !fir.ref<i32>
+! CHECK: %[[COOR:.*]] = hlfir.designate %[[A]]#0 (%[[IV_I64]])
! CHECK: %[[PTR:.*]] = fir.convert %[[COOR]] : (!fir.ref<i32>) -> !llvm.ptr
! CHECK: omp.yield(%[[PTR]] : !llvm.ptr)
! CHECK: } -> !omp.iterated<!llvm.ptr>
@@ -554,11 +548,11 @@ subroutine target_update_depend_iterator_multi()
! CHECK: %[[B:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) uniq_name("_QFtarget_update_depend_iterator_multiEb")
! CHECK: %[[X:.*]]:2 = hlfir.declare %{{.*}} uniq_name("_QFtarget_update_depend_iterator_multiEx")
! CHECK: %[[IT1:.*]] = omp.iterator(%{{.*}}: index) = ({{.*}} to {{.*}} step {{.*}}) {
-! CHECK: %[[COOR1:.*]] = fir.array_coor %[[A]]#0(%{{.*}}) %{{.*}} : (!fir.ref<!fir.array<8xi32>>, !fir.shape<1>, i64) -> !fir.ref<i32>
+! CHECK: %[[COOR1:.*]] = hlfir.designate %[[A]]#0 (%{{.*}})
! CHECK: omp.yield(%{{.*}} : !llvm.ptr)
! CHECK: } -> !omp.iterated<!llvm.ptr>
! CHECK: %[[IT2:.*]] = omp.iterator(%{{.*}}: index) = ({{.*}} to {{.*}} step {{.*}}) {
-! CHECK: %[[COOR2:.*]] = fir.array_coor %[[B]]#0(%{{.*}}) %{{.*}} : (!fir.ref<!fir.array<8xi32>>, !fir.shape<1>, i64) -> !fir.ref<i32>
+! CHECK: %[[COOR2:.*]] = hlfir.designate %[[B]]#0 (%{{.*}})
! CHECK: omp.yield(%{{.*}} : !llvm.ptr)
! CHECK: } -> !omp.iterated<!llvm.ptr>
! CHECK: %[[MAP_A:.*]] = omp.map.info var_ptr(%[[A]]#1 : {{.*}}) map_clauses(to) capture(ByRef) bounds({{.*}}) name("a") -> !fir.ref<!fir.array<8xi32>>
diff --git a/flang/test/Lower/OpenMP/iterator-locators.f90 b/flang/test/Lower/OpenMP/iterator-locators.f90
new file mode 100644
index 0000000000000..2ed1ce918eec1
--- /dev/null
+++ b/flang/test/Lower/OpenMP/iterator-locators.f90
@@ -0,0 +1,246 @@
+! RUN: bbc -emit-hlfir -fopenmp -fopenmp-version=52 -o - %s \
+! RUN: | FileCheck %s
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=52 -o - %s \
+! RUN: | FileCheck %s
+! RUN: %flang_fc1 -emit-llvm -fopenmp -fopenmp-version=52 -o /dev/null %s
+! RUN: %flang_fc1 -emit-llvm -O1 -fopenmp -fopenmp-version=52 -o - %s \
+! RUN: | FileCheck %s --check-prefix=LLVM
+
+! Folded and live iterator references must use ordinary locator semantics.
+! All designator evaluation belongs inside the selected iterator region.
+
+subroutine depend_component(a, m, d)
+ type t
+ integer :: field
+ end type
+ type(t) :: a(8)
+ integer :: m, d
+ !$omp task depend(iterator(i=1:m), in: &
+ !$omp& a(1+0*i)%field, a(i/d)%field)
+ !$omp end task
+end
+! CHECK-LABEL: func.func @_QPdepend_component(
+! CHECK: %[[BASE:.*]]:2 = hlfir.declare %arg0
+! CHECK-NOT: arith.divsi
+! CHECK: %[[FOLDED:.*]] = omp.iterator(
+! CHECK: %[[ELEM:.*]] = hlfir.designate %[[BASE]]#0 (
+! CHECK: %[[ADDR:.*]] = hlfir.designate %[[ELEM]]{"field"}
+! CHECK: %[[PTR:.*]] = fir.convert %[[ADDR]]
+! CHECK: omp.yield(%[[PTR]] : !llvm.ptr)
+! CHECK: %[[LIVE:.*]] = omp.iterator(
+! CHECK: arith.divsi
+! CHECK: %[[ELEM:.*]] = hlfir.designate %[[BASE]]#0 (
+! CHECK: %[[ADDR:.*]] = hlfir.designate %[[ELEM]]{"field"}
+! CHECK: %[[PTR:.*]] = fir.convert %[[ADDR]]
+! CHECK: omp.yield(%[[PTR]] : !llvm.ptr)
+! CHECK: omp.task depend(
+! CHECK-SAME: %[[FOLDED]] :
+! CHECK-SAME: %[[LIVE]] :
+
+subroutine depend_vector(a, m, d)
+ integer :: a(8)
+ integer :: m, d
+ !$omp task depend(iterator(i=1:m), in: &
+ !$omp& a([1+0*i]), a([i/d]))
+ !$omp end task
+end
+! CHECK-LABEL: func.func @_QPdepend_vector(
+! CHECK: %[[BASE:.*]]:2 = hlfir.declare %arg0
+! CHECK-NOT: arith.divsi
+! CHECK: %[[FOLDED:.*]] = omp.iterator(
+! CHECK: %[[INDEX:.*]] = fir.load {{.*}} : !fir.ref<i64>
+! CHECK: %[[ADDR:.*]] = hlfir.designate %[[BASE]]#0 (%[[INDEX]])
+! CHECK: %[[PTR:.*]] = fir.convert %[[ADDR]]
+! CHECK: omp.yield(%[[PTR]] : !llvm.ptr)
+! CHECK: %[[LIVE:.*]] = omp.iterator(
+! CHECK: arith.divsi
+! CHECK: %[[TMP:.*]] = hlfir.as_expr
+! CHECK: %[[INDEX:.*]] = hlfir.apply %[[TMP]],
+! CHECK: %[[ADDR:.*]] = hlfir.designate %[[BASE]]#0 (%[[INDEX]])
+! CHECK: %[[PTR:.*]] = fir.convert %[[ADDR]]
+! CHECK: hlfir.destroy %[[TMP]]
+! CHECK: omp.yield(%[[PTR]] : !llvm.ptr)
+! CHECK: omp.task depend(
+! CHECK-SAME: %[[FOLDED]] :
+! CHECK-SAME: %[[LIVE]] :
+
+subroutine depend_section(x, m, d)
+ type t
+ integer :: a(8)
+ end type
+ type(t) :: x
+ integer :: m, d
+ !$omp task depend(iterator(i=1:m), in: &
+ !$omp& x%a(1:2+0*i), x%a(i/d:i/d+1))
+ !$omp end task
+end
+! CHECK-LABEL: func.func @_QPdepend_section(
+! CHECK: %[[BASE:.*]]:2 = hlfir.declare %arg0
+! CHECK-NOT: arith.divsi
+! CHECK: %[[FOLDED:.*]] = omp.iterator(
+! CHECK: %[[ADDR:.*]] = hlfir.designate %[[BASE]]#0{"a"}
+! CHECK: %[[PTR:.*]] = fir.convert %[[ADDR]]
+! CHECK: omp.yield(%[[PTR]] : !llvm.ptr)
+! CHECK: %[[LIVE:.*]] = omp.iterator(
+! CHECK: arith.divsi
+! CHECK: %[[BOX:.*]] = hlfir.designate %[[BASE]]#0{"a"}
+! CHECK: %[[ADDR:.*]] = fir.box_addr %[[BOX]]
+! CHECK: %[[PTR:.*]] = fir.convert %[[ADDR]]
+! CHECK: omp.yield(%[[PTR]] : !llvm.ptr)
+! CHECK: omp.task depend(
+! CHECK-SAME: %[[FOLDED]] :
+! CHECK-SAME: %[[LIVE]] :
+
+subroutine affinity_component(a, m, d)
+ type t
+ integer :: field
+ end type
+ type(t) :: a(8)
+ integer :: m, d
+ !$omp task affinity(iterator(i=1:m): &
+ !$omp& a(1+0*i)%field, a(i/d)%field)
+ !$omp end task
+end
+! CHECK-LABEL: func.func @_QPaffinity_component(
+! CHECK: %[[BASE:.*]]:2 = hlfir.declare %arg0
+! CHECK-NOT: arith.divsi
+! CHECK: %[[FOLDED:.*]] = omp.iterator(
+! CHECK: %[[ELEM:.*]] = hlfir.designate %[[BASE]]#0 (
+! CHECK: %[[ADDR:.*]] = hlfir.designate %[[ELEM]]{"field"}
+! CHECK: %[[PTR:.*]] = fir.convert %[[ADDR]]
+! CHECK: %[[ENTRY:.*]] = omp.affinity_entry %[[PTR]],
+! CHECK: omp.yield(%[[ENTRY]] :
+! CHECK: %[[LIVE:.*]] = omp.iterator(
+! CHECK: arith.divsi
+! CHECK: %[[ELEM:.*]] = hlfir.designate %[[BASE]]#0 (
+! CHECK: %[[ADDR:.*]] = hlfir.designate %[[ELEM]]{"field"}
+! CHECK: %[[PTR:.*]] = fir.convert %[[ADDR]]
+! CHECK: %[[ENTRY:.*]] = omp.affinity_entry %[[PTR]],
+! CHECK: omp.yield(%[[ENTRY]] :
+! CHECK: omp.task affinity(
+! CHECK-SAME: %[[FOLDED]] :
+! CHECK-SAME: %[[LIVE]] :
+
+subroutine affinity_section(x, m, d)
+ type t
+ integer :: a(8)
+ end type
+ type(t) :: x
+ integer :: m, d
+ !$omp task affinity(iterator(i=1:m): &
+ !$omp& x%a(1:2+0*i), x%a(i/d:i/d+1))
+ !$omp end task
+end
+! CHECK-LABEL: func.func @_QPaffinity_section(
+! CHECK: %[[BASE:.*]]:2 = hlfir.declare %arg0
+! CHECK-NOT: arith.divsi
+! CHECK: %[[FOLDED:.*]] = omp.iterator(
+! CHECK: %[[ADDR:.*]] = hlfir.designate %[[BASE]]#0{"a"}
+! CHECK: %[[PTR:.*]] = fir.convert %[[ADDR]]
+! CHECK: %[[ENTRY:.*]] = omp.affinity_entry %[[PTR]],
+! CHECK: omp.yield(%[[ENTRY]] :
+! CHECK: %[[LIVE:.*]] = omp.iterator(
+! CHECK: arith.divsi
+! CHECK: %[[BOX:.*]] = hlfir.designate %[[BASE]]#0{"a"}
+! CHECK: %[[ADDR:.*]] = fir.box_addr %[[BOX]]
+! CHECK: %[[ELEMS:.*]] = fir.convert %{{.*}} : (index) -> i64
+! CHECK: %[[LEN:.*]] = arith.muli %[[ELEMS]], %{{.*}} : i64
+! CHECK: %[[PTR:.*]] = fir.convert %[[ADDR]]
+! CHECK: %[[ENTRY:.*]] = omp.affinity_entry %[[PTR]], %[[LEN]]
+! CHECK: omp.yield(%[[ENTRY]] :
+! CHECK: omp.task affinity(
+! CHECK-SAME: %[[FOLDED]] :
+! CHECK-SAME: %[[LIVE]] :
+
+! Scalar components occupy one element; component sections span two.
+! LLVM-LABEL: define {{.*}} @affinity_component_(
+! LLVM: store i64 4,
+! LLVM: store i64 4,
+! LLVM: call i32 @__kmpc_omp_reg_task_with_affinity(
+! LLVM-LABEL: define {{.*}} @affinity_section_(
+! LLVM: store i64 8,
+! LLVM: call i32 @__kmpc_omp_reg_task_with_affinity(
+
+! Empty ranges must suppress component and vector designator evaluation.
+
+subroutine depend_component_empty(a, m, d)
+ type t
+ integer :: field
+ end type
+ type(t) :: a(8)
+ integer :: m, d
+ !$omp task depend(iterator(i=2:1), in: &
+ !$omp& a(1+0*i)%field, a(i/d)%field)
+ !$omp end task
+end
+! LLVM-LABEL: define {{.*}} @depend_component_empty_(
+! LLVM-NOT: sdiv
+! LLVM: call i32 @__kmpc_omp_task_with_deps(
+! LLVM-SAME: i32 0, ptr
+! LLVM-NOT: sdiv
+! LLVM: ret void
+
+subroutine depend_vector_empty(a, m, d)
+ integer :: a(8)
+ integer :: m, d
+ !$omp task depend(iterator(i=2:1), in: &
+ !$omp& a([1+0*i]), a([i/d]))
+ !$omp end task
+end
+! LLVM-LABEL: define {{.*}} @depend_vector_empty_(
+! LLVM-NOT: sdiv
+! LLVM: call i32 @__kmpc_omp_task_with_deps(
+! LLVM-SAME: i32 0, ptr
+! LLVM-NOT: sdiv
+! LLVM: ret void
+
+subroutine depend_section_empty(x, m, d)
+ type t
+ integer :: a(8)
+ end type
+ type(t) :: x
+ integer :: m, d
+ !$omp task depend(iterator(i=2:1), in: &
+ !$omp& x%a(1:2+0*i), x%a(i/d:i/d+1))
+ !$omp end task
+end
+! LLVM-LABEL: define {{.*}} @depend_section_empty_(
+! LLVM-NOT: sdiv
+! LLVM: call i32 @__kmpc_omp_task_with_deps(
+! LLVM-SAME: i32 0, ptr
+! LLVM-NOT: sdiv
+! LLVM: ret void
+
+subroutine affinity_component_empty(a, m, d)
+ type t
+ integer :: field
+ end type
+ type(t) :: a(8)
+ integer :: m, d
+ !$omp task affinity(iterator(i=2:1): &
+ !$omp& a(1+0*i)%field, a(i/d)%field)
+ !$omp end task
+end
+! LLVM-LABEL: define {{.*}} @affinity_component_empty_(
+! LLVM-NOT: sdiv
+! LLVM: call i32 @__kmpc_omp_reg_task_with_affinity(
+! LLVM-SAME: i32 0, ptr
+! LLVM-NOT: sdiv
+! LLVM: ret void
+
+subroutine affinity_section_empty(x, m, d)
+ type t
+ integer :: a(8)
+ end type
+ type(t) :: x
+ integer :: m, d
+ !$omp task affinity(iterator(i=2:1): &
+ !$omp& x%a(1:2+0*i), x%a(i/d:i/d+1))
+ !$omp end task
+end
+! LLVM-LABEL: define {{.*}} @affinity_section_empty_(
+! LLVM-NOT: sdiv
+! LLVM: call i32 @__kmpc_omp_reg_task_with_affinity(
+! LLVM-SAME: i32 0, ptr
+! LLVM-NOT: sdiv
+! LLVM: ret void
diff --git a/flang/test/Lower/OpenMP/iterator-source-occurrences.f90 b/flang/test/Lower/OpenMP/iterator-source-occurrences.f90
index 7387a54495066..4c89d5c827538 100644
--- a/flang/test/Lower/OpenMP/iterator-source-occurrences.f90
+++ b/flang/test/Lower/OpenMP/iterator-source-occurrences.f90
@@ -14,15 +14,45 @@ subroutine depend_folded(a, m, d, i)
end subroutine
! CHECK-LABEL: func.func @_QPdepend_folded(
-! CHECK: omp.iterator(%{{.*}}: index, %{{.*}}: index) =
+! CHECK: %[[A:.*]]:2 = hlfir.declare
+! CHECK-SAME: uniq_name("_QFdepend_foldedEa")
+! CHECK: %[[M:.*]]:2 = hlfir.declare {{.*}}uniq_name("{{.*}}Em")
+! CHECK: %[[ONE:.*]] = arith.constant 1 : i32
+! CHECK: %[[MVAL:.*]] = fir.load %[[M]]#0
+! CHECK: %[[ILB:.*]] = fir.convert %[[ONE]] : (i32) -> index
+! CHECK: %[[IUB:.*]] = fir.convert %[[MVAL]] : (i32) -> index
+! CHECK: %[[ISTEP:.*]] = arith.constant 1 : index
+! CHECK: %[[JONE:.*]] = arith.constant 1 : i32
+! CHECK: %[[TWO:.*]] = arith.constant 2 : i32
+! CHECK: %[[JLB:.*]] = fir.convert %[[JONE]] : (i32) -> index
+! CHECK: %[[JUB:.*]] = fir.convert %[[TWO]] : (i32) -> index
+! CHECK: %[[JSTEP:.*]] = arith.constant 1 : index
+! CHECK: %[[IT_IJ:.*]] = omp.iterator(%{{.*}}: index, %{{.*}}: index) =
+! CHECK-SAME: (%[[ILB]] to %[[IUB]] step %[[ISTEP]],
+! CHECK-SAME: %[[JLB]] to %[[JUB]] step %[[JSTEP]])
! CHECK: arith.divsi
! CHECK: omp.yield
-! CHECK: omp.iterator(%{{[^,:]+}}: index) =
-! CHECK: omp.yield
-! CHECK: omp.iterator(%{{[^,:]+}}: index) =
-! CHECK: omp.yield
+! CHECK: %[[IT_I:.*]] = omp.iterator(%[[I:.*]]: index) =
+! CHECK-SAME: (%[[ILB]] to %[[IUB]] step %[[ISTEP]])
+! CHECK: %[[FIRST:.*]] = arith.constant 1 : index
+! CHECK: %[[FIXED:.*]] = hlfir.designate %[[A]]#0 (%[[FIRST]])
+! CHECK: %[[FIXED_PTR:.*]] = fir.convert %[[FIXED]]
+! CHECK: omp.yield(%[[FIXED_PTR]] : !llvm.ptr)
+! CHECK: %[[IT_J:.*]] = omp.iterator(%[[J:.*]]: index) =
+! CHECK-SAME: (%[[JLB]] to %[[JUB]] step %[[JSTEP]])
+! CHECK: %[[JVAL:.*]] = fir.convert %[[J]] : (index) -> i32
+! CHECK: fir.store %[[JVAL]] to %[[JMEM:.*]] : !fir.ref<i32>
+! CHECK: %[[JDECL:.*]]:2 = hlfir.declare %[[JMEM]]
+! CHECK: %[[JLOAD:.*]] = fir.load %[[JDECL]]#0
+! CHECK: %[[JIDX:.*]] = fir.convert %[[JLOAD]] : (i32) -> i64
+! CHECK: %[[VARIABLE:.*]] = hlfir.designate %[[A]]#0 (%[[JIDX]])
+! CHECK: %[[VARIABLE_PTR:.*]] = fir.convert %[[VARIABLE]]
+! CHECK: omp.yield(%[[VARIABLE_PTR]] : !llvm.ptr)
! CHECK-NOT: omp.iterator
-! CHECK: omp.task
+! CHECK: omp.task depend(
+! CHECK-SAME: %[[IT_IJ]] :
+! CHECK-SAME: %[[IT_I]] :
+! CHECK-SAME: %[[IT_J]] :
! CHECK: return
! The host i in the second clause must not be confused with iterator j.
@@ -48,15 +78,47 @@ subroutine affinity_folded(a, m, d, i)
end subroutine
! CHECK-LABEL: func.func @_QPaffinity_folded(
-! CHECK: omp.iterator(%{{.*}}: index, %{{.*}}: index) =
+! CHECK: %[[A:.*]]:2 = hlfir.declare
+! CHECK-SAME: uniq_name("_QFaffinity_foldedEa")
+! CHECK: %[[M:.*]]:2 = hlfir.declare {{.*}}uniq_name("{{.*}}Em")
+! CHECK: %[[ONE:.*]] = arith.constant 1 : i32
+! CHECK: %[[MVAL:.*]] = fir.load %[[M]]#0
+! CHECK: %[[ILB:.*]] = fir.convert %[[ONE]] : (i32) -> index
+! CHECK: %[[IUB:.*]] = fir.convert %[[MVAL]] : (i32) -> index
+! CHECK: %[[ISTEP:.*]] = arith.constant 1 : index
+! CHECK: %[[JONE:.*]] = arith.constant 1 : i32
+! CHECK: %[[TWO:.*]] = arith.constant 2 : i32
+! CHECK: %[[JLB:.*]] = fir.convert %[[JONE]] : (i32) -> index
+! CHECK: %[[JUB:.*]] = fir.convert %[[TWO]] : (i32) -> index
+! CHECK: %[[JSTEP:.*]] = arith.constant 1 : index
+! CHECK: %[[IT_IJ:.*]] = omp.iterator(%{{.*}}: index, %{{.*}}: index) =
+! CHECK-SAME: (%[[ILB]] to %[[IUB]] step %[[ISTEP]],
+! CHECK-SAME: %[[JLB]] to %[[JUB]] step %[[JSTEP]])
! CHECK: arith.divsi
! CHECK: omp.yield
-! CHECK: omp.iterator(%{{[^,:]+}}: index) =
-! CHECK: omp.yield
-! CHECK: omp.iterator(%{{[^,:]+}}: index) =
-! CHECK: omp.yield
+! CHECK: %[[IT_I:.*]] = omp.iterator(%[[I:.*]]: index) =
+! CHECK-SAME: (%[[ILB]] to %[[IUB]] step %[[ISTEP]])
+! CHECK: %[[FIRST:.*]] = arith.constant 1 : index
+! CHECK: %[[FIXED:.*]] = hlfir.designate %[[A]]#0 (%[[FIRST]])
+! CHECK: %[[FIXED_PTR:.*]] = fir.convert %[[FIXED]]
+! CHECK: %[[FIXED_ENTRY:.*]] = omp.affinity_entry %[[FIXED_PTR]],
+! CHECK: omp.yield(%[[FIXED_ENTRY]] :
+! CHECK: %[[IT_J:.*]] = omp.iterator(%[[J:.*]]: index) =
+! CHECK-SAME: (%[[JLB]] to %[[JUB]] step %[[JSTEP]])
+! CHECK: %[[JVAL:.*]] = fir.convert %[[J]] : (index) -> i32
+! CHECK: fir.store %[[JVAL]] to %[[JMEM:.*]] : !fir.ref<i32>
+! CHECK: %[[JDECL:.*]]:2 = hlfir.declare %[[JMEM]]
+! CHECK: %[[JLOAD:.*]] = fir.load %[[JDECL]]#0
+! CHECK: %[[JIDX:.*]] = fir.convert %[[JLOAD]] : (i32) -> i64
+! CHECK: %[[VARIABLE:.*]] = hlfir.designate %[[A]]#0 (%[[JIDX]])
+! CHECK: %[[VARIABLE_PTR:.*]] = fir.convert %[[VARIABLE]]
+! CHECK: %[[VARIABLE_ENTRY:.*]] = omp.affinity_entry %[[VARIABLE_PTR]],
+! CHECK: omp.yield(%[[VARIABLE_ENTRY]] :
! CHECK-NOT: omp.iterator
-! CHECK: omp.task
+! CHECK: omp.task affinity(
+! CHECK-SAME: %[[IT_IJ]] :
+! CHECK-SAME: %[[IT_I]] :
+! CHECK-SAME: %[[IT_J]] :
! CHECK: return
! The host i in the second task must not be confused with iterator j.
diff --git a/flang/test/Lower/OpenMP/iterator-target-data.f90 b/flang/test/Lower/OpenMP/iterator-target-data.f90
new file mode 100644
index 0000000000000..59141b13d9221
--- /dev/null
+++ b/flang/test/Lower/OpenMP/iterator-target-data.f90
@@ -0,0 +1,66 @@
+! RUN: split-file %s %t
+! RUN: not %flang_fc1 -emit-llvm -O1 -fopenmp -fopenmp-version=52 \
+! RUN: -fopenmp-targets=amdgcn-amd-amdhsa -o - %t/enter-folded.f90 \
+! RUN: 2>&1 | FileCheck %s --check-prefix=ENTER
+! RUN: not %flang_fc1 -emit-llvm -O1 -fopenmp -fopenmp-version=52 \
+! RUN: -fopenmp-targets=amdgcn-amd-amdhsa -o - %t/enter-live.f90 \
+! RUN: 2>&1 | FileCheck %s --check-prefix=ENTER
+! RUN: not %flang_fc1 -emit-llvm -O1 -fopenmp -fopenmp-version=52 \
+! RUN: -fopenmp-targets=amdgcn-amd-amdhsa -o - %t/exit-folded.f90 \
+! RUN: 2>&1 | FileCheck %s --check-prefix=EXIT
+! RUN: not %flang_fc1 -emit-llvm -O1 -fopenmp -fopenmp-version=52 \
+! RUN: -fopenmp-targets=amdgcn-amd-amdhsa -o - %t/exit-live.f90 \
+! RUN: 2>&1 | FileCheck %s --check-prefix=EXIT
+! RUN: not %flang_fc1 -emit-llvm -O1 -fopenmp -fopenmp-version=52 \
+! RUN: -fopenmp-targets=amdgcn-amd-amdhsa -o - %t/update-folded.f90 \
+! RUN: 2>&1 | FileCheck %s --check-prefix=UPDATE
+! RUN: not %flang_fc1 -emit-llvm -O1 -fopenmp -fopenmp-version=52 \
+! RUN: -fopenmp-targets=amdgcn-amd-amdhsa -o - %t/update-live.f90 \
+! RUN: 2>&1 | FileCheck %s --check-prefix=UPDATE
+
+! Valid HLFIR dependences must be rejected at the translation boundary.
+! ENTER: Unhandled clause depend in omp.target_enter_data operation
+! EXIT: Unhandled clause depend in omp.target_exit_data operation
+! UPDATE: Unhandled clause depend in omp.target_update operation
+
+!--- enter-folded.f90
+subroutine s(a)
+ integer :: a(2)
+ !$omp target enter data map(to:a) &
+ !$omp& depend(iterator(i=1:1), in:a(1+0*i))
+end
+
+!--- enter-live.f90
+subroutine s(a)
+ integer :: a(2)
+ !$omp target enter data map(to:a) &
+ !$omp& depend(iterator(i=1:1), in:a(i))
+end
+
+!--- exit-folded.f90
+subroutine s(a)
+ integer :: a(2)
+ !$omp target exit data map(from:a) &
+ !$omp& depend(iterator(i=1:1), in:a(1+0*i))
+end
+
+!--- exit-live.f90
+subroutine s(a)
+ integer :: a(2)
+ !$omp target exit data map(from:a) &
+ !$omp& depend(iterator(i=1:1), in:a(i))
+end
+
+!--- update-folded.f90
+subroutine s(a)
+ integer :: a(2)
+ !$omp target update to(a) &
+ !$omp& depend(iterator(i=1:1), in:a(1+0*i))
+end
+
+!--- update-live.f90
+subroutine s(a)
+ integer :: a(2)
+ !$omp target update to(a) &
+ !$omp& depend(iterator(i=1:1), in:a(i))
+end
diff --git a/flang/test/Lower/OpenMP/task-affinity.f90 b/flang/test/Lower/OpenMP/task-affinity.f90
index 17e26454add65..813fb6f23251f 100644
--- a/flang/test/Lower/OpenMP/task-affinity.f90
+++ b/flang/test/Lower/OpenMP/task-affinity.f90
@@ -19,14 +19,7 @@ end subroutine omp_task_affinity_elem
! CHECK: omp.parallel {
! CHECK: %[[C1:.*]] = arith.constant 1 : index
! CHECK: %[[ELEM:.*]] = hlfir.designate %[[A]]#0 (%[[C1]]) : (!fir.ref<!fir.array<100xi32>>, index) -> !fir.ref<i32>
-! CHECK: %[[C0:.*]] = arith.constant 0 : index
-! CHECK: %[[C4:.*]] = arith.constant 4 : i64
-! CHECK: %[[ONE:.*]] = arith.constant 1 : index
-! CHECK: %[[SUB:.*]] = arith.subi %[[C0]], %[[C0]] : index
-! CHECK: %[[MUL:.*]] = arith.muli %[[SUB]], %[[ONE]] : index
-! CHECK: %[[ADD:.*]] = arith.addi %[[ONE]], %[[MUL]] : index
-! CHECK: %[[CAST:.*]] = fir.convert %[[ADD]] : (index) -> i64
-! CHECK: %[[LEN:.*]] = arith.muli %[[CAST]], %[[C4]] : i64
+! CHECK: %[[LEN:.*]] = arith.constant 4 : i64
! CHECK: %[[ADDRI8:.*]] = fir.convert %[[ELEM]] : (!fir.ref<i32>) -> !fir.ref<i8>
! CHECK: %[[ENTRY:.*]] = omp.affinity_entry %[[ADDRI8]], %[[LEN]] : (!fir.ref<i8>, i64) -> !omp.affinity_entry_ty<!fir.ref<i8>, i64>
! CHECK: omp.task affinity(%[[ENTRY]] : !omp.affinity_entry_ty<!fir.ref<i8>, i64>) {
@@ -292,7 +285,7 @@ subroutine affinity_unused_iterator(m)
! CHECK: %[[DECL_I:.*]]:2 = hlfir.declare %[[MEM_I]]
! CHECK: %[[LD_I:.*]] = fir.load %[[DECL_I]]#0 : !fir.ref<i32>
! CHECK: %[[IDX_I:.*]] = fir.convert %[[LD_I]] : (i32) -> i64
-! CHECK: %[[COOR_I:.*]] = fir.array_coor %[[A]]#0(%{{.*}}) %[[IDX_I]]
+! CHECK: %[[COOR_I:.*]] = hlfir.designate %[[A]]#0 (%[[IDX_I]])
! CHECK: %[[SIZE_I:.*]] = arith.constant 4 : i64
! CHECK: %[[PTR_I:.*]] = fir.convert %[[COOR_I]]
! CHECK-SAME: (!fir.ref<i32>) -> !fir.ref<i8>
@@ -339,7 +332,7 @@ subroutine affinity_per_locator(m)
! CHECK: %[[DECL_I:.*]]:2 = hlfir.declare %[[MEM_I]]
! CHECK: %[[LD_I:.*]] = fir.load %[[DECL_I]]#0 : !fir.ref<i32>
! CHECK: %[[IDX_I:.*]] = fir.convert %[[LD_I]] : (i32) -> i64
-! CHECK: %[[COOR_I:.*]] = fir.array_coor %[[A]]#0(%{{.*}}) %[[IDX_I]]
+! CHECK: %[[COOR_I:.*]] = hlfir.designate %[[A]]#0 (%[[IDX_I]])
! CHECK: %[[SIZE_I:.*]] = arith.constant 4 : i64
! CHECK: %[[PTR_I:.*]] = fir.convert %[[COOR_I]]
! CHECK-SAME: (!fir.ref<i32>) -> !fir.ref<i8>
@@ -354,7 +347,7 @@ subroutine affinity_per_locator(m)
! CHECK: %[[DECL_J:.*]]:2 = hlfir.declare %[[MEM_J]]
! CHECK: %[[LD_J:.*]] = fir.load %[[DECL_J]]#0 : !fir.ref<i32>
! CHECK: %[[IDX_J:.*]] = fir.convert %[[LD_J]] : (i32) -> i64
-! CHECK: %[[COOR_J:.*]] = fir.array_coor %[[B]]#0(%{{.*}}) %[[IDX_J]]
+! CHECK: %[[COOR_J:.*]] = hlfir.designate %[[B]]#0 (%[[IDX_J]])
! CHECK: %[[SIZE_J:.*]] = arith.constant 4 : i64
! CHECK: %[[PTR_J:.*]] = fir.convert %[[COOR_J]]
! CHECK-SAME: (!fir.ref<i32>) -> !fir.ref<i8>
@@ -395,8 +388,7 @@ subroutine task_affinity_iterator_simple()
! CHECK: %[[IV_DECL:.*]]:2 = hlfir.declare %[[IV_MEM]] uniq_name("_QQ{{.*}}.omp.iter")
! CHECK: %[[IV_LD:.*]] = fir.load %[[IV_DECL]]#0 : !fir.ref<i32>
! CHECK: %[[IV_I64:.*]] = fir.convert %[[IV_LD]] : (i32) -> i64
-! CHECK: %[[SHAPE:.*]] = fir.shape %c16 : (index) -> !fir.shape<1>
-! CHECK: %[[COOR:.*]] = fir.array_coor {{.*}}(%[[SHAPE]]) %[[IV_I64]] : (!fir.ref<!fir.array<16xi32>>, !fir.shape<1>, i64) -> !fir.ref<i32>
+! CHECK: %[[COOR:.*]] = hlfir.designate {{.*}} (%[[IV_I64]])
! CHECK: %[[C4:.*]] = arith.constant 4 : i64
! CHECK: %[[ADDRI8:.*]] = fir.convert %[[COOR]] : (!fir.ref<i32>) -> !fir.ref<i8>
! CHECK: %[[ENTRY:.*]] = omp.affinity_entry %[[ADDRI8]], %[[C4]] : (!fir.ref<i8>, i64) -> !omp.affinity_entry_ty<!fir.ref<i8>, i64>
@@ -426,8 +418,7 @@ subroutine task_affinity_iterator_nondefault_lb()
! CHECK: %[[IV_NDLB_DECL:.*]]:2 = hlfir.declare %[[IV_NDLB_MEM]]
! CHECK: %[[IV_NDLB_LD:.*]] = fir.load %[[IV_NDLB_DECL]]#0 : !fir.ref<i32>
! CHECK: %[[IV_NDLB_I64:.*]] = fir.convert %[[IV_NDLB_LD]] : (i32) -> i64
-! CHECK: %[[SHIFT_NDLB:.*]] = fir.shape_shift %c0, %c9 : (index, index) -> !fir.shapeshift<1>
-! CHECK: %[[COOR_NDLB:.*]] = fir.array_coor {{.*}}(%[[SHIFT_NDLB]]) %[[IV_NDLB_I64]] : (!fir.box<!fir.array<9xi32>>, !fir.shapeshift<1>, i64) -> !fir.ref<i32>
+! CHECK: %[[COOR_NDLB:.*]] = hlfir.designate {{.*}} (%[[IV_NDLB_I64]])
! CHECK: %[[ELEM_NDLB:.*]] = fir.box_elesize %{{.*}} : (!fir.box<!fir.array<9xi32>>) -> index
! CHECK: %[[ELEM_NDLB_I64:.*]] = fir.convert %[[ELEM_NDLB]] : (index) -> i64
! CHECK: %[[ADDRI8_NDLB:.*]] = fir.convert %[[COOR_NDLB]] : (!fir.ref<i32>) -> !fir.ref<i8>
@@ -463,8 +454,8 @@ subroutine task_affinity_iterator_nondefault_lb_2d()
! CHECK: %[[IV0_NDLB2_I64:.*]] = fir.convert %[[IV0_NDLB2_LD]] : (i32) -> i64
! CHECK: %[[IV1_NDLB2_LD:.*]] = fir.load %[[IV1_NDLB2_DECL]]#0 : !fir.ref<i32>
! CHECK: %[[IV1_NDLB2_I64:.*]] = fir.convert %[[IV1_NDLB2_LD]] : (i32) -> i64
-! CHECK: %[[SHIFT_NDLB2:.*]] = fir.shape_shift %c0, %c5, %c-1, %c8 : (index, index, index, index) -> !fir.shapeshift<2>
-! CHECK: %[[COOR_NDLB2:.*]] = fir.array_coor {{.*}}(%[[SHIFT_NDLB2]]) %[[IV0_NDLB2_I64]], %[[IV1_NDLB2_I64]] : (!fir.box<!fir.array<5x8xi32>>, !fir.shapeshift<2>, i64, i64) -> !fir.ref<i32>
+! CHECK: %[[COOR_NDLB2:.*]] = hlfir.designate
+! CHECK-SAME: {{.*}} (%[[IV0_NDLB2_I64]], %[[IV1_NDLB2_I64]])
! CHECK: %[[ELEM_NDLB2:.*]] = fir.box_elesize %{{.*}} : (!fir.box<!fir.array<5x8xi32>>) -> index
! CHECK: %[[ELEM_NDLB2_I64:.*]] = fir.convert %[[ELEM_NDLB2]] : (index) -> i64
! CHECK: %[[ADDRI8_NDLB2:.*]] = fir.convert %[[COOR_NDLB2]] : (!fir.ref<i32>) -> !fir.ref<i8>
@@ -503,8 +494,7 @@ subroutine task_affinity_iterator_multi_dimension()
! CHECK: %[[IV0_I64:.*]] = fir.convert %[[IV0_LD]] : (i32) -> i64
! CHECK: %[[IV1_LD:.*]] = fir.load %[[IV1_DECL]]#0 : !fir.ref<i32>
! CHECK: %[[IV1_I64:.*]] = fir.convert %[[IV1_LD]] : (i32) -> i64
-! CHECK: %[[SHAPE:.*]] = fir.shape %c4, %c6 : (index, index) -> !fir.shape<2>
-! CHECK: %[[COOR:.*]] = fir.array_coor {{.*}}(%[[SHAPE]]) %[[IV0_I64]], %[[IV1_I64]] : (!fir.ref<!fir.array<4x6xi32>>, !fir.shape<2>, i64, i64) -> !fir.ref<i32>
+! CHECK: %[[COOR:.*]] = hlfir.designate {{.*}} (%[[IV0_I64]], %[[IV1_I64]])
! CHECK: %[[C4:.*]] = arith.constant 4 : i64
! CHECK: %[[ADDRI8:.*]] = fir.convert %[[COOR]] : (!fir.ref<i32>) -> !fir.ref<i8>
! CHECK: %[[ENTRY:.*]] = omp.affinity_entry %[[ADDRI8]], %[[C4]] : (!fir.ref<i8>, i64) -> !omp.affinity_entry_ty<!fir.ref<i8>, i64>
@@ -538,8 +528,8 @@ subroutine task_affinity_iterator_reordered()
! CHECK: %[[RO_IV1_I64:.*]] = fir.convert %[[RO_IV1_LD]] : (i32) -> i64
! CHECK: %[[RO_IV0_LD:.*]] = fir.load %[[RO_IV0_DECL]]#0 : !fir.ref<i32>
! CHECK: %[[RO_IV0_I64:.*]] = fir.convert %[[RO_IV0_LD]] : (i32) -> i64
-! CHECK: %[[SHAPE:.*]] = fir.shape %c4, %c6 : (index, index) -> !fir.shape<2>
-! CHECK: %[[COOR:.*]] = fir.array_coor {{.*}}(%[[SHAPE]]) %[[RO_IV1_I64]], %[[RO_IV0_I64]] : (!fir.ref<!fir.array<4x6xi32>>, !fir.shape<2>, i64, i64) -> !fir.ref<i32>
+! CHECK: %[[COOR:.*]] = hlfir.designate
+! CHECK-SAME: {{.*}} (%[[RO_IV1_I64]], %[[RO_IV0_I64]])
subroutine task_affinity_iterator_expr_subscript()
integer, parameter :: n = 5, m = 6
@@ -565,12 +555,12 @@ subroutine task_affinity_iterator_expr_subscript()
! CHECK: %[[IVB_DECL:.*]]:2 = hlfir.declare %[[IVB_MEM]]
! CHECK: %[[IVA_LD:.*]] = fir.load %[[IVA_DECL]]#0 : !fir.ref<i32>
! CHECK: %[[C1_I32:.*]] = arith.constant 1 : i32
-! CHECK: %[[IP1_I32:.*]] = arith.addi %[[IVA_LD]], %[[C1_I32]] : i32
+! CHECK: %[[IP1_I32:.*]] = arith.addi %[[IVA_LD]], %[[C1_I32]]
+! CHECK-SAME: overflow<nsw> : i32
! CHECK: %[[IP1_I64:.*]] = fir.convert %[[IP1_I32]] : (i32) -> i64
! CHECK: %[[IVB_LD:.*]] = fir.load %[[IVB_DECL]]#0 : !fir.ref<i32>
! CHECK: %[[IVB_I64:.*]] = fir.convert %[[IVB_LD]] : (i32) -> i64
-! CHECK: %[[SHAPE2:.*]] = fir.shape %c5, %c6 : (index, index) -> !fir.shape<2>
-! CHECK: %[[COOR2:.*]] = fir.array_coor {{.*}}(%[[SHAPE2]]) %[[IP1_I64]], %[[IVB_I64]] : (!fir.ref<!fir.array<5x6xi32>>, !fir.shape<2>, i64, i64) -> !fir.ref<i32>
+! CHECK: %[[COOR2:.*]] = hlfir.designate {{.*}} (%[[IP1_I64]], %[[IVB_I64]])
subroutine task_affinity_iterator_section_subscript()
integer, parameter :: n = 5, m = 6
@@ -596,12 +586,19 @@ subroutine task_affinity_iterator_section_subscript()
! CHECK: %[[IVS1_DECL:.*]]:2 = hlfir.declare %[[IVS1_MEM]]
! CHECK: %[[IVS0_LD:.*]] = fir.load %[[IVS0_DECL]]#0 : !fir.ref<i32>
! CHECK: %[[IVS0_I64:.*]] = fir.convert %[[IVS0_LD]] : (i32) -> i64
+! CHECK: %[[LOWER:.*]] = fir.convert %[[IVS0_I64]] : (i64) -> index
! CHECK: %[[IVS1_LD:.*]] = fir.load %[[IVS1_DECL]]#0 : !fir.ref<i32>
! CHECK: %[[C2_I32:.*]] = arith.constant 2 : i32
-! CHECK: %[[JP2_I32:.*]] = arith.addi %[[IVS1_LD]], %[[C2_I32]] : i32
+! CHECK: %[[JP2_I32:.*]] = arith.addi %[[IVS1_LD]], %[[C2_I32]]
+! CHECK-SAME: overflow<nsw> : i32
! CHECK: %[[JP2_I64:.*]] = fir.convert %[[JP2_I32]] : (i32) -> i64
-! CHECK: %[[SHAPE3:.*]] = fir.shape %c5, %c6 : (index, index) -> !fir.shape<2>
-! CHECK: %[[COOR3:.*]] = fir.array_coor {{.*}}(%[[SHAPE3]]) %[[IVS0_I64]], %[[JP2_I64]] : (!fir.ref<!fir.array<5x6xi32>>, !fir.shape<2>, i64, i64) -> !fir.ref<i32>
+! CHECK: %[[COOR3:.*]] = hlfir.designate
+! CHECK-SAME: (%[[LOWER]]:{{.*}}, %[[JP2_I64]])
+! CHECK: %[[ADDR3:.*]] = fir.box_addr %[[COOR3]]
+! CHECK: %[[ELEMS3:.*]] = fir.convert %{{.*}} : (index) -> i64
+! CHECK: %[[LEN3:.*]] = arith.muli %[[ELEMS3]], %{{.*}} : i64
+! CHECK: %[[PTR3:.*]] = fir.convert %[[ADDR3]]
+! CHECK: omp.affinity_entry %[[PTR3]], %[[LEN3]]
subroutine task_affinity_iterator_section_implicit_lower()
integer, parameter :: n = 5, m = 6
@@ -625,10 +622,11 @@ subroutine task_affinity_iterator_section_implicit_lower()
! CHECK: %[[C1_IDX:.*]] = arith.constant 1 : index
! CHECK: %[[IVT1_LD:.*]] = fir.load %[[IVT1_DECL]]#0 : !fir.ref<i32>
! CHECK: %[[C2_I32_2:.*]] = arith.constant 2 : i32
-! CHECK: %[[JP2_I32_2:.*]] = arith.addi %[[IVT1_LD]], %[[C2_I32_2]] : i32
+! CHECK: %[[JP2_I32_2:.*]] = arith.addi %[[IVT1_LD]], %[[C2_I32_2]]
+! CHECK-SAME: overflow<nsw> : i32
! CHECK: %[[JP2_I64_2:.*]] = fir.convert %[[JP2_I32_2]] : (i32) -> i64
-! CHECK: %[[SHAPE4:.*]] = fir.shape %c5, %c6 : (index, index) -> !fir.shape<2>
-! CHECK: %[[COOR4:.*]] = fir.array_coor {{.*}}(%[[SHAPE4]]) %[[C1_IDX]], %[[JP2_I64_2]] : (!fir.ref<!fir.array<5x6xi32>>, !fir.shape<2>, index, i64) -> !fir.ref<i32>
+! CHECK: %[[COOR4:.*]] = hlfir.designate
+! CHECK-SAME: (%[[C1_IDX]]:{{.*}}, %[[JP2_I64_2]])
subroutine task_affinity_iterator_char_simple()
integer, parameter :: n = 8
@@ -651,8 +649,7 @@ subroutine task_affinity_iterator_char_simple()
! CHECK: %[[IVC_DECL:.*]]:2 = hlfir.declare %[[IVC_MEM]]
! CHECK: %[[IVC_LD:.*]] = fir.load %[[IVC_DECL]]#0 : !fir.ref<i32>
! CHECK: %[[IVC_I64:.*]] = fir.convert %[[IVC_LD]] : (i32) -> i64
-! CHECK: %[[SHAPE5:.*]] = fir.shape {{.*}} : (index) -> !fir.shape<1>
-! CHECK: %[[COOR5:.*]] = fir.array_coor {{.*}}(%[[SHAPE5]]) %[[IVC_I64]] : ({{.*}}, !fir.shape<1>, i64) -> !fir.ref<!fir.char<1,7>>
+! CHECK: %[[COOR5:.*]] = hlfir.designate {{.*}} (%[[IVC_I64]])
! CHECK: %[[C1_I64:.*]] = arith.constant 1 : i64
! CHECK: %[[C7_I64:.*]] = fir.convert %c7 : (index) -> i64
! CHECK: %[[ELEM5:.*]] = arith.muli %[[C7_I64]], %[[C1_I64]] : i64
@@ -680,10 +677,10 @@ subroutine task_affinity_iterator_char_expr_subscript()
! CHECK: %[[IVC2_DECL:.*]]:2 = hlfir.declare %[[IVC2_MEM]]
! CHECK: %[[IVC2_LD:.*]] = fir.load %[[IVC2_DECL]]#0 : !fir.ref<i32>
! CHECK: %[[C1_I32_6:.*]] = arith.constant 1 : i32
-! CHECK: %[[IP1C_I32:.*]] = arith.addi %[[IVC2_LD]], %[[C1_I32_6]] : i32
+! CHECK: %[[IP1C_I32:.*]] = arith.addi %[[IVC2_LD]], %[[C1_I32_6]]
+! CHECK-SAME: overflow<nsw> : i32
! CHECK: %[[IP1C_I64:.*]] = fir.convert %[[IP1C_I32]] : (i32) -> i64
-! CHECK: %[[SHAPE6:.*]] = fir.shape {{.*}} : (index) -> !fir.shape<1>
-! CHECK: %[[COOR6:.*]] = fir.array_coor {{.*}}(%[[SHAPE6]]) %[[IP1C_I64]] : ({{.*}}, !fir.shape<1>, i64) -> !fir.ref<!fir.char<1,7>>
+! CHECK: %[[COOR6:.*]] = hlfir.designate {{.*}} (%[[IP1C_I64]])
! CHECK: %[[C1_I64_2:.*]] = arith.constant 1 : i64
! CHECK: %[[C7_I64_2:.*]] = fir.convert %c7 : (index) -> i64
! CHECK: %[[ELEM6:.*]] = arith.muli %[[C7_I64_2]], %[[C1_I64_2]] : i64
@@ -707,8 +704,10 @@ subroutine task_affinity_iterator_char_runtime(n, l)
! CHECK-LABEL: func.func @_QPtask_affinity_iterator_char_runtime(
! CHECK: %[[A:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) typeparams %{{.*}} uniq_name("_QFtask_affinity_iterator_char_runtimeEa")
! CHECK: %[[ITER:.*]] = omp.iterator(%[[IV:.*]]: index) = ({{.*}} to {{.*}} step {{.*}}) {
-! CHECK: %[[COOR:.*]] = fir.array_coor %[[A]]#0({{.*}}) {{.*}} : (!fir.box<!fir.array<?x!fir.char<1,?>>>, !fir.shape<1>, i64) -> !fir.ref<!fir.char<1,?>>
+! CHECK: %[[COOR:.*]] = hlfir.designate %[[A]]#0 ({{.*}})
+! CHECK: %[[RAW:.*]]:2 = fir.unboxchar %[[COOR]]
! CHECK: %[[ELEM:.*]] = fir.box_elesize %[[A]]#0 : (!fir.box<!fir.array<?x!fir.char<1,?>>>) -> index
! CHECK: %[[ELEM_I64:.*]] = fir.convert %[[ELEM]] : (index) -> i64
-! CHECK: %[[ADDR:.*]] = fir.convert %[[COOR]] : (!fir.ref<!fir.char<1,?>>) -> !fir.ref<i8>
+! CHECK: %[[ADDR:.*]] = fir.convert %[[RAW]]#0
+! CHECK-SAME: : (!fir.ref<!fir.char<1,?>>) -> !fir.ref<i8>
! CHECK: %[[ENTRY:.*]] = omp.affinity_entry %[[ADDR]], %[[ELEM_I64]] : (!fir.ref<i8>, i64) -> !omp.affinity_entry_ty<!fir.ref<i8>, i64>
diff --git a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
index 80be348fe5687..1ed02e3e581d9 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
@@ -416,7 +416,8 @@ static LogicalResult checkImplementationStatus(Operation &op) {
result = todo("ompx_bare");
};
auto checkDepend = [&todo](auto op, LogicalResult &result) {
- if (!op.getDependVars().empty() || op.getDependKinds())
+ if (!op.getDependVars().empty() || op.getDependKinds() ||
+ !op.getDependIterated().empty() || op.getDependIteratedKinds())
result = todo("depend");
};
auto checkHint = [](auto op, LogicalResult &) {
diff --git a/mlir/test/Target/LLVMIR/openmp-iterator-wide.mlir b/mlir/test/Target/LLVMIR/openmp-iterator-wide.mlir
index bf4405d8c1d29..013b20636d9df 100644
--- a/mlir/test/Target/LLVMIR/openmp-iterator-wide.mlir
+++ b/mlir/test/Target/LLVMIR/openmp-iterator-wide.mlir
@@ -1,5 +1,37 @@
// RUN: mlir-translate --mlir-to-llvmir %s | FileCheck %s
+// Narrowing the lower bound to i64 would turn this empty range into 1:2.
+llvm.func @empty_positive(%x: !llvm.ptr) {
+ %lb = llvm.mlir.constant(18446744073709551617 : i128) : i128
+ %ub = llvm.mlir.constant(2 : i128) : i128
+ %st = llvm.mlir.constant(1 : i128) : i128
+ %it = omp.iterator(%i: i128) = (%lb to %ub step %st) {
+ omp.yield(%x : !llvm.ptr)
+ } -> !omp.iterated<!llvm.ptr>
+ omp.taskwait depend(taskdependin -> %it : !omp.iterated<!llvm.ptr>)
+ llvm.return
+}
+// CHECK-LABEL: define void @empty_positive(
+// CHECK: icmp ult i64 %{{.*}}, 0
+// CHECK: call void @__kmpc_omp_taskwait_deps_51(
+// CHECK-SAME: i32 0, ptr %{{.*}}, i32 0, ptr null, i32 0)
+
+// The negative-step counterpart must also remain empty.
+llvm.func @empty_negative(%x: !llvm.ptr) {
+ %lb = llvm.mlir.constant(2 : i128) : i128
+ %ub = llvm.mlir.constant(18446744073709551617 : i128) : i128
+ %st = llvm.mlir.constant(-1 : i128) : i128
+ %it = omp.iterator(%i: i128) = (%lb to %ub step %st) {
+ omp.yield(%x : !llvm.ptr)
+ } -> !omp.iterated<!llvm.ptr>
+ omp.taskwait depend(taskdependin -> %it : !omp.iterated<!llvm.ptr>)
+ llvm.return
+}
+// CHECK-LABEL: define void @empty_negative(
+// CHECK: icmp ult i64 %{{.*}}, 0
+// CHECK: call void @__kmpc_omp_taskwait_deps_51(
+// CHECK-SAME: i32 0, ptr %{{.*}}, i32 0, ptr null, i32 0)
+
// Bounds and induction values keep their declared width; only the trip count
// is converted to i64.
llvm.func @dynamic(%x: !llvm.ptr, %lb: i128, %ub: i128, %st: i128) {
diff --git a/mlir/test/Target/LLVMIR/openmp-todo.mlir b/mlir/test/Target/LLVMIR/openmp-todo.mlir
index 327d091538863..2b502ac2ef028 100644
--- a/mlir/test/Target/LLVMIR/openmp-todo.mlir
+++ b/mlir/test/Target/LLVMIR/openmp-todo.mlir
@@ -1,5 +1,52 @@
// RUN: mlir-translate -mlir-to-llvmir -split-input-file -verify-diagnostics %s
+// -----
+
+llvm.func @target_enter_data_iterated_depend(%x: !llvm.ptr) {
+ %one = llvm.mlir.constant(1 : i64) : i64
+ %it = omp.iterator(%i: i64) = (%one to %one step %one) {
+ omp.yield(%x : !llvm.ptr)
+ } -> !omp.iterated<!llvm.ptr>
+ // expected-error at +2 {{Unhandled clause depend in omp.target_enter_data}}
+ // expected-error at +1 {{LLVM Translation failed}}
+ omp.target_enter_data depend(taskdependin -> %it : !omp.iterated<!llvm.ptr>) {
+ omp.terminator
+ }
+ llvm.return
+}
+
+// -----
+
+llvm.func @target_exit_data_iterated_depend(%x: !llvm.ptr) {
+ %one = llvm.mlir.constant(1 : i64) : i64
+ %it = omp.iterator(%i: i64) = (%one to %one step %one) {
+ omp.yield(%x : !llvm.ptr)
+ } -> !omp.iterated<!llvm.ptr>
+ // expected-error at +2 {{Unhandled clause depend in omp.target_exit_data}}
+ // expected-error at +1 {{LLVM Translation failed}}
+ omp.target_exit_data depend(taskdependin -> %it : !omp.iterated<!llvm.ptr>) {
+ omp.terminator
+ }
+ llvm.return
+}
+
+// -----
+
+llvm.func @target_update_iterated_depend(%x: !llvm.ptr) {
+ %one = llvm.mlir.constant(1 : i64) : i64
+ %it = omp.iterator(%i: i64) = (%one to %one step %one) {
+ omp.yield(%x : !llvm.ptr)
+ } -> !omp.iterated<!llvm.ptr>
+ // expected-error at +2 {{Unhandled clause depend in omp.target_update}}
+ // expected-error at +1 {{LLVM Translation failed}}
+ omp.target_update depend(taskdependin -> %it : !omp.iterated<!llvm.ptr>) {
+ omp.terminator
+ }
+ llvm.return
+}
+
+// -----
+
llvm.func @atomic_hint(%v : !llvm.ptr, %x : !llvm.ptr, %expr : i32) {
// expected-warning at below {{hint clause discarded}}
>From 73d4de3bf0c700447045b7cef2ca1c505e4b973b Mon Sep 17 00:00:00 2001
From: "Chi Chun, Chen" <chichun.chen at hpe.com>
Date: Tue, 6 Oct 2026 13:19:09 -0500
Subject: [PATCH 4/8] Lower iterator ranges in the iterator's own type
Flang converted iterator bounds and steps to index before building
omp.iterator. An integer(16) range such as
9223372036854775807:9223372036854775809 therefore wrapped and produced no
dependences or affinity entries.
Convert begin and end to the iterator variable's type, and build each
range in the wider of that type and the step's type so that a large step
can't change direction. Translation counts each range one bit wider than
its operands, so wide kinds keep all their entries.
Lowering now relies on the iterator being an integer, so DEPEND
iterators get the same semantic checks as the other clauses that take an
iterator modifier. The range warnings in those checks now skip constants
wider than 64 bits, which they used to truncate.
---
flang/lib/Lower/OpenMP/ClauseProcessor.cpp | 38 ++--
flang/lib/Semantics/check-omp-structure.cpp | 18 +-
flang/test/Lower/OpenMP/depend-iterator.f90 | 167 +++++++++---------
.../Lower/OpenMP/iterator-empty-range.f90 | 84 ++++++---
.../OpenMP/iterator-source-occurrences.f90 | 74 ++++----
flang/test/Lower/OpenMP/task-affinity.f90 | 106 +++++------
flang/test/Semantics/OpenMP/depend08.f90 | 17 ++
7 files changed, 261 insertions(+), 243 deletions(-)
create mode 100644 flang/test/Semantics/OpenMP/depend08.f90
diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
index e99c803fff5d7..72f6e7e59def7 100644
--- a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
+++ b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
@@ -256,23 +256,23 @@ static IteratorRange lowerIteratorRange(
mlir::Value ubVal =
fir::getBase(converter.genExprValue(toEvExpr(ubExpr), stmtCtx));
- auto toIndex = [](fir::FirOpBuilder &builder, mlir::Location loc,
- mlir::Value v) -> mlir::Value {
- if (v.getType().isIndex())
- return v;
- return fir::ConvertOp::create(builder, loc, builder.getIndexType(), v);
- };
-
- r.lb = toIndex(builder, loc, lbVal);
- r.ub = toIndex(builder, loc, ubVal);
-
- if (stExpr) {
- mlir::Value stVal =
- fir::getBase(converter.genExprValue(toEvExpr(*stExpr), stmtCtx));
- r.step = toIndex(builder, loc, stVal);
- } else {
- r.step = mlir::arith::ConstantIndexOp::create(builder, loc, 1);
- }
+ // Begin and end take the iterator's type, but the step keeps its own. Count
+ // in the wider of the two so that neither is narrowed.
+ mlir::Type ivTy = converter.genType(*r.ivSym);
+ mlir::Value stVal =
+ stExpr ? fir::getBase(converter.genExprValue(toEvExpr(*stExpr), stmtCtx))
+ : builder.createIntegerConstant(loc, ivTy, 1);
+ mlir::Type rangeTy = ivTy;
+ if (auto stTy = mlir::dyn_cast<mlir::IntegerType>(stVal.getType()))
+ if (stTy.isSignless() &&
+ stTy.getWidth() > mlir::cast<mlir::IntegerType>(ivTy).getWidth())
+ rangeTy = stTy;
+
+ r.lb = builder.createConvert(loc, rangeTy,
+ builder.createConvert(loc, ivTy, lbVal));
+ r.ub = builder.createConvert(loc, rangeTy,
+ builder.createConvert(loc, ivTy, ubVal));
+ r.step = builder.createConvert(loc, rangeTy, stVal);
return r;
}
@@ -306,8 +306,8 @@ static mlir::Value buildIteratorOp(Fortran::lower::AbstractConverter &converter,
llvm::SmallVector<mlir::Value> ivs;
ivs.reserve(ranges.size());
- for (size_t i = 0; i < ranges.size(); ++i)
- ivs.push_back(body->addArgument(builder.getIndexType(), loc));
+ for (const IteratorRange &r : ranges)
+ ivs.push_back(body->addArgument(r.lb.getType(), loc));
Fortran::lower::SymMap &symMap = converter.getSymbolMap();
Fortran::lower::SymMapScope scope(symMap);
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 6193b297b62fb..5b7f2db27d1cc 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -1569,15 +1569,24 @@ void OmpStructureChecker::CheckIteratorRange(
"The begin and end expressions in iterator range-specification are "
"mandatory"_err_en_US);
}
+ // GetIntValue keeps only the low 64 bits, so skip wider constants.
+ auto getIntValue{[](const auto &e) -> std::optional<int64_t> {
+ if (const auto *expr{GetExpr(nullptr, e)}) {
+ if (auto type{expr->GetType()}; type && type->kind() <= 8) {
+ return evaluate::ToInt64(*expr);
+ }
+ }
+ return std::nullopt;
+ }};
// [5.2:67:19] In a range-specification, if the step is not specified its
// value is implicitly defined to be 1.
- if (auto stepv{step ? GetIntValue(*step) : std::optional<int64_t>{1}}) {
+ if (auto stepv{step ? getIntValue(*step) : std::optional<int64_t>{1}}) {
if (*stepv == 0) {
context_.Say(
x.source, "The step value in the iterator range is 0"_warn_en_US);
} else if (begin && end) {
- std::optional<int64_t> beginv{GetIntValue(*begin)};
- std::optional<int64_t> endv{GetIntValue(*end)};
+ std::optional<int64_t> beginv{getIntValue(*begin)};
+ std::optional<int64_t> endv{getIntValue(*end)};
if (beginv && endv) {
if (*stepv > 0 && *beginv > *endv) {
context_.Say(x.source,
@@ -5266,7 +5275,8 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Depend &x) {
}
}
auto &modifiers{OmpGetModifiers(*taskDep)};
- if (OmpGetUniqueModifier<parser::OmpIterator>(modifiers)) {
+ if (auto *iter{OmpGetUniqueModifier<parser::OmpIterator>(modifiers)}) {
+ CheckIteratorModifier(*iter);
if (dir == llvm::omp::OMPD_depobj) {
context_.Say(GetContext().clauseSource,
"An iterator-modifier may specify multiple locators, a DEPEND clause on a DEPOBJ construct must only specify one locator"_warn_en_US);
diff --git a/flang/test/Lower/OpenMP/depend-iterator.f90 b/flang/test/Lower/OpenMP/depend-iterator.f90
index bd83fdc8a01ad..42d6a4f8d7688 100644
--- a/flang/test/Lower/OpenMP/depend-iterator.f90
+++ b/flang/test/Lower/OpenMP/depend-iterator.f90
@@ -24,15 +24,12 @@ subroutine depend_unused_iterator(m)
! CHECK-SAME: uniq_name("_QFdepend_unused_iteratorEa")
! CHECK: %[[M:.*]]:2 = hlfir.declare
! CHECK-SAME: uniq_name("_QFdepend_unused_iteratorEm")
-! CHECK: %[[I_LB32:.*]] = arith.constant 1 : i32
-! CHECK: %[[I_UB32:.*]] = arith.constant 2 : i32
-! CHECK: %[[I_LB:.*]] = fir.convert %[[I_LB32]] : (i32) -> index
-! CHECK: %[[I_UB:.*]] = fir.convert %[[I_UB32]] : (i32) -> index
-! CHECK: %[[I_STEP:.*]] = arith.constant 1 : index
-! CHECK: %[[IT_I:.*]] = omp.iterator(%[[IV_I:.*]]: index) =
+! CHECK: %[[I_LB:.*]] = arith.constant 1 : i32
+! CHECK: %[[I_UB:.*]] = arith.constant 2 : i32
+! CHECK: %[[I_STEP:.*]] = arith.constant 1 : i32
+! CHECK: %[[IT_I:.*]] = omp.iterator(%[[IV_I:.*]]: i32) =
! CHECK-SAME: (%[[I_LB]] to %[[I_UB]] step %[[I_STEP]]) {
-! CHECK: %[[V32_I:.*]] = fir.convert %[[IV_I]] : (index) -> i32
-! CHECK: fir.store %[[V32_I]] to %[[MEM_I:.*]] : !fir.ref<i32>
+! CHECK: fir.store %[[IV_I]] to %[[MEM_I:.*]] : !fir.ref<i32>
! CHECK: %[[DECL_I:.*]]:2 = hlfir.declare %[[MEM_I]]
! CHECK: %[[LD_I:.*]] = fir.load %[[DECL_I]]#0 : !fir.ref<i32>
! CHECK: %[[IDX_I:.*]] = fir.convert %[[LD_I]] : (i32) -> i64
@@ -63,20 +60,15 @@ subroutine depend_per_locator(m)
! CHECK-SAME: uniq_name("_QFdepend_per_locatorEc")
! CHECK: %[[M:.*]]:2 = hlfir.declare
! CHECK-SAME: uniq_name("_QFdepend_per_locatorEm")
-! CHECK: %[[I_LB32:.*]] = arith.constant 1 : i32
-! CHECK: %[[I_UB32:.*]] = arith.constant 2 : i32
-! CHECK: %[[I_LB:.*]] = fir.convert %[[I_LB32]] : (i32) -> index
-! CHECK: %[[I_UB:.*]] = fir.convert %[[I_UB32]] : (i32) -> index
-! CHECK: %[[I_STEP:.*]] = arith.constant 1 : index
-! CHECK: %[[J_LB32:.*]] = arith.constant 3 : i32
-! CHECK: %[[J_UB32:.*]] = fir.load %[[M]]#0 : !fir.ref<i32>
-! CHECK: %[[J_LB:.*]] = fir.convert %[[J_LB32]] : (i32) -> index
-! CHECK: %[[J_UB:.*]] = fir.convert %[[J_UB32]] : (i32) -> index
-! CHECK: %[[J_STEP:.*]] = arith.constant 1 : index
-! CHECK: %[[IT_I:.*]] = omp.iterator(%[[IV_I:.*]]: index) =
+! CHECK: %[[I_LB:.*]] = arith.constant 1 : i32
+! CHECK: %[[I_UB:.*]] = arith.constant 2 : i32
+! CHECK: %[[I_STEP:.*]] = arith.constant 1 : i32
+! CHECK: %[[J_LB:.*]] = arith.constant 3 : i32
+! CHECK: %[[J_UB:.*]] = fir.load %[[M]]#0 : !fir.ref<i32>
+! CHECK: %[[J_STEP:.*]] = arith.constant 1 : i32
+! CHECK: %[[IT_I:.*]] = omp.iterator(%[[IV_I:.*]]: i32) =
! CHECK-SAME: (%[[I_LB]] to %[[I_UB]] step %[[I_STEP]]) {
-! CHECK: %[[V32_I:.*]] = fir.convert %[[IV_I]] : (index) -> i32
-! CHECK: fir.store %[[V32_I]] to %[[MEM_I:.*]] : !fir.ref<i32>
+! CHECK: fir.store %[[IV_I]] to %[[MEM_I:.*]] : !fir.ref<i32>
! CHECK: %[[DECL_I:.*]]:2 = hlfir.declare %[[MEM_I]]
! CHECK: %[[LD_I:.*]] = fir.load %[[DECL_I]]#0 : !fir.ref<i32>
! CHECK: %[[IDX_I:.*]] = fir.convert %[[LD_I]] : (i32) -> i64
@@ -85,10 +77,9 @@ subroutine depend_per_locator(m)
! CHECK-SAME: (!fir.ref<i32>) -> !llvm.ptr
! CHECK: omp.yield(%[[PTR_I]] : !llvm.ptr)
! CHECK: } -> !omp.iterated<!llvm.ptr>
-! CHECK: %[[IT_J:.*]] = omp.iterator(%[[IV_J:.*]]: index) =
+! CHECK: %[[IT_J:.*]] = omp.iterator(%[[IV_J:.*]]: i32) =
! CHECK-SAME: (%[[J_LB]] to %[[J_UB]] step %[[J_STEP]]) {
-! CHECK: %[[V32_J:.*]] = fir.convert %[[IV_J]] : (index) -> i32
-! CHECK: fir.store %[[V32_J]] to %[[MEM_J:.*]] : !fir.ref<i32>
+! CHECK: fir.store %[[IV_J]] to %[[MEM_J:.*]] : !fir.ref<i32>
! CHECK: %[[DECL_J:.*]]:2 = hlfir.declare %[[MEM_J]]
! CHECK: %[[LD_J:.*]] = fir.load %[[DECL_J]]#0 : !fir.ref<i32>
! CHECK: %[[IDX_J:.*]] = fir.convert %[[LD_J]] : (i32) -> i64
@@ -102,6 +93,28 @@ subroutine depend_per_locator(m)
! CHECK-SAME: taskdependin -> %[[IT_I]] : !omp.iterated<!llvm.ptr>,
! CHECK-SAME: taskdependin -> %[[IT_J]] : !omp.iterated<!llvm.ptr>) {
+! Each range and induction value keeps its own iterator's kind.
+subroutine depend_iterator_kinds(a, n)
+ integer :: a(4, 4)
+ integer(8) :: n
+ !$omp task depend(iterator(integer(8) :: i = 1:n, j = 1:2), in: a(i, j))
+ !$omp end task
+end subroutine
+
+! CHECK-LABEL: func.func @_QPdepend_iterator_kinds(
+! CHECK: %[[N:.*]]:2 = hlfir.declare {{.*}}uniq_name("_QFdepend_iterator_kindsEn")
+! CHECK: %[[I_UB:.*]] = fir.load %[[N]]#0 : !fir.ref<i64>
+! CHECK: %[[I_STEP:.*]] = arith.constant 1 : i64
+! CHECK: %[[I_LB:.*]] = fir.convert %{{.*}} : (i32) -> i64
+! CHECK: %[[J_LB:.*]] = arith.constant 1 : i32
+! CHECK: %[[J_UB:.*]] = arith.constant 2 : i32
+! CHECK: %[[J_STEP:.*]] = arith.constant 1 : i32
+! CHECK: omp.iterator(%[[IV_I:.*]]: i64, %[[IV_J:.*]]: i32) =
+! CHECK-SAME: (%[[I_LB]] to %[[I_UB]] step %[[I_STEP]],
+! CHECK-SAME: %[[J_LB]] to %[[J_UB]] step %[[J_STEP]]) {
+! CHECK: fir.store %[[IV_I]] to %{{.*}} : !fir.ref<i64>
+! CHECK: fir.store %[[IV_J]] to %{{.*}} : !fir.ref<i32>
+
subroutine task_depend_iterator_simple()
integer, parameter :: n = 16
integer :: a(n)
@@ -113,9 +126,8 @@ subroutine task_depend_iterator_simple()
! CHECK-LABEL: func.func @_QPtask_depend_iterator_simple()
! CHECK: %[[A:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) uniq_name("_QFtask_depend_iterator_simpleEa")
-! CHECK: %[[IT:.*]] = omp.iterator(%[[IV:.*]]: index) = ({{.*}} to {{.*}} step {{.*}}) {
-! CHECK: %[[IV_I32:.*]] = fir.convert %[[IV]] : (index) -> i32
-! CHECK: fir.store %[[IV_I32]] to %[[IV_MEM:.*]] : !fir.ref<i32>
+! CHECK: %[[IT:.*]] = omp.iterator(%[[IV:.*]]: i32) = ({{.*}} to {{.*}} step {{.*}}) {
+! CHECK: fir.store %[[IV]] to %[[IV_MEM:.*]] : !fir.ref<i32>
! Iterator IV temp must be named in the compiler-generated namespace ("_QQ"
! prefix) so it is not emitted as a bogus user local in DWARF under -g.
! CHECK: %[[IV_DECL:.*]]:2 = hlfir.declare %[[IV_MEM]] uniq_name("_QQ{{.*}}.omp.iter")
@@ -139,12 +151,10 @@ subroutine task_depend_iterator_2d()
end subroutine
! CHECK-LABEL: func.func @_QPtask_depend_iterator_2d()
-! CHECK: %[[IT:.*]] = omp.iterator(%[[IV0:.*]]: index, %[[IV1:.*]]: index) = ({{.*}} to {{.*}} step {{.*}}, {{.*}} to {{.*}} step {{.*}}) {
-! CHECK: %[[IV0_I32:.*]] = fir.convert %[[IV0]] : (index) -> i32
-! CHECK: fir.store %[[IV0_I32]] to %[[IV0_MEM:.*]] : !fir.ref<i32>
+! CHECK: %[[IT:.*]] = omp.iterator(%[[IV0:.*]]: i32, %[[IV1:.*]]: i32) = ({{.*}} to {{.*}} step {{.*}}, {{.*}} to {{.*}} step {{.*}}) {
+! CHECK: fir.store %[[IV0]] to %[[IV0_MEM:.*]] : !fir.ref<i32>
! CHECK: %[[IV0_DECL:.*]]:2 = hlfir.declare %[[IV0_MEM]]
-! CHECK: %[[IV1_I32:.*]] = fir.convert %[[IV1]] : (index) -> i32
-! CHECK: fir.store %[[IV1_I32]] to %[[IV1_MEM:.*]] : !fir.ref<i32>
+! CHECK: fir.store %[[IV1]] to %[[IV1_MEM:.*]] : !fir.ref<i32>
! CHECK: %[[IV1_DECL:.*]]:2 = hlfir.declare %[[IV1_MEM]]
! CHECK: %[[IV0_LD:.*]] = fir.load %[[IV0_DECL]]#0 : !fir.ref<i32>
! CHECK: %[[IV0_I64:.*]] = fir.convert %[[IV0_LD]] : (i32) -> i64
@@ -168,7 +178,7 @@ subroutine task_depend_iterator_mixed()
! CHECK-LABEL: func.func @_QPtask_depend_iterator_mixed()
! CHECK: %[[A:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) uniq_name("_QFtask_depend_iterator_mixedEa")
! CHECK: %[[X:.*]]:2 = hlfir.declare %{{.*}} uniq_name("_QFtask_depend_iterator_mixedEx")
-! CHECK: %[[IT:.*]] = omp.iterator(%[[IV:.*]]: index) = ({{.*}} to {{.*}} step {{.*}}) {
+! CHECK: %[[IT:.*]] = omp.iterator(%[[IV:.*]]: i32) = ({{.*}} to {{.*}} step {{.*}}) {
! CHECK: omp.yield(%{{.*}} : !llvm.ptr)
! CHECK: } -> !omp.iterated<!llvm.ptr>
! CHECK: omp.task depend(taskdependout -> %[[X]]#0 : !fir.ref<i32>, taskdependin -> %[[IT]] : !omp.iterated<!llvm.ptr>) {
@@ -183,13 +193,10 @@ subroutine task_depend_iterator_step()
end subroutine
! CHECK-LABEL: func.func @_QPtask_depend_iterator_step()
-! CHECK: %[[C1_I32:.*]] = arith.constant 1 : i32
-! CHECK: %[[C16_I32:.*]] = arith.constant 16 : i32
-! CHECK: %[[LB:.*]] = fir.convert %[[C1_I32]] : (i32) -> index
-! CHECK: %[[UB:.*]] = fir.convert %[[C16_I32]] : (i32) -> index
-! CHECK: %[[C2_I32:.*]] = arith.constant 2 : i32
-! CHECK: %[[STEP:.*]] = fir.convert %[[C2_I32]] : (i32) -> index
-! CHECK: %[[IT:.*]] = omp.iterator(%[[IV:.*]]: index) = (%[[LB]] to %[[UB]] step %[[STEP]]) {
+! CHECK: %[[LB:.*]] = arith.constant 1 : i32
+! CHECK: %[[UB:.*]] = arith.constant 16 : i32
+! CHECK: %[[STEP:.*]] = arith.constant 2 : i32
+! CHECK: %[[IT:.*]] = omp.iterator(%[[IV:.*]]: i32) = (%[[LB]] to %[[UB]] step %[[STEP]]) {
! CHECK: omp.yield(%{{.*}} : !llvm.ptr)
! CHECK: } -> !omp.iterated<!llvm.ptr>
! CHECK: omp.task depend(taskdependin -> %[[IT]] : !omp.iterated<!llvm.ptr>) {
@@ -206,12 +213,12 @@ subroutine task_depend_iterator_multi_obj()
! CHECK-LABEL: func.func @_QPtask_depend_iterator_multi_obj()
! CHECK: %[[A:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) uniq_name("_QFtask_depend_iterator_multi_objEa")
! CHECK: %[[B:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) uniq_name("_QFtask_depend_iterator_multi_objEb")
-! CHECK: %[[IT1:.*]] = omp.iterator(%[[IV1:.*]]: index) = ({{.*}} to {{.*}} step {{.*}}) {
+! CHECK: %[[IT1:.*]] = omp.iterator(%[[IV1:.*]]: i32) = ({{.*}} to {{.*}} step {{.*}}) {
! CHECK: %[[COOR1:.*]] = hlfir.designate %[[A]]#0 (%{{.*}})
! CHECK: %[[PTR1:.*]] = fir.convert %[[COOR1]] : (!fir.ref<i32>) -> !llvm.ptr
! CHECK: omp.yield(%[[PTR1]] : !llvm.ptr)
! CHECK: } -> !omp.iterated<!llvm.ptr>
-! CHECK: %[[IT2:.*]] = omp.iterator(%[[IV2:.*]]: index) = ({{.*}} to {{.*}} step {{.*}}) {
+! CHECK: %[[IT2:.*]] = omp.iterator(%[[IV2:.*]]: i32) = ({{.*}} to {{.*}} step {{.*}}) {
! CHECK: %[[COOR2:.*]] = hlfir.designate %[[B]]#0 (%{{.*}})
! CHECK: %[[PTR2:.*]] = fir.convert %[[COOR2]] : (!fir.ref<i32>) -> !llvm.ptr
! CHECK: omp.yield(%[[PTR2]] : !llvm.ptr)
@@ -232,12 +239,10 @@ subroutine task_depend_iterator_expr_subscript()
! CHECK-LABEL: func.func @_QPtask_depend_iterator_expr_subscript()
! CHECK: %[[A:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) uniq_name("_QFtask_depend_iterator_expr_subscriptEa")
-! CHECK: %[[IT:.*]] = omp.iterator(%[[IV0:.*]]: index, %[[IV1:.*]]: index) = ({{.*}} to {{.*}} step {{.*}}, {{.*}} to {{.*}} step {{.*}}) {
-! CHECK: %[[IV0_I32:.*]] = fir.convert %[[IV0]] : (index) -> i32
-! CHECK: fir.store %[[IV0_I32]] to %[[IV0_MEM:.*]] : !fir.ref<i32>
+! CHECK: %[[IT:.*]] = omp.iterator(%[[IV0:.*]]: i32, %[[IV1:.*]]: i32) = ({{.*}} to {{.*}} step {{.*}}, {{.*}} to {{.*}} step {{.*}}) {
+! CHECK: fir.store %[[IV0]] to %[[IV0_MEM:.*]] : !fir.ref<i32>
! CHECK: %[[IV0_DECL:.*]]:2 = hlfir.declare %[[IV0_MEM]]
-! CHECK: %[[IV1_I32:.*]] = fir.convert %[[IV1]] : (index) -> i32
-! CHECK: fir.store %[[IV1_I32]] to %[[IV1_MEM:.*]] : !fir.ref<i32>
+! CHECK: fir.store %[[IV1]] to %[[IV1_MEM:.*]] : !fir.ref<i32>
! CHECK: %[[IV1_DECL:.*]]:2 = hlfir.declare %[[IV1_MEM]]
! CHECK: %[[IV0_LD:.*]] = fir.load %[[IV0_DECL]]#0 : !fir.ref<i32>
! CHECK: %[[C1_I32:.*]] = arith.constant 1 : i32
@@ -267,12 +272,12 @@ subroutine task_depend_multi_iter_clauses()
! CHECK-LABEL: func.func @_QPtask_depend_multi_iter_clauses()
! CHECK: %[[A:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) uniq_name("_QFtask_depend_multi_iter_clausesEa")
! CHECK: %[[B:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) uniq_name("_QFtask_depend_multi_iter_clausesEb")
-! CHECK: %[[IT1:.*]] = omp.iterator(%[[IV1:.*]]: index) = ({{.*}} to {{.*}} step {{.*}}) {
+! CHECK: %[[IT1:.*]] = omp.iterator(%[[IV1:.*]]: i32) = ({{.*}} to {{.*}} step {{.*}}) {
! CHECK: %[[COOR1:.*]] = hlfir.designate %[[A]]#0 (%{{.*}})
! CHECK: %[[PTR1:.*]] = fir.convert %[[COOR1]] : (!fir.ref<i32>) -> !llvm.ptr
! CHECK: omp.yield(%[[PTR1]] : !llvm.ptr)
! CHECK: } -> !omp.iterated<!llvm.ptr>
-! CHECK: %[[IT2:.*]] = omp.iterator(%[[IV2:.*]]: index) = ({{.*}} to {{.*}} step {{.*}}) {
+! CHECK: %[[IT2:.*]] = omp.iterator(%[[IV2:.*]]: i32) = ({{.*}} to {{.*}} step {{.*}}) {
! CHECK: %[[COOR2:.*]] = hlfir.designate %[[B]]#0 (%{{.*}})
! CHECK: %[[PTR2:.*]] = fir.convert %[[COOR2]] : (!fir.ref<i32>) -> !llvm.ptr
! CHECK: omp.yield(%[[PTR2]] : !llvm.ptr)
@@ -289,13 +294,10 @@ subroutine task_depend_iterator_negative_step()
end subroutine
! CHECK-LABEL: func.func @_QPtask_depend_iterator_negative_step()
-! CHECK: %[[C16_I32:.*]] = arith.constant 16 : i32
-! CHECK: %[[C1_I32:.*]] = arith.constant 1 : i32
-! CHECK: %[[LB:.*]] = fir.convert %[[C16_I32]] : (i32) -> index
-! CHECK: %[[UB:.*]] = fir.convert %[[C1_I32]] : (i32) -> index
-! CHECK: %[[CM1_I32:.*]] = arith.constant -1 : i32
-! CHECK: %[[STEP:.*]] = fir.convert %[[CM1_I32]] : (i32) -> index
-! CHECK: %[[IT:.*]] = omp.iterator(%[[IV:.*]]: index) = (%[[LB]] to %[[UB]] step %[[STEP]]) {
+! CHECK: %[[LB:.*]] = arith.constant 16 : i32
+! CHECK: %[[UB:.*]] = arith.constant 1 : i32
+! CHECK: %[[STEP:.*]] = arith.constant -1 : i32
+! CHECK: %[[IT:.*]] = omp.iterator(%[[IV:.*]]: i32) = (%[[LB]] to %[[UB]] step %[[STEP]]) {
! CHECK: omp.yield(%{{.*}} : !llvm.ptr)
! CHECK: } -> !omp.iterated<!llvm.ptr>
! CHECK: omp.task depend(taskdependin -> %[[IT]] : !omp.iterated<!llvm.ptr>) {
@@ -315,7 +317,7 @@ subroutine task_depend_iterator_mixed_within_clause()
! CHECK-LABEL: func.func @_QPtask_depend_iterator_mixed_within_clause()
! CHECK: %[[A:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) uniq_name("_QFtask_depend_iterator_mixed_within_clauseEa")
! CHECK: %[[A1:.*]] = hlfir.designate %[[A]]#0 (%{{.*}}) : (!fir.ref<!fir.array<16xi32>>, index) -> !fir.ref<i32>
-! CHECK: %[[IT:.*]] = omp.iterator(%[[IV:.*]]: index) = ({{.*}} to {{.*}} step {{.*}}) {
+! CHECK: %[[IT:.*]] = omp.iterator(%[[IV:.*]]: i32) = ({{.*}} to {{.*}} step {{.*}}) {
! CHECK: %[[COOR:.*]] = hlfir.designate %[[A]]#0 (%{{.*}})
! CHECK: %[[PTR:.*]] = fir.convert %[[COOR]] : (!fir.ref<i32>) -> !llvm.ptr
! CHECK: omp.yield(%[[PTR]] : !llvm.ptr)
@@ -338,9 +340,8 @@ subroutine target_depend_iterator()
! CHECK-LABEL: func.func @_QPtarget_depend_iterator()
! CHECK: %[[A:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) uniq_name("_QFtarget_depend_iteratorEa")
-! CHECK: %[[IT:.*]] = omp.iterator(%[[IV:.*]]: index) = ({{.*}} to {{.*}} step {{.*}}) {
-! CHECK: %[[IV_I32:.*]] = fir.convert %[[IV]] : (index) -> i32
-! CHECK: fir.store %[[IV_I32]] to %[[IV_MEM:.*]] : !fir.ref<i32>
+! CHECK: %[[IT:.*]] = omp.iterator(%[[IV:.*]]: i32) = ({{.*}} to {{.*}} step {{.*}}) {
+! CHECK: fir.store %[[IV]] to %[[IV_MEM:.*]] : !fir.ref<i32>
! CHECK: %[[IV_DECL:.*]]:2 = hlfir.declare %[[IV_MEM]]
! CHECK: %[[IV_LD:.*]] = fir.load %[[IV_DECL]]#0 : !fir.ref<i32>
! CHECK: %[[IV_I64:.*]] = fir.convert %[[IV_LD]] : (i32) -> i64
@@ -369,15 +370,15 @@ subroutine target_depend_iterator_multi()
! CHECK: %[[A:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) uniq_name("_QFtarget_depend_iterator_multiEa")
! CHECK: %[[B:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) uniq_name("_QFtarget_depend_iterator_multiEb")
! CHECK: %[[C:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) uniq_name("_QFtarget_depend_iterator_multiEc")
-! CHECK: %[[IT1:.*]] = omp.iterator(%{{.*}}: index) = ({{.*}} to {{.*}} step {{.*}}) {
+! CHECK: %[[IT1:.*]] = omp.iterator(%{{.*}}: i32) = ({{.*}} to {{.*}} step {{.*}}) {
! CHECK: %[[COOR1:.*]] = hlfir.designate %[[A]]#0 (%{{.*}})
! CHECK: omp.yield(%{{.*}} : !llvm.ptr)
! CHECK: } -> !omp.iterated<!llvm.ptr>
-! CHECK: %[[IT2:.*]] = omp.iterator(%{{.*}}: index) = ({{.*}} to {{.*}} step {{.*}}) {
+! CHECK: %[[IT2:.*]] = omp.iterator(%{{.*}}: i32) = ({{.*}} to {{.*}} step {{.*}}) {
! CHECK: %[[COOR2:.*]] = hlfir.designate %[[B]]#0 (%{{.*}})
! CHECK: omp.yield(%{{.*}} : !llvm.ptr)
! CHECK: } -> !omp.iterated<!llvm.ptr>
-! CHECK: %[[IT3:.*]] = omp.iterator(%{{.*}}: index) = ({{.*}} to {{.*}} step {{.*}}) {
+! CHECK: %[[IT3:.*]] = omp.iterator(%{{.*}}: i32) = ({{.*}} to {{.*}} step {{.*}}) {
! CHECK: %[[COOR3:.*]] = hlfir.designate %[[C]]#0 (%{{.*}})
! CHECK: omp.yield(%{{.*}} : !llvm.ptr)
! CHECK: } -> !omp.iterated<!llvm.ptr>
@@ -400,9 +401,8 @@ subroutine target_enter_data_depend_iterator()
! CHECK-LABEL: func.func @_QPtarget_enter_data_depend_iterator()
! CHECK: %[[A:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) uniq_name("_QFtarget_enter_data_depend_iteratorEa")
-! CHECK: %[[IT:.*]] = omp.iterator(%[[IV:.*]]: index) = ({{.*}} to {{.*}} step {{.*}}) {
-! CHECK: %[[IV_I32:.*]] = fir.convert %[[IV]] : (index) -> i32
-! CHECK: fir.store %[[IV_I32]] to %[[IV_MEM:.*]] : !fir.ref<i32>
+! CHECK: %[[IT:.*]] = omp.iterator(%[[IV:.*]]: i32) = ({{.*}} to {{.*}} step {{.*}}) {
+! CHECK: fir.store %[[IV]] to %[[IV_MEM:.*]] : !fir.ref<i32>
! CHECK: %[[IV_DECL:.*]]:2 = hlfir.declare %[[IV_MEM]]
! CHECK: %[[IV_LD:.*]] = fir.load %[[IV_DECL]]#0 : !fir.ref<i32>
! CHECK: %[[IV_I64:.*]] = fir.convert %[[IV_LD]] : (i32) -> i64
@@ -426,12 +426,10 @@ subroutine target_enter_data_depend_iterator_expr()
! CHECK-LABEL: func.func @_QPtarget_enter_data_depend_iterator_expr()
! CHECK: %[[A:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) uniq_name("_QFtarget_enter_data_depend_iterator_exprEa")
! CHECK: %[[A1:.*]] = hlfir.designate %[[A]]#0 (%{{.*}}) : (!fir.ref<!fir.array<16xi32>>, index) -> !fir.ref<i32>
-! CHECK: %[[IT:.*]] = omp.iterator(%[[IV0:.*]]: index, %[[IV1:.*]]: index) = ({{.*}} to {{.*}} step {{.*}}, {{.*}} to {{.*}} step {{.*}}) {
-! CHECK: %[[IV0_I32:.*]] = fir.convert %[[IV0]] : (index) -> i32
-! CHECK: fir.store %[[IV0_I32]] to %[[IV0_MEM:.*]] : !fir.ref<i32>
+! CHECK: %[[IT:.*]] = omp.iterator(%[[IV0:.*]]: i32, %[[IV1:.*]]: i32) = ({{.*}} to {{.*}} step {{.*}}, {{.*}} to {{.*}} step {{.*}}) {
+! CHECK: fir.store %[[IV0]] to %[[IV0_MEM:.*]] : !fir.ref<i32>
! CHECK: %[[IV0_DECL:.*]]:2 = hlfir.declare %[[IV0_MEM]]
-! CHECK: %[[IV1_I32:.*]] = fir.convert %[[IV1]] : (index) -> i32
-! CHECK: fir.store %[[IV1_I32]] to %[[IV1_MEM:.*]] : !fir.ref<i32>
+! CHECK: fir.store %[[IV1]] to %[[IV1_MEM:.*]] : !fir.ref<i32>
! CHECK: %[[IV1_DECL:.*]]:2 = hlfir.declare %[[IV1_MEM]]
! CHECK: %[[IV0_LD:.*]] = fir.load %[[IV0_DECL]]#0 : !fir.ref<i32>
! CHECK: %[[SUB:.*]] = arith.subi %[[IV0_LD]], %{{.*}} : i32
@@ -460,9 +458,8 @@ subroutine target_exit_data_depend_iterator()
! CHECK-LABEL: func.func @_QPtarget_exit_data_depend_iterator()
! CHECK: %[[A:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) uniq_name("_QFtarget_exit_data_depend_iteratorEa")
-! CHECK: %[[IT:.*]] = omp.iterator(%[[IV:.*]]: index) = ({{.*}} to {{.*}} step {{.*}}) {
-! CHECK: %[[IV_I32:.*]] = fir.convert %[[IV]] : (index) -> i32
-! CHECK: fir.store %[[IV_I32]] to %[[IV_MEM:.*]] : !fir.ref<i32>
+! CHECK: %[[IT:.*]] = omp.iterator(%[[IV:.*]]: i32) = ({{.*}} to {{.*}} step {{.*}}) {
+! CHECK: fir.store %[[IV]] to %[[IV_MEM:.*]] : !fir.ref<i32>
! CHECK: %[[IV_DECL:.*]]:2 = hlfir.declare %[[IV_MEM]]
! CHECK: %[[IV_LD:.*]] = fir.load %[[IV_DECL]]#0 : !fir.ref<i32>
! CHECK: %[[IV_I64:.*]] = fir.convert %[[IV_LD]] : (i32) -> i64
@@ -485,17 +482,14 @@ subroutine target_exit_data_depend_iterator_multi()
! CHECK-LABEL: func.func @_QPtarget_exit_data_depend_iterator_multi()
! CHECK: %[[A:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) uniq_name("_QFtarget_exit_data_depend_iterator_multiEa")
! CHECK: %[[B:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) uniq_name("_QFtarget_exit_data_depend_iterator_multiEb")
-! CHECK: %[[C16_I32:.*]] = arith.constant 16 : i32
-! CHECK: %[[C1_I32:.*]] = arith.constant 1 : i32
-! CHECK: %[[LB:.*]] = fir.convert %[[C16_I32]] : (i32) -> index
-! CHECK: %[[UB:.*]] = fir.convert %[[C1_I32]] : (i32) -> index
-! CHECK: %[[CM1_I32:.*]] = arith.constant -1 : i32
-! CHECK: %[[STEP:.*]] = fir.convert %[[CM1_I32]] : (i32) -> index
-! CHECK: %[[IT1:.*]] = omp.iterator(%{{.*}}: index) = (%[[LB]] to %[[UB]] step %[[STEP]]) {
+! CHECK: %[[LB:.*]] = arith.constant 16 : i32
+! CHECK: %[[UB:.*]] = arith.constant 1 : i32
+! CHECK: %[[STEP:.*]] = arith.constant -1 : i32
+! CHECK: %[[IT1:.*]] = omp.iterator(%{{.*}}: i32) = (%[[LB]] to %[[UB]] step %[[STEP]]) {
! CHECK: %[[COOR1:.*]] = hlfir.designate %[[A]]#0 (%{{.*}})
! CHECK: omp.yield(%{{.*}} : !llvm.ptr)
! CHECK: } -> !omp.iterated<!llvm.ptr>
-! CHECK: %[[IT2:.*]] = omp.iterator(%{{.*}}: index) = (%[[LB]] to %[[UB]] step %[[STEP]]) {
+! CHECK: %[[IT2:.*]] = omp.iterator(%{{.*}}: i32) = (%[[LB]] to %[[UB]] step %[[STEP]]) {
! CHECK: %[[COOR2:.*]] = hlfir.designate %[[B]]#0 (%{{.*}})
! CHECK: omp.yield(%{{.*}} : !llvm.ptr)
! CHECK: } -> !omp.iterated<!llvm.ptr>
@@ -517,9 +511,8 @@ subroutine target_update_depend_iterator()
! CHECK-LABEL: func.func @_QPtarget_update_depend_iterator()
! CHECK: %[[A:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) uniq_name("_QFtarget_update_depend_iteratorEa")
-! CHECK: %[[IT:.*]] = omp.iterator(%[[IV:.*]]: index) = ({{.*}} to {{.*}} step {{.*}}) {
-! CHECK: %[[IV_I32:.*]] = fir.convert %[[IV]] : (index) -> i32
-! CHECK: fir.store %[[IV_I32]] to %[[IV_MEM:.*]] : !fir.ref<i32>
+! CHECK: %[[IT:.*]] = omp.iterator(%[[IV:.*]]: i32) = ({{.*}} to {{.*}} step {{.*}}) {
+! CHECK: fir.store %[[IV]] to %[[IV_MEM:.*]] : !fir.ref<i32>
! CHECK: %[[IV_DECL:.*]]:2 = hlfir.declare %[[IV_MEM]]
! CHECK: %[[IV_LD:.*]] = fir.load %[[IV_DECL]]#0 : !fir.ref<i32>
! CHECK: %[[IV_I64:.*]] = fir.convert %[[IV_LD]] : (i32) -> i64
@@ -547,11 +540,11 @@ subroutine target_update_depend_iterator_multi()
! CHECK: %[[A:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) uniq_name("_QFtarget_update_depend_iterator_multiEa")
! CHECK: %[[B:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) uniq_name("_QFtarget_update_depend_iterator_multiEb")
! CHECK: %[[X:.*]]:2 = hlfir.declare %{{.*}} uniq_name("_QFtarget_update_depend_iterator_multiEx")
-! CHECK: %[[IT1:.*]] = omp.iterator(%{{.*}}: index) = ({{.*}} to {{.*}} step {{.*}}) {
+! CHECK: %[[IT1:.*]] = omp.iterator(%{{.*}}: i32) = ({{.*}} to {{.*}} step {{.*}}) {
! CHECK: %[[COOR1:.*]] = hlfir.designate %[[A]]#0 (%{{.*}})
! CHECK: omp.yield(%{{.*}} : !llvm.ptr)
! CHECK: } -> !omp.iterated<!llvm.ptr>
-! CHECK: %[[IT2:.*]] = omp.iterator(%{{.*}}: index) = ({{.*}} to {{.*}} step {{.*}}) {
+! CHECK: %[[IT2:.*]] = omp.iterator(%{{.*}}: i32) = ({{.*}} to {{.*}} step {{.*}}) {
! CHECK: %[[COOR2:.*]] = hlfir.designate %[[B]]#0 (%{{.*}})
! CHECK: omp.yield(%{{.*}} : !llvm.ptr)
! CHECK: } -> !omp.iterated<!llvm.ptr>
diff --git a/flang/test/Lower/OpenMP/iterator-empty-range.f90 b/flang/test/Lower/OpenMP/iterator-empty-range.f90
index dcdd8752dea94..874bcb549808f 100644
--- a/flang/test/Lower/OpenMP/iterator-empty-range.f90
+++ b/flang/test/Lower/OpenMP/iterator-empty-range.f90
@@ -11,10 +11,8 @@ subroutine depend_empty_positive(a, m, d)
end
! CHECK-LABEL: define {{.*}} @depend_empty_positive_(
! CHECK: [[M:%.*]] = load i32, ptr
-! CHECK: [[WIDE:%.*]] = sext i32 [[M]] to i64
! CHECK: [[EMPTY:%.*]] = icmp slt i32 [[M]], 3
-! CHECK: [[NONEMPTY:%.*]] = add nsw i64 [[WIDE]], -2
-! CHECK: [[COUNT:%.*]] = select i1 [[EMPTY]], i64 0, i64 [[NONEMPTY]]
+! CHECK: [[COUNT:%.*]] = select i1 [[EMPTY]], i64 0, i64 %{{.*}}
! CHECK: [[SIZE:%.*]] = mul {{.*}}i64 [[COUNT]], 24
! CHECK: [[LIST:%.*]] = {{.*}}call ptr @malloc(i64 [[SIZE]])
! CHECK: [[ZERO:%.*]] = icmp eq i64 [[COUNT]], 0
@@ -34,10 +32,8 @@ subroutine affinity_empty_positive(a, m, d)
end
! CHECK-LABEL: define {{.*}} @affinity_empty_positive_(
! CHECK: [[M:%.*]] = load i32, ptr
-! CHECK: [[WIDE:%.*]] = sext i32 [[M]] to i64
! CHECK: [[EMPTY:%.*]] = icmp slt i32 [[M]], 3
-! CHECK: [[NONEMPTY:%.*]] = add nsw i64 [[WIDE]], -2
-! CHECK: [[COUNT:%.*]] = select i1 [[EMPTY]], i64 0, i64 [[NONEMPTY]]
+! CHECK: [[COUNT:%.*]] = select i1 [[EMPTY]], i64 0, i64 %{{.*}}
! CHECK: [[LIST:%.*]] = alloca { i64, i64, i32 }, i64 [[COUNT]]
! CHECK: [[ZERO:%.*]] = icmp eq i64 [[COUNT]], 0
! CHECK-NEXT: br i1 [[ZERO]], label %[[CONT:[^,]+]], label %[[BODY:.*]]
@@ -56,17 +52,16 @@ subroutine depend_empty_negative(a, m, d)
end
! CHECK-LABEL: define {{.*}} @depend_empty_negative_(
! CHECK: [[M:%.*]] = load i32, ptr
-! CHECK: [[WIDE:%.*]] = sext i32 [[M]] to i65
-! CHECK: [[SPAN:%.*]] = sub nsw i65 3, [[WIDE]]
+! CHECK: [[WIDE:%.*]] = sext i32 [[M]] to i33
+! CHECK: [[SPAN:%.*]] = sub nsw i33 3, [[WIDE]]
! CHECK: [[EMPTY:%.*]] = icmp sgt i32 [[M]], 3
-! CHECK: [[HALF:%.*]] = lshr i65 [[SPAN]], 1
-! CHECK: [[HALF64:%.*]] = trunc {{.*}}i65 [[HALF]] to i64
-! CHECK: [[NONEMPTY:%.*]] = add i64 [[HALF64]], 1
+! CHECK: [[HALF:%.*]] = lshr i33 [[SPAN]], 1
+! CHECK: [[NONEMPTY33:%.*]] = add {{.*}}i33 [[HALF]], 1
+! CHECK: [[NONEMPTY:%.*]] = zext i33 [[NONEMPTY33]] to i64
! CHECK: [[COUNT:%.*]] = select i1 [[EMPTY]], i64 0, i64 [[NONEMPTY]]
! CHECK: [[SIZE:%.*]] = mul {{.*}}i64 [[COUNT]], 24
! CHECK: [[LIST:%.*]] = {{.*}}call ptr @malloc(i64 [[SIZE]])
-! CHECK: [[ZERO:%.*]] = icmp eq i64 [[COUNT]], 0
-! CHECK-NEXT: br i1 [[ZERO]], label %[[CONT:[^,]+]], label %[[BODY:.*]]
+! CHECK-NEXT: br i1 [[EMPTY]], label %[[CONT:[^,]+]], label %[[BODY:.*]]
! CHECK: [[BODY]]:
! CHECK: sdiv i32
! CHECK: [[CONT]]:
@@ -82,16 +77,15 @@ subroutine affinity_empty_negative(a, m, d)
end
! CHECK-LABEL: define {{.*}} @affinity_empty_negative_(
! CHECK: [[M:%.*]] = load i32, ptr
-! CHECK: [[WIDE:%.*]] = sext i32 [[M]] to i65
-! CHECK: [[SPAN:%.*]] = sub nsw i65 3, [[WIDE]]
+! CHECK: [[WIDE:%.*]] = sext i32 [[M]] to i33
+! CHECK: [[SPAN:%.*]] = sub nsw i33 3, [[WIDE]]
! CHECK: [[EMPTY:%.*]] = icmp sgt i32 [[M]], 3
-! CHECK: [[HALF:%.*]] = lshr i65 [[SPAN]], 1
-! CHECK: [[HALF64:%.*]] = trunc {{.*}}i65 [[HALF]] to i64
-! CHECK: [[NONEMPTY:%.*]] = add i64 [[HALF64]], 1
+! CHECK: [[HALF:%.*]] = lshr i33 [[SPAN]], 1
+! CHECK: [[NONEMPTY33:%.*]] = add {{.*}}i33 [[HALF]], 1
+! CHECK: [[NONEMPTY:%.*]] = zext i33 [[NONEMPTY33]] to i64
! CHECK: [[COUNT:%.*]] = select i1 [[EMPTY]], i64 0, i64 [[NONEMPTY]]
! CHECK: [[LIST:%.*]] = alloca { i64, i64, i32 }, i64 [[COUNT]]
-! CHECK: [[ZERO:%.*]] = icmp eq i64 [[COUNT]], 0
-! CHECK-NEXT: br i1 [[ZERO]], label %[[CONT:[^,]+]], label %[[BODY:.*]]
+! CHECK: br i1 [[EMPTY]], label %[[CONT:[^,]+]], label %[[BODY:.*]]
! CHECK: [[BODY]]:
! CHECK: sdiv i32
! CHECK: [[CONT]]:
@@ -109,10 +103,8 @@ subroutine depend_empty_product(a, m, n, d)
! CHECK-LABEL: define {{.*}} @depend_empty_product_(
! CHECK: [[M:%.*]] = load i32, ptr
! CHECK: [[N:%.*]] = load i32, ptr
-! CHECK: [[WIDE:%.*]] = sext i32 [[M]] to i64
! CHECK: [[EMPTY:%.*]] = icmp slt i32 [[M]], 3
-! CHECK: [[NONEMPTY:%.*]] = add nsw i64 [[WIDE]], -2
-! CHECK: [[COUNT:%.*]] = select i1 [[EMPTY]], i64 0, i64 [[NONEMPTY]]
+! CHECK: [[COUNT:%.*]] = select i1 [[EMPTY]], i64 0, i64 %{{.*}}
! CHECK: [[NCOUNT:%.*]] = {{.*}}call i32 @llvm.smax.i32(i32 [[N]], i32 0)
! CHECK: [[N64:%.*]] = zext {{.*}}i32 [[NCOUNT]] to i64
! CHECK: [[TOTAL:%.*]] = mul {{.*}}i64 [[COUNT]], [[N64]]
@@ -136,10 +128,8 @@ subroutine affinity_empty_product(a, m, n, d)
! CHECK-LABEL: define {{.*}} @affinity_empty_product_(
! CHECK: [[M:%.*]] = load i32, ptr
! CHECK: [[N:%.*]] = load i32, ptr
-! CHECK: [[WIDE:%.*]] = sext i32 [[M]] to i64
! CHECK: [[EMPTY:%.*]] = icmp slt i32 [[M]], 3
-! CHECK: [[NONEMPTY:%.*]] = add nsw i64 [[WIDE]], -2
-! CHECK: [[COUNT:%.*]] = select i1 [[EMPTY]], i64 0, i64 [[NONEMPTY]]
+! CHECK: [[COUNT:%.*]] = select i1 [[EMPTY]], i64 0, i64 %{{.*}}
! CHECK: [[NCOUNT:%.*]] = {{.*}}call i32 @llvm.smax.i32(i32 [[N]], i32 0)
! CHECK: [[N64:%.*]] = zext {{.*}}i32 [[NCOUNT]] to i64
! CHECK: [[TOTAL:%.*]] = mul {{.*}}i64 [[COUNT]], [[N64]]
@@ -280,3 +270,45 @@ subroutine depend_retained_empty(a, m, n)
! CHECK: %[[COUNT:.*]] = trunc i64 %[[TRIPS]] to i32
! CHECK: call i32 @__kmpc_omp_task_with_deps(
! CHECK-SAME: ptr {{[^,]+}}, i32 {{[^,]+}}, ptr {{[^,]+}}, i32 %[[COUNT]],
+
+! Ranges keep the iterator's kind; narrowing these bounds would empty the range.
+subroutine depend_wide_kind(a)
+ integer :: a(3)
+ integer(16) :: lb, ub
+ lb = 9223372036854775807_16
+ ub = 9223372036854775809_16
+ !$omp task depend(iterator(integer(16) :: i = lb:ub), in: a(i-lb+1))
+ !$omp end task
+end subroutine
+
+! CHECK-LABEL: define {{.*}} @depend_wide_kind_(
+! CHECK: %[[IV:.*]] = phi i64 [ 0, %entry ]
+! CHECK: getelementptr {{.*}}[4 x i8], ptr %{{[0-9]+}}, i64 %[[IV]]
+! CHECK: icmp eq i64 %{{.*}}, 3
+! CHECK: call i32 @__kmpc_omp_task_with_deps(
+! CHECK-SAME: ptr {{[^,]+}}, i32 {{[^,]+}}, ptr {{[^,]+}}, i32 3,
+
+! The step is wider than the iterator's kind; narrowing it would empty {-128}.
+subroutine depend_wide_step(a)
+ integer :: a(-200:200)
+ !$omp task depend(iterator(integer(1) :: i = -128:-1:200), in: a(i))
+ !$omp end task
+end subroutine
+
+! CHECK-LABEL: define {{.*}} @depend_wide_step_(
+! CHECK: getelementptr {{.*}} ptr %{{[0-9]+}}, i64 288
+! CHECK: call i32 @__kmpc_omp_task_with_deps(
+! CHECK-SAME: ptr {{[^,]+}}, i32 {{[^,]+}}, ptr {{[^,]+}}, i32 1,
+
+subroutine affinity_wide_kind(a)
+ integer :: a(3)
+ integer(16) :: lb, ub
+ lb = 9223372036854775807_16
+ ub = 9223372036854775809_16
+ !$omp task affinity(iterator(integer(16) :: i = lb:ub): a(i-lb+1))
+ !$omp end task
+end subroutine
+
+! CHECK-LABEL: define {{.*}} @affinity_wide_kind_(
+! CHECK: call i32 @__kmpc_omp_reg_task_with_affinity(
+! CHECK-SAME: ptr {{[^,]+}}, i32 {{[^,]+}}, ptr {{[^,]+}}, i32 3,
diff --git a/flang/test/Lower/OpenMP/iterator-source-occurrences.f90 b/flang/test/Lower/OpenMP/iterator-source-occurrences.f90
index 4c89d5c827538..4a8832385ca91 100644
--- a/flang/test/Lower/OpenMP/iterator-source-occurrences.f90
+++ b/flang/test/Lower/OpenMP/iterator-source-occurrences.f90
@@ -17,31 +17,26 @@ subroutine depend_folded(a, m, d, i)
! CHECK: %[[A:.*]]:2 = hlfir.declare
! CHECK-SAME: uniq_name("_QFdepend_foldedEa")
! CHECK: %[[M:.*]]:2 = hlfir.declare {{.*}}uniq_name("{{.*}}Em")
-! CHECK: %[[ONE:.*]] = arith.constant 1 : i32
-! CHECK: %[[MVAL:.*]] = fir.load %[[M]]#0
-! CHECK: %[[ILB:.*]] = fir.convert %[[ONE]] : (i32) -> index
-! CHECK: %[[IUB:.*]] = fir.convert %[[MVAL]] : (i32) -> index
-! CHECK: %[[ISTEP:.*]] = arith.constant 1 : index
-! CHECK: %[[JONE:.*]] = arith.constant 1 : i32
-! CHECK: %[[TWO:.*]] = arith.constant 2 : i32
-! CHECK: %[[JLB:.*]] = fir.convert %[[JONE]] : (i32) -> index
-! CHECK: %[[JUB:.*]] = fir.convert %[[TWO]] : (i32) -> index
-! CHECK: %[[JSTEP:.*]] = arith.constant 1 : index
-! CHECK: %[[IT_IJ:.*]] = omp.iterator(%{{.*}}: index, %{{.*}}: index) =
+! CHECK: %[[ILB:.*]] = arith.constant 1 : i32
+! CHECK: %[[IUB:.*]] = fir.load %[[M]]#0
+! CHECK: %[[ISTEP:.*]] = arith.constant 1 : i32
+! CHECK: %[[JLB:.*]] = arith.constant 1 : i32
+! CHECK: %[[JUB:.*]] = arith.constant 2 : i32
+! CHECK: %[[JSTEP:.*]] = arith.constant 1 : i32
+! CHECK: %[[IT_IJ:.*]] = omp.iterator(%{{.*}}: i32, %{{.*}}: i32) =
! CHECK-SAME: (%[[ILB]] to %[[IUB]] step %[[ISTEP]],
! CHECK-SAME: %[[JLB]] to %[[JUB]] step %[[JSTEP]])
! CHECK: arith.divsi
! CHECK: omp.yield
-! CHECK: %[[IT_I:.*]] = omp.iterator(%[[I:.*]]: index) =
+! CHECK: %[[IT_I:.*]] = omp.iterator(%[[I:.*]]: i32) =
! CHECK-SAME: (%[[ILB]] to %[[IUB]] step %[[ISTEP]])
! CHECK: %[[FIRST:.*]] = arith.constant 1 : index
! CHECK: %[[FIXED:.*]] = hlfir.designate %[[A]]#0 (%[[FIRST]])
! CHECK: %[[FIXED_PTR:.*]] = fir.convert %[[FIXED]]
! CHECK: omp.yield(%[[FIXED_PTR]] : !llvm.ptr)
-! CHECK: %[[IT_J:.*]] = omp.iterator(%[[J:.*]]: index) =
+! CHECK: %[[IT_J:.*]] = omp.iterator(%[[J:.*]]: i32) =
! CHECK-SAME: (%[[JLB]] to %[[JUB]] step %[[JSTEP]])
-! CHECK: %[[JVAL:.*]] = fir.convert %[[J]] : (index) -> i32
-! CHECK: fir.store %[[JVAL]] to %[[JMEM:.*]] : !fir.ref<i32>
+! CHECK: fir.store %[[J]] to %[[JMEM:.*]] : !fir.ref<i32>
! CHECK: %[[JDECL:.*]]:2 = hlfir.declare %[[JMEM]]
! CHECK: %[[JLOAD:.*]] = fir.load %[[JDECL]]#0
! CHECK: %[[JIDX:.*]] = fir.convert %[[JLOAD]] : (i32) -> i64
@@ -64,7 +59,7 @@ subroutine depend_shadowed(a, b, m, i)
end subroutine
! CHECK-LABEL: func.func @_QPdepend_shadowed(
-! CHECK: omp.iterator(%{{[^,:]+}}: index) =
+! CHECK: omp.iterator(%{{[^,:]+}}: i32) =
! CHECK: omp.yield
! CHECK-NOT: omp.iterator
! CHECK: omp.task
@@ -81,32 +76,27 @@ subroutine affinity_folded(a, m, d, i)
! CHECK: %[[A:.*]]:2 = hlfir.declare
! CHECK-SAME: uniq_name("_QFaffinity_foldedEa")
! CHECK: %[[M:.*]]:2 = hlfir.declare {{.*}}uniq_name("{{.*}}Em")
-! CHECK: %[[ONE:.*]] = arith.constant 1 : i32
-! CHECK: %[[MVAL:.*]] = fir.load %[[M]]#0
-! CHECK: %[[ILB:.*]] = fir.convert %[[ONE]] : (i32) -> index
-! CHECK: %[[IUB:.*]] = fir.convert %[[MVAL]] : (i32) -> index
-! CHECK: %[[ISTEP:.*]] = arith.constant 1 : index
-! CHECK: %[[JONE:.*]] = arith.constant 1 : i32
-! CHECK: %[[TWO:.*]] = arith.constant 2 : i32
-! CHECK: %[[JLB:.*]] = fir.convert %[[JONE]] : (i32) -> index
-! CHECK: %[[JUB:.*]] = fir.convert %[[TWO]] : (i32) -> index
-! CHECK: %[[JSTEP:.*]] = arith.constant 1 : index
-! CHECK: %[[IT_IJ:.*]] = omp.iterator(%{{.*}}: index, %{{.*}}: index) =
+! CHECK: %[[ILB:.*]] = arith.constant 1 : i32
+! CHECK: %[[IUB:.*]] = fir.load %[[M]]#0
+! CHECK: %[[ISTEP:.*]] = arith.constant 1 : i32
+! CHECK: %[[JLB:.*]] = arith.constant 1 : i32
+! CHECK: %[[JUB:.*]] = arith.constant 2 : i32
+! CHECK: %[[JSTEP:.*]] = arith.constant 1 : i32
+! CHECK: %[[IT_IJ:.*]] = omp.iterator(%{{.*}}: i32, %{{.*}}: i32) =
! CHECK-SAME: (%[[ILB]] to %[[IUB]] step %[[ISTEP]],
! CHECK-SAME: %[[JLB]] to %[[JUB]] step %[[JSTEP]])
! CHECK: arith.divsi
! CHECK: omp.yield
-! CHECK: %[[IT_I:.*]] = omp.iterator(%[[I:.*]]: index) =
+! CHECK: %[[IT_I:.*]] = omp.iterator(%[[I:.*]]: i32) =
! CHECK-SAME: (%[[ILB]] to %[[IUB]] step %[[ISTEP]])
! CHECK: %[[FIRST:.*]] = arith.constant 1 : index
! CHECK: %[[FIXED:.*]] = hlfir.designate %[[A]]#0 (%[[FIRST]])
! CHECK: %[[FIXED_PTR:.*]] = fir.convert %[[FIXED]]
! CHECK: %[[FIXED_ENTRY:.*]] = omp.affinity_entry %[[FIXED_PTR]],
! CHECK: omp.yield(%[[FIXED_ENTRY]] :
-! CHECK: %[[IT_J:.*]] = omp.iterator(%[[J:.*]]: index) =
+! CHECK: %[[IT_J:.*]] = omp.iterator(%[[J:.*]]: i32) =
! CHECK-SAME: (%[[JLB]] to %[[JUB]] step %[[JSTEP]])
-! CHECK: %[[JVAL:.*]] = fir.convert %[[J]] : (index) -> i32
-! CHECK: fir.store %[[JVAL]] to %[[JMEM:.*]] : !fir.ref<i32>
+! CHECK: fir.store %[[J]] to %[[JMEM:.*]] : !fir.ref<i32>
! CHECK: %[[JDECL:.*]]:2 = hlfir.declare %[[JMEM]]
! CHECK: %[[JLOAD:.*]] = fir.load %[[JDECL]]#0
! CHECK: %[[JIDX:.*]] = fir.convert %[[JLOAD]] : (i32) -> i64
@@ -132,7 +122,7 @@ subroutine affinity_shadowed(a, b, m, i)
end subroutine
! CHECK-LABEL: func.func @_QPaffinity_shadowed(
-! CHECK: omp.iterator(%{{[^,:]+}}: index) =
+! CHECK: omp.iterator(%{{[^,:]+}}: i32) =
! CHECK: omp.yield
! CHECK-NOT: omp.iterator
! CHECK: omp.task
@@ -150,9 +140,9 @@ subroutine depend_equal_designators(a, m)
!$omp end task
end
! CHECK-LABEL: func.func @_QPdepend_equal_designators(
-! CHECK: omp.iterator(%{{[^:]+}}: index) =
+! CHECK: omp.iterator(%{{[^:]+}}: i32) =
! CHECK: omp.yield
-! CHECK: omp.iterator(%{{[^:]+}}: index, %{{[^:]+}}: index) =
+! CHECK: omp.iterator(%{{[^:]+}}: i32, %{{[^:]+}}: i32) =
! CHECK: omp.yield
! CHECK-NOT: omp.iterator
! CHECK: omp.task depend(
@@ -163,9 +153,9 @@ subroutine affinity_equal_designators(a, m)
!$omp end task
end
! CHECK-LABEL: func.func @_QPaffinity_equal_designators(
-! CHECK: omp.iterator(%{{[^:]+}}: index) =
+! CHECK: omp.iterator(%{{[^:]+}}: i32) =
! CHECK: omp.yield
-! CHECK: omp.iterator(%{{[^:]+}}: index, %{{[^:]+}}: index) =
+! CHECK: omp.iterator(%{{[^:]+}}: i32, %{{[^:]+}}: i32) =
! CHECK: omp.yield
! CHECK-NOT: omp.iterator
! CHECK: omp.task affinity(
@@ -178,9 +168,9 @@ subroutine depend_scoped_references(a, m)
!$omp end task
end
! CHECK-LABEL: func.func @_QPdepend_scoped_references(
-! CHECK: omp.iterator(%{{[^:]+}}: index) =
+! CHECK: omp.iterator(%{{[^:]+}}: i32) =
! CHECK: omp.yield
-! CHECK: omp.iterator(%{{[^:]+}}: index) =
+! CHECK: omp.iterator(%{{[^:]+}}: i32) =
! CHECK: omp.yield
! CHECK: omp.task depend(
@@ -197,15 +187,15 @@ subroutine target_folded_reference(a, m)
!$omp target exit data map(from:a) depend(iterator(i=1:m), in: a(1+0*i))
end
! CHECK-LABEL: func.func @_QPtarget_folded_reference(
-! CHECK: omp.iterator(%{{[^:]+}}: index) =
+! CHECK: omp.iterator(%{{[^:]+}}: i32) =
! CHECK: omp.yield
! CHECK: omp.target
-! CHECK: omp.iterator(%{{[^:]+}}: index) =
+! CHECK: omp.iterator(%{{[^:]+}}: i32) =
! CHECK: omp.yield
! CHECK: omp.target_enter_data
-! CHECK: omp.iterator(%{{[^:]+}}: index) =
+! CHECK: omp.iterator(%{{[^:]+}}: i32) =
! CHECK: omp.yield
! CHECK: omp.target_update
-! CHECK: omp.iterator(%{{[^:]+}}: index) =
+! CHECK: omp.iterator(%{{[^:]+}}: i32) =
! CHECK: omp.yield
! CHECK: omp.target_exit_data
diff --git a/flang/test/Lower/OpenMP/task-affinity.f90 b/flang/test/Lower/OpenMP/task-affinity.f90
index 813fb6f23251f..331570895b37d 100644
--- a/flang/test/Lower/OpenMP/task-affinity.f90
+++ b/flang/test/Lower/OpenMP/task-affinity.f90
@@ -273,15 +273,12 @@ subroutine affinity_unused_iterator(m)
! CHECK-SAME: uniq_name("_QFaffinity_unused_iteratorEa")
! CHECK: %[[M:.*]]:2 = hlfir.declare
! CHECK-SAME: uniq_name("_QFaffinity_unused_iteratorEm")
-! CHECK: %[[I_LB32:.*]] = arith.constant 1 : i32
-! CHECK: %[[I_UB32:.*]] = arith.constant 2 : i32
-! CHECK: %[[I_LB:.*]] = fir.convert %[[I_LB32]] : (i32) -> index
-! CHECK: %[[I_UB:.*]] = fir.convert %[[I_UB32]] : (i32) -> index
-! CHECK: %[[I_STEP:.*]] = arith.constant 1 : index
-! CHECK: %[[IT_I:.*]] = omp.iterator(%[[IV_I:.*]]: index) =
+! CHECK: %[[I_LB:.*]] = arith.constant 1 : i32
+! CHECK: %[[I_UB:.*]] = arith.constant 2 : i32
+! CHECK: %[[I_STEP:.*]] = arith.constant 1 : i32
+! CHECK: %[[IT_I:.*]] = omp.iterator(%[[IV_I:.*]]: i32) =
! CHECK-SAME: (%[[I_LB]] to %[[I_UB]] step %[[I_STEP]]) {
-! CHECK: %[[V32_I:.*]] = fir.convert %[[IV_I]] : (index) -> i32
-! CHECK: fir.store %[[V32_I]] to %[[MEM_I:.*]] : !fir.ref<i32>
+! CHECK: fir.store %[[IV_I]] to %[[MEM_I:.*]] : !fir.ref<i32>
! CHECK: %[[DECL_I:.*]]:2 = hlfir.declare %[[MEM_I]]
! CHECK: %[[LD_I:.*]] = fir.load %[[DECL_I]]#0 : !fir.ref<i32>
! CHECK: %[[IDX_I:.*]] = fir.convert %[[LD_I]] : (i32) -> i64
@@ -315,20 +312,15 @@ subroutine affinity_per_locator(m)
! CHECK-SAME: uniq_name("_QFaffinity_per_locatorEc")
! CHECK: %[[M:.*]]:2 = hlfir.declare
! CHECK-SAME: uniq_name("_QFaffinity_per_locatorEm")
-! CHECK: %[[I_LB32:.*]] = arith.constant 1 : i32
-! CHECK: %[[I_UB32:.*]] = arith.constant 2 : i32
-! CHECK: %[[I_LB:.*]] = fir.convert %[[I_LB32]] : (i32) -> index
-! CHECK: %[[I_UB:.*]] = fir.convert %[[I_UB32]] : (i32) -> index
-! CHECK: %[[I_STEP:.*]] = arith.constant 1 : index
-! CHECK: %[[J_LB32:.*]] = arith.constant 3 : i32
-! CHECK: %[[J_UB32:.*]] = fir.load %[[M]]#0 : !fir.ref<i32>
-! CHECK: %[[J_LB:.*]] = fir.convert %[[J_LB32]] : (i32) -> index
-! CHECK: %[[J_UB:.*]] = fir.convert %[[J_UB32]] : (i32) -> index
-! CHECK: %[[J_STEP:.*]] = arith.constant 1 : index
-! CHECK: %[[IT_I:.*]] = omp.iterator(%[[IV_I:.*]]: index) =
+! CHECK: %[[I_LB:.*]] = arith.constant 1 : i32
+! CHECK: %[[I_UB:.*]] = arith.constant 2 : i32
+! CHECK: %[[I_STEP:.*]] = arith.constant 1 : i32
+! CHECK: %[[J_LB:.*]] = arith.constant 3 : i32
+! CHECK: %[[J_UB:.*]] = fir.load %[[M]]#0 : !fir.ref<i32>
+! CHECK: %[[J_STEP:.*]] = arith.constant 1 : i32
+! CHECK: %[[IT_I:.*]] = omp.iterator(%[[IV_I:.*]]: i32) =
! CHECK-SAME: (%[[I_LB]] to %[[I_UB]] step %[[I_STEP]]) {
-! CHECK: %[[V32_I:.*]] = fir.convert %[[IV_I]] : (index) -> i32
-! CHECK: fir.store %[[V32_I]] to %[[MEM_I:.*]] : !fir.ref<i32>
+! CHECK: fir.store %[[IV_I]] to %[[MEM_I:.*]] : !fir.ref<i32>
! CHECK: %[[DECL_I:.*]]:2 = hlfir.declare %[[MEM_I]]
! CHECK: %[[LD_I:.*]] = fir.load %[[DECL_I]]#0 : !fir.ref<i32>
! CHECK: %[[IDX_I:.*]] = fir.convert %[[LD_I]] : (i32) -> i64
@@ -340,10 +332,9 @@ subroutine affinity_per_locator(m)
! CHECK: omp.yield(%[[ENTRY_I]] :
! CHECK-SAME: !omp.affinity_entry_ty<!fir.ref<i8>, i64>)
! CHECK: } -> !omp.iterated<!omp.affinity_entry_ty<!fir.ref<i8>, i64>>
-! CHECK: %[[IT_J:.*]] = omp.iterator(%[[IV_J:.*]]: index) =
+! CHECK: %[[IT_J:.*]] = omp.iterator(%[[IV_J:.*]]: i32) =
! CHECK-SAME: (%[[J_LB]] to %[[J_UB]] step %[[J_STEP]]) {
-! CHECK: %[[V32_J:.*]] = fir.convert %[[IV_J]] : (index) -> i32
-! CHECK: fir.store %[[V32_J]] to %[[MEM_J:.*]] : !fir.ref<i32>
+! CHECK: fir.store %[[IV_J]] to %[[MEM_J:.*]] : !fir.ref<i32>
! CHECK: %[[DECL_J:.*]]:2 = hlfir.declare %[[MEM_J]]
! CHECK: %[[LD_J:.*]] = fir.load %[[DECL_J]]#0 : !fir.ref<i32>
! CHECK: %[[IDX_J:.*]] = fir.convert %[[LD_J]] : (i32) -> i64
@@ -380,9 +371,8 @@ subroutine task_affinity_iterator_simple()
end subroutine
! CHECK-LABEL: func.func @_QPtask_affinity_iterator_simple()
-! CHECK: %[[ITERATED:.*]] = omp.iterator(%[[IV:.*]]: index) = ({{.*}} to {{.*}} step {{.*}}) {
-! CHECK: %[[IV_I32:.*]] = fir.convert %[[IV]] : (index) -> i32
-! CHECK: fir.store %[[IV_I32]] to %[[IV_MEM:.*]] : !fir.ref<i32>
+! CHECK: %[[ITERATED:.*]] = omp.iterator(%[[IV:.*]]: i32) = ({{.*}} to {{.*}} step {{.*}}) {
+! CHECK: fir.store %[[IV]] to %[[IV_MEM:.*]] : !fir.ref<i32>
! Iterator IV temp must be named in the compiler-generated namespace ("_QQ"
! prefix) so it is not emitted as a bogus user local in DWARF under -g.
! CHECK: %[[IV_DECL:.*]]:2 = hlfir.declare %[[IV_MEM]] uniq_name("_QQ{{.*}}.omp.iter")
@@ -412,9 +402,8 @@ subroutine task_affinity_iterator_nondefault_lb()
end subroutine
! CHECK-LABEL: func.func @_QPtask_affinity_iterator_nondefault_lb()
-! CHECK: %[[ITERATED_NDLB:.*]] = omp.iterator(%[[IV_NDLB:.*]]: index) = ({{.*}} to {{.*}} step {{.*}}) {
-! CHECK: %[[IV_NDLB_I32:.*]] = fir.convert %[[IV_NDLB]] : (index) -> i32
-! CHECK: fir.store %[[IV_NDLB_I32]] to %[[IV_NDLB_MEM:.*]] : !fir.ref<i32>
+! CHECK: %[[ITERATED_NDLB:.*]] = omp.iterator(%[[IV_NDLB:.*]]: i32) = ({{.*}} to {{.*}} step {{.*}}) {
+! CHECK: fir.store %[[IV_NDLB]] to %[[IV_NDLB_MEM:.*]] : !fir.ref<i32>
! CHECK: %[[IV_NDLB_DECL:.*]]:2 = hlfir.declare %[[IV_NDLB_MEM]]
! CHECK: %[[IV_NDLB_LD:.*]] = fir.load %[[IV_NDLB_DECL]]#0 : !fir.ref<i32>
! CHECK: %[[IV_NDLB_I64:.*]] = fir.convert %[[IV_NDLB_LD]] : (i32) -> i64
@@ -443,12 +432,10 @@ subroutine task_affinity_iterator_nondefault_lb_2d()
end subroutine
! CHECK-LABEL: func.func @_QPtask_affinity_iterator_nondefault_lb_2d()
-! CHECK: %[[ITERATED_NDLB2:.*]] = omp.iterator(%[[IV0_NDLB2:.*]]: index, %[[IV1_NDLB2:.*]]: index) = ({{.*}} to {{.*}} step {{.*}}, {{.*}} to {{.*}} step {{.*}}) {
-! CHECK: %[[IV0_NDLB2_I32:.*]] = fir.convert %[[IV0_NDLB2]] : (index) -> i32
-! CHECK: fir.store %[[IV0_NDLB2_I32]] to %[[IV0_NDLB2_MEM:.*]] : !fir.ref<i32>
+! CHECK: %[[ITERATED_NDLB2:.*]] = omp.iterator(%[[IV0_NDLB2:.*]]: i32, %[[IV1_NDLB2:.*]]: i32) = ({{.*}} to {{.*}} step {{.*}}, {{.*}} to {{.*}} step {{.*}}) {
+! CHECK: fir.store %[[IV0_NDLB2]] to %[[IV0_NDLB2_MEM:.*]] : !fir.ref<i32>
! CHECK: %[[IV0_NDLB2_DECL:.*]]:2 = hlfir.declare %[[IV0_NDLB2_MEM]]
-! CHECK: %[[IV1_NDLB2_I32:.*]] = fir.convert %[[IV1_NDLB2]] : (index) -> i32
-! CHECK: fir.store %[[IV1_NDLB2_I32]] to %[[IV1_NDLB2_MEM:.*]] : !fir.ref<i32>
+! CHECK: fir.store %[[IV1_NDLB2]] to %[[IV1_NDLB2_MEM:.*]] : !fir.ref<i32>
! CHECK: %[[IV1_NDLB2_DECL:.*]]:2 = hlfir.declare %[[IV1_NDLB2_MEM]]
! CHECK: %[[IV0_NDLB2_LD:.*]] = fir.load %[[IV0_NDLB2_DECL]]#0 : !fir.ref<i32>
! CHECK: %[[IV0_NDLB2_I64:.*]] = fir.convert %[[IV0_NDLB2_LD]] : (i32) -> i64
@@ -483,12 +470,10 @@ subroutine task_affinity_iterator_multi_dimension()
end subroutine
! CHECK-LABEL: func.func @_QPtask_affinity_iterator_multi_dimension()
-! CHECK: %[[ITER:.*]] = omp.iterator(%[[IV0:.*]]: index, %[[IV1:.*]]: index) = ({{.*}} to {{.*}} step {{.*}}, {{.*}} to {{.*}} step {{.*}}) {
-! CHECK: %[[IV0_I32:.*]] = fir.convert %[[IV0]] : (index) -> i32
-! CHECK: fir.store %[[IV0_I32]] to %[[IV0_MEM:.*]] : !fir.ref<i32>
+! CHECK: %[[ITER:.*]] = omp.iterator(%[[IV0:.*]]: i32, %[[IV1:.*]]: i32) = ({{.*}} to {{.*}} step {{.*}}, {{.*}} to {{.*}} step {{.*}}) {
+! CHECK: fir.store %[[IV0]] to %[[IV0_MEM:.*]] : !fir.ref<i32>
! CHECK: %[[IV0_DECL:.*]]:2 = hlfir.declare %[[IV0_MEM]]
-! CHECK: %[[IV1_I32:.*]] = fir.convert %[[IV1]] : (index) -> i32
-! CHECK: fir.store %[[IV1_I32]] to %[[IV1_MEM:.*]] : !fir.ref<i32>
+! CHECK: fir.store %[[IV1]] to %[[IV1_MEM:.*]] : !fir.ref<i32>
! CHECK: %[[IV1_DECL:.*]]:2 = hlfir.declare %[[IV1_MEM]]
! CHECK: %[[IV0_LD:.*]] = fir.load %[[IV0_DECL]]#0 : !fir.ref<i32>
! CHECK: %[[IV0_I64:.*]] = fir.convert %[[IV0_LD]] : (i32) -> i64
@@ -517,12 +502,10 @@ subroutine task_affinity_iterator_reordered()
end subroutine
! CHECK-LABEL: func.func @_QPtask_affinity_iterator_reordered()
-! CHECK: %[[ITER:.*]] = omp.iterator(%[[IV0:.*]]: index, %[[IV1:.*]]: index) = ({{.*}} to {{.*}} step {{.*}}, {{.*}} to {{.*}} step {{.*}}) {
-! CHECK: %[[RO_IV0_I32:.*]] = fir.convert %[[IV0]] : (index) -> i32
-! CHECK: fir.store %[[RO_IV0_I32]] to %[[RO_IV0_MEM:.*]] : !fir.ref<i32>
+! CHECK: %[[ITER:.*]] = omp.iterator(%[[IV0:.*]]: i32, %[[IV1:.*]]: i32) = ({{.*}} to {{.*}} step {{.*}}, {{.*}} to {{.*}} step {{.*}}) {
+! CHECK: fir.store %[[IV0]] to %[[RO_IV0_MEM:.*]] : !fir.ref<i32>
! CHECK: %[[RO_IV0_DECL:.*]]:2 = hlfir.declare %[[RO_IV0_MEM]]
-! CHECK: %[[RO_IV1_I32:.*]] = fir.convert %[[IV1]] : (index) -> i32
-! CHECK: fir.store %[[RO_IV1_I32]] to %[[RO_IV1_MEM:.*]] : !fir.ref<i32>
+! CHECK: fir.store %[[IV1]] to %[[RO_IV1_MEM:.*]] : !fir.ref<i32>
! CHECK: %[[RO_IV1_DECL:.*]]:2 = hlfir.declare %[[RO_IV1_MEM]]
! CHECK: %[[RO_IV1_LD:.*]] = fir.load %[[RO_IV1_DECL]]#0 : !fir.ref<i32>
! CHECK: %[[RO_IV1_I64:.*]] = fir.convert %[[RO_IV1_LD]] : (i32) -> i64
@@ -546,12 +529,10 @@ subroutine task_affinity_iterator_expr_subscript()
end subroutine
! CHECK-LABEL: func.func @_QPtask_affinity_iterator_expr_subscript()
-! CHECK: %[[ITER2:.*]] = omp.iterator(%[[IVA:.*]]: index, %[[IVB:.*]]: index) = ({{.*}} to {{.*}} step {{.*}}, {{.*}} to {{.*}} step {{.*}}) {
-! CHECK: %[[IVA_I32:.*]] = fir.convert %[[IVA]] : (index) -> i32
-! CHECK: fir.store %[[IVA_I32]] to %[[IVA_MEM:.*]] : !fir.ref<i32>
+! CHECK: %[[ITER2:.*]] = omp.iterator(%[[IVA:.*]]: i32, %[[IVB:.*]]: i32) = ({{.*}} to {{.*}} step {{.*}}, {{.*}} to {{.*}} step {{.*}}) {
+! CHECK: fir.store %[[IVA]] to %[[IVA_MEM:.*]] : !fir.ref<i32>
! CHECK: %[[IVA_DECL:.*]]:2 = hlfir.declare %[[IVA_MEM]]
-! CHECK: %[[IVB_I32:.*]] = fir.convert %[[IVB]] : (index) -> i32
-! CHECK: fir.store %[[IVB_I32]] to %[[IVB_MEM:.*]] : !fir.ref<i32>
+! CHECK: fir.store %[[IVB]] to %[[IVB_MEM:.*]] : !fir.ref<i32>
! CHECK: %[[IVB_DECL:.*]]:2 = hlfir.declare %[[IVB_MEM]]
! CHECK: %[[IVA_LD:.*]] = fir.load %[[IVA_DECL]]#0 : !fir.ref<i32>
! CHECK: %[[C1_I32:.*]] = arith.constant 1 : i32
@@ -577,12 +558,10 @@ subroutine task_affinity_iterator_section_subscript()
end subroutine
! CHECK-LABEL: func.func @_QPtask_affinity_iterator_section_subscript()
-! CHECK: %[[ITER3:.*]] = omp.iterator(%[[IVS0:.*]]: index, %[[IVS1:.*]]: index) = ({{.*}} to {{.*}} step {{.*}}, {{.*}} to {{.*}} step {{.*}}) {
-! CHECK: %[[IVS0_I32:.*]] = fir.convert %[[IVS0]] : (index) -> i32
-! CHECK: fir.store %[[IVS0_I32]] to %[[IVS0_MEM:.*]] : !fir.ref<i32>
+! CHECK: %[[ITER3:.*]] = omp.iterator(%[[IVS0:.*]]: i32, %[[IVS1:.*]]: i32) = ({{.*}} to {{.*}} step {{.*}}, {{.*}} to {{.*}} step {{.*}}) {
+! CHECK: fir.store %[[IVS0]] to %[[IVS0_MEM:.*]] : !fir.ref<i32>
! CHECK: %[[IVS0_DECL:.*]]:2 = hlfir.declare %[[IVS0_MEM]]
-! CHECK: %[[IVS1_I32:.*]] = fir.convert %[[IVS1]] : (index) -> i32
-! CHECK: fir.store %[[IVS1_I32]] to %[[IVS1_MEM:.*]] : !fir.ref<i32>
+! CHECK: fir.store %[[IVS1]] to %[[IVS1_MEM:.*]] : !fir.ref<i32>
! CHECK: %[[IVS1_DECL:.*]]:2 = hlfir.declare %[[IVS1_MEM]]
! CHECK: %[[IVS0_LD:.*]] = fir.load %[[IVS0_DECL]]#0 : !fir.ref<i32>
! CHECK: %[[IVS0_I64:.*]] = fir.convert %[[IVS0_LD]] : (i32) -> i64
@@ -615,9 +594,8 @@ subroutine task_affinity_iterator_section_implicit_lower()
end subroutine
! CHECK-LABEL: func.func @_QPtask_affinity_iterator_section_implicit_lower()
-! CHECK: %[[ITER4:.*]] = omp.iterator(%[[IVT0:.*]]: index, %[[IVT1:.*]]: index) = ({{.*}} to {{.*}} step {{.*}}, {{.*}} to {{.*}} step {{.*}}) {
-! CHECK: %[[IVT1_I32:.*]] = fir.convert %[[IVT1]] : (index) -> i32
-! CHECK: fir.store %[[IVT1_I32]] to %[[IVT1_MEM:.*]] : !fir.ref<i32>
+! CHECK: %[[ITER4:.*]] = omp.iterator(%[[IVT0:.*]]: i32, %[[IVT1:.*]]: i32) = ({{.*}} to {{.*}} step {{.*}}, {{.*}} to {{.*}} step {{.*}}) {
+! CHECK: fir.store %[[IVT1]] to %[[IVT1_MEM:.*]] : !fir.ref<i32>
! CHECK: %[[IVT1_DECL:.*]]:2 = hlfir.declare %[[IVT1_MEM]]
! CHECK: %[[C1_IDX:.*]] = arith.constant 1 : index
! CHECK: %[[IVT1_LD:.*]] = fir.load %[[IVT1_DECL]]#0 : !fir.ref<i32>
@@ -643,9 +621,8 @@ subroutine task_affinity_iterator_char_simple()
end subroutine
! CHECK-LABEL: func.func @_QPtask_affinity_iterator_char_simple()
-! CHECK: %[[ITER5:.*]] = omp.iterator(%[[IVC:.*]]: index) = ({{.*}} to {{.*}} step {{.*}}) {
-! CHECK: %[[IVC_I32:.*]] = fir.convert %[[IVC]] : (index) -> i32
-! CHECK: fir.store %[[IVC_I32]] to %[[IVC_MEM:.*]] : !fir.ref<i32>
+! CHECK: %[[ITER5:.*]] = omp.iterator(%[[IVC:.*]]: i32) = ({{.*}} to {{.*}} step {{.*}}) {
+! CHECK: fir.store %[[IVC]] to %[[IVC_MEM:.*]] : !fir.ref<i32>
! CHECK: %[[IVC_DECL:.*]]:2 = hlfir.declare %[[IVC_MEM]]
! CHECK: %[[IVC_LD:.*]] = fir.load %[[IVC_DECL]]#0 : !fir.ref<i32>
! CHECK: %[[IVC_I64:.*]] = fir.convert %[[IVC_LD]] : (i32) -> i64
@@ -671,9 +648,8 @@ subroutine task_affinity_iterator_char_expr_subscript()
end subroutine
! CHECK-LABEL: func.func @_QPtask_affinity_iterator_char_expr_subscript()
-! CHECK: %[[ITER6:.*]] = omp.iterator(%[[IVC2:.*]]: index) = ({{.*}} to {{.*}} step {{.*}}) {
-! CHECK: %[[IVC2_I32:.*]] = fir.convert %[[IVC2]] : (index) -> i32
-! CHECK: fir.store %[[IVC2_I32]] to %[[IVC2_MEM:.*]] : !fir.ref<i32>
+! CHECK: %[[ITER6:.*]] = omp.iterator(%[[IVC2:.*]]: i32) = ({{.*}} to {{.*}} step {{.*}}) {
+! CHECK: fir.store %[[IVC2]] to %[[IVC2_MEM:.*]] : !fir.ref<i32>
! CHECK: %[[IVC2_DECL:.*]]:2 = hlfir.declare %[[IVC2_MEM]]
! CHECK: %[[IVC2_LD:.*]] = fir.load %[[IVC2_DECL]]#0 : !fir.ref<i32>
! CHECK: %[[C1_I32_6:.*]] = arith.constant 1 : i32
@@ -703,7 +679,7 @@ subroutine task_affinity_iterator_char_runtime(n, l)
! CHECK-LABEL: func.func @_QPtask_affinity_iterator_char_runtime(
! CHECK: %[[A:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) typeparams %{{.*}} uniq_name("_QFtask_affinity_iterator_char_runtimeEa")
-! CHECK: %[[ITER:.*]] = omp.iterator(%[[IV:.*]]: index) = ({{.*}} to {{.*}} step {{.*}}) {
+! CHECK: %[[ITER:.*]] = omp.iterator(%[[IV:.*]]: i32) = ({{.*}} to {{.*}} step {{.*}}) {
! CHECK: %[[COOR:.*]] = hlfir.designate %[[A]]#0 ({{.*}})
! CHECK: %[[RAW:.*]]:2 = fir.unboxchar %[[COOR]]
! CHECK: %[[ELEM:.*]] = fir.box_elesize %[[A]]#0 : (!fir.box<!fir.array<?x!fir.char<1,?>>>) -> index
diff --git a/flang/test/Semantics/OpenMP/depend08.f90 b/flang/test/Semantics/OpenMP/depend08.f90
new file mode 100644
index 0000000000000..ca445b6c245f2
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/depend08.f90
@@ -0,0 +1,17 @@
+! RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=52
+
+subroutine depend_iterator_noninteger_iv(x)
+ integer :: x(10)
+ !ERROR: The iterator variable must be of integer type
+ !$omp task depend(iterator(real :: r = 1:3), in: x(int(r)))
+ !$omp end task
+end subroutine
+
+! The range is nonempty; truncating the bounds to 64 bits would reverse them.
+subroutine depend_iterator_wide_constants(x)
+ integer :: x(3)
+ !$omp task depend(iterator(integer(16) :: i = &
+ !$omp& 9223372036854775807_16:9223372036854775809_16), &
+ !$omp& in: x(i - 9223372036854775806_16))
+ !$omp end task
+end subroutine
>From 80c528660ee392b181b3b8e8e6b5baba8fb15840 Mon Sep 17 00:00:00 2001
From: "Chi Chun, Chen" <chichun.chen at hpe.com>
Date: Wed, 7 Oct 2026 16:21:56 -0500
Subject: [PATCH 5/8] Build iterator ranges in their widest type and reject
vector-subscript affinity
OpenMP 5.2 does not convert begin and end to the iterator type for Fortran,
but lowering did, which could change which values a range contains. For
example, integer(1) :: i = 0:n:-1 with n = 256 wrapped to 0:0:-1, and
0:150:100 became the empty 0:-106:100. Build each range in the widest of the
iterator, begin, end and step types instead, and narrow only the induction
value.
Lowering iterator affinity locators through the ordinary path let vector
subscripts through: the bounds helper only reports a non-fatal error, so the
affinity record pointed at a freed temporary. Report vector subscripts in
AFFINITY as not yet implemented, with or without an iterator.
Also anchor the expected dependence counts in the empty-range tests so they
cannot match the trailing noalias count.
---
flang/lib/Lower/OpenMP/ClauseProcessor.cpp | 28 +++++-----
.../OpenMP/Todo/affinity-vector-subscript.f90 | 27 ++++++++++
.../Lower/OpenMP/iterator-empty-range.f90 | 52 ++++++++++++++++++-
flang/test/Lower/OpenMP/iterator-locators.f90 | 9 ++--
4 files changed, 96 insertions(+), 20 deletions(-)
create mode 100644 flang/test/Lower/OpenMP/Todo/affinity-vector-subscript.f90
diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
index 72f6e7e59def7..6940ce0b10b5f 100644
--- a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
+++ b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
@@ -256,22 +256,20 @@ static IteratorRange lowerIteratorRange(
mlir::Value ubVal =
fir::getBase(converter.genExprValue(toEvExpr(ubExpr), stmtCtx));
- // Begin and end take the iterator's type, but the step keeps its own. Count
- // in the wider of the two so that neither is narrowed.
+ // Fortran does not convert begin and end to the iterator's type (OpenMP 5.2
+ // section 3.2.6), so build the range in the widest operand type.
mlir::Type ivTy = converter.genType(*r.ivSym);
mlir::Value stVal =
stExpr ? fir::getBase(converter.genExprValue(toEvExpr(*stExpr), stmtCtx))
: builder.createIntegerConstant(loc, ivTy, 1);
- mlir::Type rangeTy = ivTy;
- if (auto stTy = mlir::dyn_cast<mlir::IntegerType>(stVal.getType()))
- if (stTy.isSignless() &&
- stTy.getWidth() > mlir::cast<mlir::IntegerType>(ivTy).getWidth())
- rangeTy = stTy;
-
- r.lb = builder.createConvert(loc, rangeTy,
- builder.createConvert(loc, ivTy, lbVal));
- r.ub = builder.createConvert(loc, rangeTy,
- builder.createConvert(loc, ivTy, ubVal));
+ unsigned width = mlir::cast<mlir::IntegerType>(ivTy).getWidth();
+ for (mlir::Value v : {lbVal, ubVal, stVal})
+ width =
+ std::max(width, mlir::cast<mlir::IntegerType>(v.getType()).getWidth());
+ mlir::Type rangeTy = builder.getIntegerType(width);
+
+ r.lb = builder.createConvert(loc, rangeTy, lbVal);
+ r.ub = builder.createConvert(loc, rangeTy, ubVal);
r.step = builder.createConvert(loc, rangeTy, stVal);
return r;
@@ -1020,6 +1018,9 @@ static llvm::StringMap<bool> getTargetFeatures(mlir::ModuleOp module) {
return featuresMap;
}
+template <typename T>
+static bool isVectorSubscript(const evaluate::Expr<T> &expr);
+
bool ClauseProcessor::processAffinity(
mlir::omp::AffinityClauseOps &result) const {
return findRepeatableClause<omp::clause::Affinity>(
@@ -1047,6 +1048,9 @@ bool ClauseProcessor::processAffinity(
auto iteratorRanges = lowerIteratorRanges(clause, converter, stmtCtx);
TodoLocators(clauseLocation, objects);
+ for (const omp::Object &object : objects)
+ if (object.ref() && isVectorSubscript(*object.ref()))
+ TODO(clauseLocation, "vector subscript in AFFINITY clause");
auto genEntry = [&](const omp::Object &object,
lower::StatementContext &localStmtCtx) {
diff --git a/flang/test/Lower/OpenMP/Todo/affinity-vector-subscript.f90 b/flang/test/Lower/OpenMP/Todo/affinity-vector-subscript.f90
new file mode 100644
index 0000000000000..8ea7849c5e502
--- /dev/null
+++ b/flang/test/Lower/OpenMP/Todo/affinity-vector-subscript.f90
@@ -0,0 +1,27 @@
+! RUN: split-file %s %t
+! RUN: %not_todo_cmd %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=52 -o - %t/iterator.f90 2>&1 | FileCheck %s
+! RUN: %not_todo_cmd %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=52 -o - %t/iterator-2d.f90 2>&1 | FileCheck %s
+! RUN: %not_todo_cmd %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=52 -o - %t/no-iterator.f90 2>&1 | FileCheck %s
+
+! CHECK: not yet implemented: vector subscript in AFFINITY clause
+
+!--- iterator.f90
+subroutine s(a, m)
+ integer :: a(8), m
+ !$omp task affinity(iterator(i = 1:m): a([i]))
+ !$omp end task
+end
+
+!--- iterator-2d.f90
+subroutine s(a, m)
+ integer :: a(2, 8), m
+ !$omp task affinity(iterator(i = 1:m): a(1:2, [i]))
+ !$omp end task
+end
+
+!--- no-iterator.f90
+subroutine s(a)
+ integer :: a(8)
+ !$omp task affinity(a([1]))
+ !$omp end task
+end
diff --git a/flang/test/Lower/OpenMP/iterator-empty-range.f90 b/flang/test/Lower/OpenMP/iterator-empty-range.f90
index 874bcb549808f..86bf278f4dac1 100644
--- a/flang/test/Lower/OpenMP/iterator-empty-range.f90
+++ b/flang/test/Lower/OpenMP/iterator-empty-range.f90
@@ -209,8 +209,7 @@ subroutine depend_folded_zero(a, d)
! CHECK-LABEL: define {{.*}} @depend_folded_zero_(
! CHECK-NOT: sdiv
-! CHECK: call i32 @__kmpc_omp_task_with_deps(
-! CHECK-SAME: ptr {{[^,]+}}, i32 {{[^,]+}}, ptr {{[^,]+}}, i32 0,
+! CHECK: call i32 @__kmpc_omp_task_with_deps(ptr {{[^,]+}}, i32 {{[^,]+}}, ptr {{[^,]+}}, i32 0,
! CHECK-NOT: sdiv
! CHECK: ret void
@@ -300,6 +299,55 @@ subroutine depend_wide_step(a)
! CHECK: call i32 @__kmpc_omp_task_with_deps(
! CHECK-SAME: ptr {{[^,]+}}, i32 {{[^,]+}}, ptr {{[^,]+}}, i32 1,
+! Begin and end are not converted to the iterator's kind, so n = 256 leaves
+! this range empty instead of wrapping to 0:0:-1.
+subroutine depend_wide_end(a, n)
+ integer :: a(8), n
+ !$omp task depend(iterator(integer(1) :: i = 0:n:-1), in: a(1+8/i))
+ !$omp end task
+end subroutine
+
+! CHECK-LABEL: define {{.*}} @depend_wide_end_(
+! CHECK: %[[N:.*]] = load i32, ptr
+! CHECK: %[[EMPTY:.*]] = icmp sgt i32 %[[N]], 0
+! CHECK: %[[COUNT:.*]] = select i1 %[[EMPTY]], i64 0, i64 %{{.*}}
+! CHECK: %[[ZERO:.*]] = icmp eq i64 %[[COUNT]], 0
+! CHECK: br i1 %[[ZERO]], label %[[CONT:[^,]+]], label %[[BODY:.*]]
+! CHECK: [[BODY]]:
+! CHECK: sdiv i32 8,
+! CHECK: [[CONT]]:
+! CHECK: %[[RUNTIME_COUNT:.*]] = trunc i64 %[[COUNT]] to i32
+! CHECK: call i32 @__kmpc_omp_task_with_deps(ptr {{[^,]+}}, i32 {{[^,]+}}, ptr {{[^,]+}}, i32 %[[RUNTIME_COUNT]],
+
+subroutine depend_wide_end_const(a)
+ integer :: a(8)
+ !$omp task depend(iterator(integer(1) :: i = 0:256:-1), in: a(1+8/i))
+ !$omp end task
+end subroutine
+
+! CHECK-LABEL: define {{.*}} @depend_wide_end_const_(
+! CHECK-NOT: sdiv
+! CHECK: call i32 @__kmpc_omp_task_with_deps(ptr {{[^,]+}}, i32 {{[^,]+}}, ptr {{[^,]+}}, i32 0,
+
+subroutine depend_wide_begin_const(a)
+ integer :: a(8)
+ !$omp task depend(iterator(integer(1) :: i = 200:100), in: a(i))
+ !$omp end task
+end subroutine
+
+! CHECK-LABEL: define {{.*}} @depend_wide_begin_const_(
+! CHECK: call i32 @__kmpc_omp_task_with_deps(ptr {{[^,]+}}, i32 {{[^,]+}}, ptr {{[^,]+}}, i32 0,
+
+! Narrowing 150 to integer(1) would empty this range; its values are {0, 100}.
+subroutine depend_wide_end_nonempty(a)
+ integer :: a(0:100)
+ !$omp task depend(iterator(integer(1) :: i = 0:150:100), in: a(i))
+ !$omp end task
+end subroutine
+
+! CHECK-LABEL: define {{.*}} @depend_wide_end_nonempty_(
+! CHECK: call i32 @__kmpc_omp_task_with_deps(ptr {{[^,]+}}, i32 {{[^,]+}}, ptr {{[^,]+}}, i32 2,
+
subroutine affinity_wide_kind(a)
integer :: a(3)
integer(16) :: lb, ub
diff --git a/flang/test/Lower/OpenMP/iterator-locators.f90 b/flang/test/Lower/OpenMP/iterator-locators.f90
index 2ed1ce918eec1..86539a0d05831 100644
--- a/flang/test/Lower/OpenMP/iterator-locators.f90
+++ b/flang/test/Lower/OpenMP/iterator-locators.f90
@@ -175,8 +175,7 @@ subroutine depend_component_empty(a, m, d)
end
! LLVM-LABEL: define {{.*}} @depend_component_empty_(
! LLVM-NOT: sdiv
-! LLVM: call i32 @__kmpc_omp_task_with_deps(
-! LLVM-SAME: i32 0, ptr
+! LLVM: call i32 @__kmpc_omp_task_with_deps(ptr {{[^,]+}}, i32 {{[^,]+}}, ptr {{[^,]+}}, i32 0,
! LLVM-NOT: sdiv
! LLVM: ret void
@@ -189,8 +188,7 @@ subroutine depend_vector_empty(a, m, d)
end
! LLVM-LABEL: define {{.*}} @depend_vector_empty_(
! LLVM-NOT: sdiv
-! LLVM: call i32 @__kmpc_omp_task_with_deps(
-! LLVM-SAME: i32 0, ptr
+! LLVM: call i32 @__kmpc_omp_task_with_deps(ptr {{[^,]+}}, i32 {{[^,]+}}, ptr {{[^,]+}}, i32 0,
! LLVM-NOT: sdiv
! LLVM: ret void
@@ -206,8 +204,7 @@ subroutine depend_section_empty(x, m, d)
end
! LLVM-LABEL: define {{.*}} @depend_section_empty_(
! LLVM-NOT: sdiv
-! LLVM: call i32 @__kmpc_omp_task_with_deps(
-! LLVM-SAME: i32 0, ptr
+! LLVM: call i32 @__kmpc_omp_task_with_deps(ptr {{[^,]+}}, i32 {{[^,]+}}, ptr {{[^,]+}}, i32 0,
! LLVM-NOT: sdiv
! LLVM: ret void
>From 18b3943d7ae65dddb7e6ef2e5401de38ab7e9862 Mon Sep 17 00:00:00 2001
From: "Chi Chun, Chen" <chichun.chen at hpe.com>
Date: Thu, 8 Oct 2026 23:50:52 -0500
Subject: [PATCH 6/8] Reject AFFINITY strides and nested vector subscripts
OpenMP allows a stride expression in an array section only where a clause
explicitly permits one, and AFFINITY does not. Semantics accepted positive
strides and lowering only reported a non-fatal error, so compilation
succeeded or crashed on the bounds. Report a stride in the last part
reference of an AFFINITY locator as a semantic error, including an explicit
unit stride. DEPEND and REDUCTION fall under the same rule but currently
accept strides; tightening them is left to a separate change.
The vector-subscript TODO for AFFINITY only checked the last part
reference, so a(v)%field(1) reached an assertion. Check every part
reference instead.
---
flang/lib/Lower/OpenMP/ClauseProcessor.cpp | 5 +--
flang/lib/Semantics/check-omp-structure.cpp | 11 ++++++-
.../OpenMP/Todo/affinity-vector-subscript.f90 | 23 +++++++++++++
.../Semantics/OpenMP/affinity-invalid.f90 | 33 +++++++++++++++++--
4 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
index 6940ce0b10b5f..0d59c698783e2 100644
--- a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
+++ b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
@@ -1018,9 +1018,6 @@ static llvm::StringMap<bool> getTargetFeatures(mlir::ModuleOp module) {
return featuresMap;
}
-template <typename T>
-static bool isVectorSubscript(const evaluate::Expr<T> &expr);
-
bool ClauseProcessor::processAffinity(
mlir::omp::AffinityClauseOps &result) const {
return findRepeatableClause<omp::clause::Affinity>(
@@ -1049,7 +1046,7 @@ bool ClauseProcessor::processAffinity(
TodoLocators(clauseLocation, objects);
for (const omp::Object &object : objects)
- if (object.ref() && isVectorSubscript(*object.ref()))
+ if (object.ref() && evaluate::HasVectorSubscript(*object.ref()))
TODO(clauseLocation, "vector subscript in AFFINITY clause");
auto genEntry = [&](const omp::Object &object,
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 5b7f2db27d1cc..09a442d15266e 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -6048,6 +6048,15 @@ void OmpStructureChecker::CheckArraySection(
for (const auto &subscript : arrayElement.Subscripts()) {
if (const auto *triplet{
std::get_if<parser::SubscriptTriplet>(&subscript.u)}) {
+ // OpenMP 5.2 3.2.5 allows a stride only in clauses that permit one.
+ // TODO: Also reject strides in DEPEND and REDUCTION, not just AFFINITY.
+ bool affinityStride{clause == llvm::omp::Clause::OMPC_affinity &&
+ !isSubstring && std::get<2>(triplet->t)};
+ if (affinityStride) {
+ context_.Say(GetContext().clauseSource,
+ "'%s' in %s clause must not specify a stride"_err_en_US,
+ name.ToString(), parser::omp::GetUpperName(clause, version));
+ }
const auto &lower{std::get<0>(triplet->t)};
const auto &upper{std::get<1>(triplet->t)};
if (lower && upper) {
@@ -6057,7 +6066,7 @@ void OmpStructureChecker::CheckArraySection(
// Restrictions: if a stride expression is specified it must be
// positive. A stride of 0 doesn't make sense.
strideVal = GetIntValue(strideExpr);
- if (strideVal && *strideVal < 1) {
+ if (strideVal && *strideVal < 1 && !affinityStride) {
context_.Say(GetContext().clauseSource,
"'%s' in %s clause must have a positive stride"_err_en_US,
name.ToString(), parser::omp::GetUpperName(clause, version));
diff --git a/flang/test/Lower/OpenMP/Todo/affinity-vector-subscript.f90 b/flang/test/Lower/OpenMP/Todo/affinity-vector-subscript.f90
index 8ea7849c5e502..139030ca3a142 100644
--- a/flang/test/Lower/OpenMP/Todo/affinity-vector-subscript.f90
+++ b/flang/test/Lower/OpenMP/Todo/affinity-vector-subscript.f90
@@ -2,6 +2,8 @@
! RUN: %not_todo_cmd %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=52 -o - %t/iterator.f90 2>&1 | FileCheck %s
! RUN: %not_todo_cmd %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=52 -o - %t/iterator-2d.f90 2>&1 | FileCheck %s
! RUN: %not_todo_cmd %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=52 -o - %t/no-iterator.f90 2>&1 | FileCheck %s
+! RUN: %not_todo_cmd %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=52 -o - %t/parent-iterator.f90 2>&1 | FileCheck %s
+! RUN: %not_todo_cmd %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=52 -o - %t/parent-no-iterator.f90 2>&1 | FileCheck %s
! CHECK: not yet implemented: vector subscript in AFFINITY clause
@@ -25,3 +27,24 @@ subroutine s(a)
!$omp task affinity(a([1]))
!$omp end task
end
+
+!--- parent-iterator.f90
+subroutine s(a, m)
+ type t
+ integer :: field(2)
+ end type
+ type(t) :: a(8)
+ integer :: m
+ !$omp task affinity(iterator(i = 1:m): a([i])%field(1))
+ !$omp end task
+end
+
+!--- parent-no-iterator.f90
+subroutine s(a)
+ type t
+ integer :: field(2)
+ end type
+ type(t) :: a(8)
+ !$omp task affinity(a([1])%field(1))
+ !$omp end task
+end
diff --git a/flang/test/Semantics/OpenMP/affinity-invalid.f90 b/flang/test/Semantics/OpenMP/affinity-invalid.f90
index 34bf9bb3c0798..eb10e373df2bf 100644
--- a/flang/test/Semantics/OpenMP/affinity-invalid.f90
+++ b/flang/test/Semantics/OpenMP/affinity-invalid.f90
@@ -38,11 +38,38 @@ subroutine affinity_iterator_section_component(n, m)
subroutine affinity_section_bad_stride(n)
integer, intent(in) :: n
integer :: a(n)
- !ERROR: 'a' in AFFINITY clause must have a positive stride
+ !ERROR: 'a' in AFFINITY clause must not specify a stride
!$omp task affinity(a(1:n:-1))
!$omp end task
end subroutine
+subroutine affinity_section_stride(n, k)
+ integer, intent(in) :: n, k
+ integer :: a(n), b(2, n)
+ type t
+ integer :: f(8)
+ end type
+ type(t) :: x
+ !ERROR: 'a' in AFFINITY clause must not specify a stride
+ !$omp task affinity(a(1:n:k))
+ !$omp end task
+ !ERROR: 'a' in AFFINITY clause must not specify a stride
+ !$omp task affinity(a(::2))
+ !$omp end task
+ !ERROR: 'a' in AFFINITY clause must not specify a stride
+ !$omp task affinity(iterator(i = 7:7): a(i:i:k))
+ !$omp end task
+ !ERROR: 'b' in AFFINITY clause must not specify a stride
+ !$omp task affinity(iterator(i = 7:7): b(1:2, i:i:k))
+ !$omp end task
+ !ERROR: 'f' in AFFINITY clause must not specify a stride
+ !$omp task affinity(x%f(1:8:2))
+ !$omp end task
+ !ERROR: 'a' in AFFINITY clause must not specify a stride
+ !$omp task affinity(a(1:n:1))
+ !$omp end task
+end subroutine
+
subroutine affinity_section_zero_size(n)
integer, intent(in) :: n
integer :: a(n)
@@ -76,7 +103,7 @@ subroutine affinity_iterator_step_zero()
subroutine affinity_iterator_section_bad_stride(n)
integer, intent(in) :: n
integer :: a(n)
- !ERROR: 'a' in AFFINITY clause must have a positive stride
+ !ERROR: 'a' in AFFINITY clause must not specify a stride
!$omp task affinity(iterator(i = 1:n): a(i:n:-1))
!$omp end task
end subroutine
@@ -91,7 +118,7 @@ subroutine affinity_substring_like_step()
subroutine affinity_section_step_zero()
integer :: a(10)
- !ERROR: 'a' in AFFINITY clause must have a positive stride
+ !ERROR: 'a' in AFFINITY clause must not specify a stride
!ERROR: Stride of triplet must not be zero
!$omp task affinity(a(1:10:0))
!$omp end task
>From ae2e8711371fd46e868aad023eb90cf28cdd5304 Mon Sep 17 00:00:00 2001
From: "Chi-Chun, Chen" <chichun.chen at hpe.com>
Date: Sat, 10 Oct 2026 18:19:16 -0500
Subject: [PATCH 7/8] Check locator strides and AFFINITY array parents
Reject explicit strides in AFFINITY and DEPEND locators, including earlier
part references. Follow only the data-reference base chain so sections
inside scalar subscript expressions remain valid.
Stop with a not-yet-implemented diagnostic for array-valued AFFINITY
parents before generating addresses or bounds. Cover ordinary and
iterated locators, including folded references and unused iterators.
Keep these locators semantically valid when the final part reference has
a section-subscript list, even when its subscripts are scalar.
Use the final symbol's rank to recognize scalar character substrings
with array-valued parents, and reject substring steps even when bounds
are omitted.
---
flang/lib/Lower/OpenMP/ClauseProcessor.cpp | 18 ++-
flang/lib/Semantics/check-omp-structure.cpp | 68 +++++++---
flang/lib/Semantics/check-omp-structure.h | 1 +
.../OpenMP/Todo/affinity-parent-section.f90 | 117 +++++++++++++++++
.../test/Lower/OpenMP/affinity-part-refs.f90 | 73 +++++++++++
.../OpenMP/task-depend-array-section.f90 | 45 ++++---
.../Semantics/OpenMP/affinity-part-refs.f90 | 74 +++++++++++
.../test/Semantics/OpenMP/depend-strides.f90 | 62 +++++++++
.../Semantics/OpenMP/depend-substring.f90 | 3 +-
flang/test/Semantics/OpenMP/depend01.f90 | 7 +-
.../Semantics/OpenMP/substring-strides.f90 | 118 ++++++++++++++++++
11 files changed, 547 insertions(+), 39 deletions(-)
create mode 100644 flang/test/Lower/OpenMP/Todo/affinity-parent-section.f90
create mode 100644 flang/test/Lower/OpenMP/affinity-part-refs.f90
create mode 100644 flang/test/Semantics/OpenMP/affinity-part-refs.f90
create mode 100644 flang/test/Semantics/OpenMP/depend-strides.f90
create mode 100644 flang/test/Semantics/OpenMP/substring-strides.f90
diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
index 0d59c698783e2..bc1777a63e6ec 100644
--- a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
+++ b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
@@ -1018,6 +1018,14 @@ static llvm::StringMap<bool> getTargetFeatures(mlir::ModuleOp module) {
return featuresMap;
}
+// Rank includes earlier array parts, but not arrays in scalar subscripts.
+static bool hasArrayParent(const evaluate::DataRef &dataRef) {
+ const auto *component = std::get_if<evaluate::Component>(&dataRef.u);
+ if (const auto *arrayRef = std::get_if<evaluate::ArrayRef>(&dataRef.u))
+ component = arrayRef->base().UnwrapComponent();
+ return component && component->base().Rank() > 0;
+}
+
bool ClauseProcessor::processAffinity(
mlir::omp::AffinityClauseOps &result) const {
return findRepeatableClause<omp::clause::Affinity>(
@@ -1045,9 +1053,15 @@ bool ClauseProcessor::processAffinity(
auto iteratorRanges = lowerIteratorRanges(clause, converter, stmtCtx);
TodoLocators(clauseLocation, objects);
- for (const omp::Object &object : objects)
- if (object.ref() && evaluate::HasVectorSubscript(*object.ref()))
+ for (const omp::Object &object : objects) {
+ if (!object.ref())
+ continue;
+ if (evaluate::HasVectorSubscript(*object.ref()))
TODO(clauseLocation, "vector subscript in AFFINITY clause");
+ if (auto dataRef = evaluate::ExtractDataRef(*object.ref()))
+ if (hasArrayParent(*dataRef))
+ TODO(clauseLocation, "array-valued parent in AFFINITY clause");
+ }
auto genEntry = [&](const omp::Object &object,
lower::StatementContext &localStmtCtx) {
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 09a442d15266e..86e90f0502c90 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -5268,6 +5268,7 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Depend &x) {
name->ToString());
} else if (auto *dataRef{GetDataRefFromObj(object)}) {
CheckDependList(*dataRef);
+ CheckArraySectionStrides(*dataRef, llvm::omp::Clause::OMPC_depend);
if (const auto *arr{GetArrayElementFromObj(object)}) {
CheckArraySection(
*arr, GetLastName(*dataRef), llvm::omp::Clause::OMPC_depend);
@@ -6011,7 +6012,7 @@ void OmpStructureChecker::CheckDependList(const parser::DataRef &d) {
d.u);
}
-// Called from both Reduction and Depend clause.
+// Check final array sections in REDUCTION, DEPEND, and AFFINITY clauses.
void OmpStructureChecker::CheckArraySection(
const parser::ArrayElement &arrayElement, const parser::Name &name,
const llvm::omp::Clause clause) {
@@ -6026,8 +6027,10 @@ void OmpStructureChecker::CheckArraySection(
if (!IsAssumedSizeArray(*name.symbol)) {
evaluate::ExpressionAnalyzer ea{context_};
if (MaybeExpr expr = ea.Analyze(arrayElement.Base())) {
- if (expr->Rank() == 0) {
- // Not an array: rank 0
+ // Use the final symbol's rank, as in CheckArraySectionStrides. A scalar
+ // character component can have an array-valued parent, making the rank
+ // of the base expression nonzero.
+ if (name.symbol->Rank() == 0) {
if (std::optional<evaluate::DynamicType> type = expr->GetType()) {
if (type->category() == evaluate::TypeCategory::Character) {
// Substrings are explicitly denied by the standard [6.0:163:9-11].
@@ -6036,7 +6039,7 @@ void OmpStructureChecker::CheckArraySection(
isSubstring = true;
context_.Say(GetContext().clauseSource,
"The use of substrings in OpenMP argument lists has been disallowed since OpenMP 5.2."_port_en_US);
- } else {
+ } else if (expr->Rank() == 0) {
llvm_unreachable(
"Array indexing on a variable that isn't an array");
}
@@ -6044,18 +6047,18 @@ void OmpStructureChecker::CheckArraySection(
}
}
}
+ // AFFINITY and DEPEND reject explicit strides in CheckArraySectionStrides.
+ // TODO: Extend that check to REDUCTION and other applicable clauses.
+ bool checkPositiveStride{isSubstring ||
+ (clause != llvm::omp::Clause::OMPC_affinity &&
+ clause != llvm::omp::Clause::OMPC_depend)};
if (!arrayElement.Subscripts().empty()) {
for (const auto &subscript : arrayElement.Subscripts()) {
if (const auto *triplet{
std::get_if<parser::SubscriptTriplet>(&subscript.u)}) {
- // OpenMP 5.2 3.2.5 allows a stride only in clauses that permit one.
- // TODO: Also reject strides in DEPEND and REDUCTION, not just AFFINITY.
- bool affinityStride{clause == llvm::omp::Clause::OMPC_affinity &&
- !isSubstring && std::get<2>(triplet->t)};
- if (affinityStride) {
+ if (isSubstring && std::get<2>(triplet->t)) {
context_.Say(GetContext().clauseSource,
- "'%s' in %s clause must not specify a stride"_err_en_US,
- name.ToString(), parser::omp::GetUpperName(clause, version));
+ "Cannot specify a step for a substring"_err_en_US);
}
const auto &lower{std::get<0>(triplet->t)};
const auto &upper{std::get<1>(triplet->t)};
@@ -6066,15 +6069,11 @@ void OmpStructureChecker::CheckArraySection(
// Restrictions: if a stride expression is specified it must be
// positive. A stride of 0 doesn't make sense.
strideVal = GetIntValue(strideExpr);
- if (strideVal && *strideVal < 1 && !affinityStride) {
+ if (strideVal && *strideVal < 1 && checkPositiveStride) {
context_.Say(GetContext().clauseSource,
"'%s' in %s clause must have a positive stride"_err_en_US,
name.ToString(), parser::omp::GetUpperName(clause, version));
}
- if (isSubstring) {
- context_.Say(GetContext().clauseSource,
- "Cannot specify a step for a substring"_err_en_US);
- }
}
const auto lval{GetIntValue(lower)};
const auto uval{GetIntValue(upper)};
@@ -6120,6 +6119,42 @@ void OmpStructureChecker::CheckArraySection(
}
}
+// OpenMP 5.2 3.2.5 forbids explicit strides unless the clause permits them.
+// Check only the locator's base chain, not sections in subscript expressions.
+void OmpStructureChecker::CheckArraySectionStrides(
+ const parser::DataRef &dataRef, llvm::omp::Clause clause) {
+ common::visit(
+ common::visitors{
+ [](const parser::Name &) {},
+ [&](const common::Indirection<parser::StructureComponent> &x) {
+ CheckArraySectionStrides(x.value().Base(), clause);
+ },
+ [&](const common::Indirection<parser::ArrayElement> &x) {
+ const auto &arrayElement{x.value()};
+ const auto &name{GetLastName(arrayElement.Base())};
+ // Scalar character substrings can be parsed as ArrayElement.
+ if (name.symbol->Rank() > 0 &&
+ llvm::any_of(arrayElement.Subscripts(), [](const auto &s) {
+ const auto *triplet{
+ std::get_if<parser::SubscriptTriplet>(&s.u)};
+ return triplet && std::get<2>(triplet->t).has_value();
+ })) {
+ context_.Say(GetContext().clauseSource,
+ "'%s' in %s clause must not specify a stride"_err_en_US,
+ name.ToString(),
+ parser::omp::GetUpperName(
+ clause, context_.langOptions().getOpenMPVersion()));
+ }
+ CheckArraySectionStrides(arrayElement.Base(), clause);
+ },
+ [&](const common::Indirection<parser::CoindexedNamedObject> &x) {
+ CheckArraySectionStrides(
+ std::get<parser::DataRef>(x.value().t), clause);
+ },
+ },
+ dataRef.u);
+}
+
void OmpStructureChecker::CheckLastPartRefForArraySection(
const parser::Designator &designator, llvm::omp::Clause clauseId) {
if (!designator.EndsInBareName()) {
@@ -6775,6 +6810,7 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Affinity &x) {
CheckArraySection(*arrayElement, GetLastName(*dataRef),
llvm::omp::Clause::OMPC_affinity);
}
+ CheckArraySectionStrides(*dataRef, llvm::omp::Clause::OMPC_affinity);
}
// CheckArraySection handles ArrayElement cases,
diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h
index 79434e43c8db4..530ad90abcefc 100644
--- a/flang/lib/Semantics/check-omp-structure.h
+++ b/flang/lib/Semantics/check-omp-structure.h
@@ -504,6 +504,7 @@ class OmpStructureChecker : public OmpStructureCheckerBase {
const parser::OmpObjectList &ompObjectList, llvm::omp::Clause clauseId);
void CheckArraySection(const parser::ArrayElement &arrayElement,
const parser::Name &name, const llvm::omp::Clause clause);
+ void CheckArraySectionStrides(const parser::DataRef &, llvm::omp::Clause);
void CheckLastPartRefForArraySection(
const parser::Designator &designator, llvm::omp::Clause clauseId);
void CheckSharedBindingInOuterContext(
diff --git a/flang/test/Lower/OpenMP/Todo/affinity-parent-section.f90 b/flang/test/Lower/OpenMP/Todo/affinity-parent-section.f90
new file mode 100644
index 0000000000000..0d42188b0f6f4
--- /dev/null
+++ b/flang/test/Lower/OpenMP/Todo/affinity-parent-section.f90
@@ -0,0 +1,117 @@
+! RUN: split-file %s %t
+! RUN: %not_todo_cmd %flang_fc1 -emit-hlfir -fopenmp \
+! RUN: -fopenmp-version=52 -o - %t/iterator.f90 2>&1 | FileCheck %s
+! RUN: %not_todo_cmd %flang_fc1 -emit-hlfir -fopenmp \
+! RUN: -fopenmp-version=52 -o - %t/folded.f90 2>&1 | FileCheck %s
+! RUN: %not_todo_cmd %flang_fc1 -emit-hlfir -fopenmp \
+! RUN: -fopenmp-version=52 -o - %t/parent-iterator.f90 2>&1 | FileCheck %s
+! RUN: %not_todo_cmd %flang_fc1 -emit-hlfir -fopenmp \
+! RUN: -fopenmp-version=52 -o - %t/unused.f90 2>&1 | FileCheck %s
+! RUN: %not_todo_cmd %flang_fc1 -emit-hlfir -fopenmp \
+! RUN: -fopenmp-version=52 -o - %t/ordinary.f90 2>&1 | FileCheck %s
+! RUN: %not_todo_cmd %flang_fc1 -emit-hlfir -fopenmp \
+! RUN: -fopenmp-version=52 -o - %t/nested.f90 2>&1 | FileCheck %s
+! RUN: %not_todo_cmd %flang_fc1 -emit-hlfir -fopenmp \
+! RUN: -fopenmp-version=52 -o - %t/intermediate.f90 2>&1 | FileCheck %s
+! RUN: %not_todo_cmd %flang_fc1 -emit-hlfir -fopenmp \
+! RUN: -fopenmp-version=52 -o - %t/whole-iterator.f90 2>&1 | FileCheck %s
+! RUN: %not_todo_cmd %flang_fc1 -emit-hlfir -fopenmp \
+! RUN: -fopenmp-version=52 -o - %t/whole-ordinary.f90 2>&1 | FileCheck %s
+
+! CHECK: not yet implemented: array-valued parent in AFFINITY clause
+
+!--- iterator.f90
+subroutine s(a)
+ type t
+ integer :: field(4)
+ end type
+ type(t) :: a(8)
+ !$omp task affinity(iterator(i=1:2): a(1:2)%field(i))
+ !$omp end task
+end
+
+!--- folded.f90
+subroutine s(a)
+ type t
+ integer :: field(4)
+ end type
+ type(t) :: a(8)
+ !$omp task affinity(iterator(i=1:2): a(1:2)%field(1+0*i))
+ !$omp end task
+end
+
+!--- parent-iterator.f90
+subroutine s(a)
+ type t
+ integer :: field(4)
+ end type
+ type(t) :: a(8)
+ !$omp task affinity(iterator(i=1:2): a(1:i)%field(1))
+ !$omp end task
+end
+
+!--- unused.f90
+subroutine s(a)
+ type t
+ integer :: field(4)
+ end type
+ type(t) :: a(8)
+ !$omp task affinity(iterator(i=1:0): a(1:2)%field(1))
+ !$omp end task
+end
+
+!--- ordinary.f90
+subroutine s(a)
+ type t
+ integer :: field(4)
+ end type
+ type(t) :: a(8)
+ !$omp task affinity(a(1:2)%field(1))
+ !$omp end task
+end
+
+!--- nested.f90
+subroutine s(a)
+ type t
+ integer :: field(4)
+ end type
+ type outer
+ type(t) :: nested
+ end type
+ type(outer) :: a(8)
+ !$omp task affinity(iterator(i=1:2): a(1:2)%nested%field(i))
+ !$omp end task
+end
+
+!--- intermediate.f90
+subroutine s(a)
+ type t
+ integer :: field(4)
+ end type
+ type outer
+ type(t) :: nested(8)
+ end type
+ type(outer) :: a
+ !$omp task affinity(iterator(i=1:2): a%nested(1:2)%field(i))
+ !$omp end task
+end
+
+!--- whole-iterator.f90
+subroutine s(a)
+ type t
+ integer :: field(4)
+ end type
+ type(t) :: a(8)
+ !$omp task affinity(iterator(i=1:2): a%field(i))
+ !$omp end task
+end
+
+!--- whole-ordinary.f90
+subroutine s(a)
+ type t
+ integer :: field(4)
+ end type
+ type(t) :: a(8)
+ !$omp task affinity(a%field(1))
+ !$omp end task
+end
diff --git a/flang/test/Lower/OpenMP/affinity-part-refs.f90 b/flang/test/Lower/OpenMP/affinity-part-refs.f90
new file mode 100644
index 0000000000000..0dd4d7a78aac2
--- /dev/null
+++ b/flang/test/Lower/OpenMP/affinity-part-refs.f90
@@ -0,0 +1,73 @@
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=52 -o - %s | \
+! RUN: FileCheck %s
+
+! These locators must not be rejected by the earlier-part section guard.
+
+subroutine scalar_parent(a, b, v)
+ type t
+ integer :: field(4)
+ end type
+ type(t) :: a(8)
+ integer :: b(100), v(8)
+ !$omp task affinity(iterator(i=1:2): a(i)%field(1))
+ !$omp end task
+end
+! CHECK-LABEL: func.func @_QPscalar_parent(
+! CHECK: omp.iterator
+! CHECK: omp.affinity_entry
+! CHECK: omp.task affinity
+
+subroutine final_section(a, b, v)
+ type t
+ integer :: field(4)
+ end type
+ type(t) :: a(8)
+ integer :: b(100), v(8)
+ !$omp task affinity(iterator(i=1:2): a(1)%field(i:i+1))
+ !$omp end task
+end
+! CHECK-LABEL: func.func @_QPfinal_section(
+! CHECK: omp.iterator
+! CHECK: omp.affinity_entry
+! CHECK: omp.task affinity
+
+subroutine ordinary_expression(a, b, v)
+ type t
+ integer :: field(4)
+ end type
+ type(t) :: a(8)
+ integer :: b(100), v(8)
+ !$omp task affinity(b(sum(v(::2))))
+ !$omp end task
+end
+! CHECK-LABEL: func.func @_QPordinary_expression(
+! CHECK: omp.affinity_entry
+! CHECK: omp.task affinity
+
+subroutine iterator_expression(a, b, v)
+ type t
+ integer :: field(4)
+ end type
+ type(t) :: a(8)
+ integer :: b(100), v(8)
+ !$omp task affinity(iterator(i=1:2): b(sum(v(::2))+i))
+ !$omp end task
+end
+! CHECK-LABEL: func.func @_QPiterator_expression(
+! CHECK: omp.iterator
+! CHECK: omp.affinity_entry
+! CHECK: omp.task affinity
+
+subroutine parent_expression(a, b, v)
+ type t
+ integer :: field(4)
+ end type
+ type(t) :: a(8)
+ integer :: b(100), v(8)
+ !$omp task affinity(iterator(i=1:2): a(sum(v(::2)))%field(i))
+ !$omp end task
+end
+! CHECK-LABEL: func.func @_QPparent_expression(
+! CHECK: omp.iterator
+! CHECK: omp.affinity_entry
+! CHECK: omp.task affinity
diff --git a/flang/test/Lower/OpenMP/task-depend-array-section.f90 b/flang/test/Lower/OpenMP/task-depend-array-section.f90
index 0c78c1dcb37b2..9166d442765ba 100644
--- a/flang/test/Lower/OpenMP/task-depend-array-section.f90
+++ b/flang/test/Lower/OpenMP/task-depend-array-section.f90
@@ -29,26 +29,25 @@ subroutine knownShape(array)
subroutine assumedShape(array)
integer :: array(:)
- !$omp task depend(in: array(2:8:2))
+ !$omp task depend(in: array(2:8))
!$omp end task
end subroutine
-! CHECK-LABEL: func.func @_QPassumedshape(
-! CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box<!fir.array<?xi32>> {fir.bindc_name = "array"}) {
-! CHECK: %[[VAL_1:.*]] = fir.dummy_scope : !fir.dscope
-! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_0]] dummy_scope %[[VAL_1]] arg {{[0-9]+}} uniq_name("_QFassumedshapeEarray") : (!fir.box<!fir.array<?xi32>>, !fir.dscope) -> (!fir.box<!fir.array<?xi32>>, !fir.box<!fir.array<?xi32>>)
-! CHECK: %[[VAL_3:.*]] = arith.constant 2 : index
-! CHECK: %[[VAL_4:.*]] = arith.constant 8 : index
-! CHECK: %[[VAL_5:.*]] = arith.constant 2 : index
-! CHECK: %[[VAL_6:.*]] = arith.constant 4 : index
-! CHECK: %[[VAL_7:.*]] = fir.shape %[[VAL_6]] : (index) -> !fir.shape<1>
-! CHECK: %[[VAL_8:.*]] = hlfir.designate %[[VAL_2]]#0 (%[[VAL_3]]:%[[VAL_4]]:%[[VAL_5]]) shape %[[VAL_7]] : (!fir.box<!fir.array<?xi32>>, index, index, index, !fir.shape<1>) -> !fir.box<!fir.array<4xi32>>
-! CHECK: %[[VAL_9:.*]] = fir.box_addr %[[VAL_8]] : (!fir.box<!fir.array<4xi32>>) -> !fir.ref<!fir.array<4xi32>>
-! CHECK: omp.task depend(taskdependin -> %[[VAL_9]] : !fir.ref<!fir.array<4xi32>>) {
-! CHECK: omp.terminator
-! CHECK: }
-! CHECK: return
-! CHECK: }
+! CHECK-LABEL: func.func @_QPassumedshape(
+! CHECK-SAME: %[[ARG:.*]]: !fir.box<!fir.array<?xi32>>
+! CHECK: %[[ARRAY:.*]]:2 = hlfir.declare %[[ARG]]
+! CHECK: %[[LOW:.*]] = arith.constant 2 : index
+! CHECK: %[[HIGH:.*]] = arith.constant 8 : index
+! CHECK: %[[STRIDE:.*]] = arith.constant 1 : index
+! CHECK: %[[EXTENT:.*]] = arith.constant 7 : index
+! CHECK: %[[SHAPE:.*]] = fir.shape %[[EXTENT]]
+! CHECK: %[[SECTION:.*]] = hlfir.designate %[[ARRAY]]#0
+! CHECK-SAME: (%[[LOW]]:%[[HIGH]]:%[[STRIDE]]) shape %[[SHAPE]]
+! CHECK: %[[ADDR:.*]] = fir.box_addr %[[SECTION]]
+! CHECK: omp.task depend(taskdependin -> %[[ADDR]] :
+! CHECK: omp.terminator
+! CHECK: return
+! CHECK: }
subroutine vectorSubscriptArraySection(array, indices)
integer :: array(:)
@@ -82,3 +81,15 @@ subroutine vectorSubscriptArraySection(array, indices)
! CHECK: hlfir.destroy %[[VAL_8]] : !hlfir.expr<?xi64>
! CHECK: return
! CHECK: }
+
+! A section inside a scalar subscript is not a section of the locator.
+subroutine scalar_subscript_section(b, v)
+ integer :: b(100), v(8)
+ !$omp task depend(iterator(i=1:2:1), in: b(sum(v(::2))+i))
+ !$omp end task
+end subroutine
+! CHECK-LABEL: func.func @_QPscalar_subscript_section(
+! CHECK: %[[ITER:.*]] = omp.iterator
+! CHECK: hlfir.sum
+! CHECK: omp.yield
+! CHECK: omp.task depend(taskdependin -> %[[ITER]]
diff --git a/flang/test/Semantics/OpenMP/affinity-part-refs.f90 b/flang/test/Semantics/OpenMP/affinity-part-refs.f90
new file mode 100644
index 0000000000000..e34ec287d71cd
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/affinity-part-refs.f90
@@ -0,0 +1,74 @@
+! RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=52
+
+subroutine earlier_part_strides(a, k)
+ type inner
+ integer :: field(4)
+ end type
+ type outer
+ type(inner) :: nested
+ end type
+ type(outer) :: a(8)
+ integer :: k
+
+ !ERROR: 'a' in AFFINITY clause must not specify a stride
+ !$omp task affinity(a(1:8:1)%nested%field(1))
+ !$omp end task
+ !ERROR: 'a' in AFFINITY clause must not specify a stride
+ !$omp task affinity(iterator(i=1:2): a(1:8:1)%nested%field(i))
+ !$omp end task
+ !ERROR: 'a' in AFFINITY clause must not specify a stride
+ !$omp task affinity(a(1:8:2)%nested%field(1))
+ !$omp end task
+ !ERROR: 'a' in AFFINITY clause must not specify a stride
+ !$omp task affinity(iterator(i=1:2): a(1:8:2)%nested%field(i))
+ !$omp end task
+ !ERROR: 'a' in AFFINITY clause must not specify a stride
+ !$omp task affinity(a(1:8:k)%nested%field(1))
+ !$omp end task
+ !ERROR: 'a' in AFFINITY clause must not specify a stride
+ !$omp task affinity(iterator(i=1:2): a(1:8:k)%nested%field(i))
+ !$omp end task
+ !ERROR: 'a' in AFFINITY clause must not specify a stride
+ !$omp task affinity(a(::2)%nested%field(1))
+ !$omp end task
+ !ERROR: 'a' in AFFINITY clause must not specify a stride
+ !$omp task affinity(iterator(i=1:2): a(::2)%nested%field(i))
+ !$omp end task
+end subroutine
+
+subroutine intermediate_part_stride(a)
+ type inner
+ integer :: field(4)
+ end type
+ type outer
+ type(inner) :: nested(8)
+ end type
+ type(outer) :: a
+ !ERROR: 'nested' in AFFINITY clause must not specify a stride
+ !$omp task affinity(iterator(i=1:2): a%nested(::2)%field(i))
+ !$omp end task
+end subroutine
+
+! A scalar final subscript satisfies the last-part-ref restriction.
+! Sections inside scalar expressions are not sections of the locator.
+subroutine valid_part_refs(a, b, v)
+ type t
+ integer :: field(4)
+ end type
+ type(t) :: a(8)
+ integer :: b(100), v(8)
+ !$omp task affinity(a%field(1))
+ !$omp end task
+ !$omp task affinity(iterator(i=1:2): a%field(i))
+ !$omp end task
+ !$omp task affinity(a(1:2)%field(1))
+ !$omp end task
+ !$omp task affinity(iterator(i=1:2): a(1:2)%field(i))
+ !$omp end task
+ !$omp task affinity(b(sum(v(::2))))
+ !$omp end task
+ !$omp task affinity(iterator(i=1:2): b(sum(v(::2))+i))
+ !$omp end task
+ !$omp task affinity(iterator(i=1:2): a(sum(v(::2)))%field(i))
+ !$omp end task
+end subroutine
diff --git a/flang/test/Semantics/OpenMP/depend-strides.f90 b/flang/test/Semantics/OpenMP/depend-strides.f90
new file mode 100644
index 0000000000000..649bc7c359e9c
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/depend-strides.f90
@@ -0,0 +1,62 @@
+! RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=52
+
+subroutine depend_strides(b, k)
+ integer :: b(8,8), k
+ !ERROR: 'b' in DEPEND clause must not specify a stride
+ !$omp task depend(in: b(1:8:1,1))
+ !$omp end task
+ !ERROR: 'b' in DEPEND clause must not specify a stride
+ !$omp task depend(in: b(1,1:8:2))
+ !$omp end task
+ !ERROR: 'b' in DEPEND clause must not specify a stride
+ !$omp task depend(in: b(1:8:k,1))
+ !$omp end task
+ !ERROR: 'b' in DEPEND clause must not specify a stride
+ !$omp task depend(in: b(1,::2))
+ !$omp end task
+ !ERROR: 'b' in DEPEND clause must not specify a stride
+ !$omp task depend(iterator(i=1:2), in: b(i,1:8:k))
+ !$omp end task
+ ! One diagnostic per part reference, even with multiple strides.
+ !ERROR: 'b' in DEPEND clause must not specify a stride
+ !$omp task depend(in: b(1:8:1,1:8:2))
+ !$omp end task
+end subroutine
+
+subroutine earlier_part_strides(a, k)
+ type inner
+ integer :: field(4)
+ end type
+ type outer
+ type(inner) :: nested(8)
+ end type
+ type(outer) :: a(8)
+ integer :: k
+ !ERROR: 'a' in DEPEND clause must not specify a stride
+ !$omp task depend(in: a(1:8:1)%nested(1)%field(1))
+ !$omp end task
+ !ERROR: 'a' in DEPEND clause must not specify a stride
+ !$omp task depend(iterator(i=1:2), in: a(::2)%nested(1)%field(i))
+ !$omp end task
+ !ERROR: 'nested' in DEPEND clause must not specify a stride
+ !$omp task depend(iterator(i=1:2), in: a(1)%nested(::k)%field(i))
+ !$omp end task
+end subroutine
+
+subroutine valid_sections(a, b, v)
+ type t
+ integer :: field(4)
+ end type
+ type(t) :: a(8)
+ integer :: b(100), v(8)
+ !$omp task depend(in: a(1:2)%field(1))
+ !$omp end task
+ !$omp task depend(iterator(i=1:2), in: a(1:2)%field(i))
+ !$omp end task
+ !$omp task depend(in: b(sum(v(::2))))
+ !$omp end task
+ !$omp task depend(iterator(i=1:2:1), in: b(sum(v(::2))+i))
+ !$omp end task
+ !$omp task depend(iterator(i=1:2), in: a(sum(v(::2)))%field(i))
+ !$omp end task
+end subroutine
diff --git a/flang/test/Semantics/OpenMP/depend-substring.f90 b/flang/test/Semantics/OpenMP/depend-substring.f90
index 558172fa218d2..f127d21e3d0c1 100644
--- a/flang/test/Semantics/OpenMP/depend-substring.f90
+++ b/flang/test/Semantics/OpenMP/depend-substring.f90
@@ -48,9 +48,10 @@ subroutine substring_5(c)
!$omp end task
end
-! This is okay: interpreted as indexing the array
+! This is an array section, so DEPEND forbids the explicit stride.
subroutine substring_5b(c)
character(:), pointer :: c(:)
+ !ERROR: 'c' in DEPEND clause must not specify a stride
!$omp task depend(out:c(1:20:5))
!$omp end task
end
diff --git a/flang/test/Semantics/OpenMP/depend01.f90 b/flang/test/Semantics/OpenMP/depend01.f90
index 10f2d40dd1779..7e95868dfd8c8 100644
--- a/flang/test/Semantics/OpenMP/depend01.f90
+++ b/flang/test/Semantics/OpenMP/depend01.f90
@@ -18,19 +18,20 @@ program omp_depend
a(2:1) = b(2, 2)
!$omp end task
- !ERROR: 'a' in DEPEND clause must have a positive stride
- !ERROR: 'b' in DEPEND clause must have a positive stride
+ !ERROR: 'a' in DEPEND clause must not specify a stride
+ !ERROR: 'b' in DEPEND clause must not specify a stride
!ERROR: 'b' in DEPEND clause is a zero size array section
!$omp task shared(x) depend(in: a(10:5:-1)) depend(in: b(5:10:-1, 2))
print *, a(5:10), b
!$omp end task
!ERROR: 'a' in DEPEND clause is a zero size array section
+ !ERROR: 'a' in DEPEND clause must not specify a stride
!$omp task shared(x) depend(in: a(1:5:10))
print *, a(5:10), b
!$omp end task
- !ERROR: 'a' in DEPEND clause must have a positive stride
+ !ERROR: 'a' in DEPEND clause must not specify a stride
!ERROR: Stride of triplet must not be zero
!$omp task shared(a) depend(in: a(1:10:0))
print *, a(1:10)
diff --git a/flang/test/Semantics/OpenMP/substring-strides.f90 b/flang/test/Semantics/OpenMP/substring-strides.f90
new file mode 100644
index 0000000000000..c79f27d83fab7
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/substring-strides.f90
@@ -0,0 +1,118 @@
+! RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=52
+
+! Scalar character components remain substrings even with array-valued parents.
+! Substring strides are invalid whether or not either bound is present.
+
+subroutine affinity_substring_strides(a, s)
+ type t
+ character(8) :: field
+ character(8) :: array(8)
+ end type
+ type(t) :: a(8)
+ character(8) :: s
+
+ !PORTABILITY: The use of substrings in OpenMP argument lists has been disallowed since OpenMP 5.2.
+ !ERROR: Cannot specify a step for a substring
+ !$omp task affinity(s(::2))
+ !$omp end task
+ !PORTABILITY: The use of substrings in OpenMP argument lists has been disallowed since OpenMP 5.2.
+ !ERROR: Cannot specify a step for a substring
+ !$omp task affinity(s(1::2))
+ !$omp end task
+ !PORTABILITY: The use of substrings in OpenMP argument lists has been disallowed since OpenMP 5.2.
+ !ERROR: Cannot specify a step for a substring
+ !$omp task affinity(s(:8:2))
+ !$omp end task
+ !PORTABILITY: The use of substrings in OpenMP argument lists has been disallowed since OpenMP 5.2.
+ !ERROR: Cannot specify a step for a substring
+ !$omp task affinity(a(1)%field(1:4:2))
+ !$omp end task
+ !PORTABILITY: The use of substrings in OpenMP argument lists has been disallowed since OpenMP 5.2.
+ !ERROR: Cannot specify a step for a substring
+ !$omp task affinity(a(1:2)%field(1:4:2))
+ !$omp end task
+ !PORTABILITY: The use of substrings in OpenMP argument lists has been disallowed since OpenMP 5.2.
+ !ERROR: Cannot specify a step for a substring
+ !$omp task affinity(a(1:2)%field(::2))
+ !$omp end task
+ !PORTABILITY: The use of substrings in OpenMP argument lists has been disallowed since OpenMP 5.2.
+ !ERROR: Cannot specify a step for a substring
+ !$omp task affinity(a%field(1:4:2))
+ !$omp end task
+ !PORTABILITY: The use of substrings in OpenMP argument lists has been disallowed since OpenMP 5.2.
+ !ERROR: Cannot specify a step for a substring
+ !$omp task affinity(iterator(i=1:2): a(1:i)%field(1:4:2))
+ !$omp end task
+
+ ! Without a step, these substrings remain accepted as an extension.
+ !PORTABILITY: The use of substrings in OpenMP argument lists has been disallowed since OpenMP 5.2.
+ !$omp task affinity(a(1)%field(1:4))
+ !$omp end task
+ !PORTABILITY: The use of substrings in OpenMP argument lists has been disallowed since OpenMP 5.2.
+ !$omp task affinity(a(1:2)%field(1:4))
+ !$omp end task
+
+ ! An array character component uses array section rules instead.
+ !ERROR: 'array' in AFFINITY clause must not specify a stride
+ !$omp task affinity(a(1)%array(1:4:2))
+ !$omp end task
+ !$omp task affinity(a(1)%array(1:4))
+ !$omp end task
+end subroutine
+
+subroutine depend_substring_strides(a, s)
+ type t
+ character(8) :: field
+ character(8) :: array(8)
+ end type
+ type(t) :: a(8)
+ character(8) :: s
+
+ !PORTABILITY: The use of substrings in OpenMP argument lists has been disallowed since OpenMP 5.2.
+ !ERROR: Cannot specify a step for a substring
+ !$omp task depend(in: s(::2))
+ !$omp end task
+ !PORTABILITY: The use of substrings in OpenMP argument lists has been disallowed since OpenMP 5.2.
+ !ERROR: Cannot specify a step for a substring
+ !$omp task depend(in: s(1::2))
+ !$omp end task
+ !PORTABILITY: The use of substrings in OpenMP argument lists has been disallowed since OpenMP 5.2.
+ !ERROR: Cannot specify a step for a substring
+ !$omp task depend(in: s(:8:2))
+ !$omp end task
+ !PORTABILITY: The use of substrings in OpenMP argument lists has been disallowed since OpenMP 5.2.
+ !ERROR: Cannot specify a step for a substring
+ !$omp task depend(in: a(1)%field(1:4:2))
+ !$omp end task
+ !PORTABILITY: The use of substrings in OpenMP argument lists has been disallowed since OpenMP 5.2.
+ !ERROR: Cannot specify a step for a substring
+ !$omp task depend(in: a(1:2)%field(1:4:2))
+ !$omp end task
+ !PORTABILITY: The use of substrings in OpenMP argument lists has been disallowed since OpenMP 5.2.
+ !ERROR: Cannot specify a step for a substring
+ !$omp task depend(in: a(1:2)%field(::2))
+ !$omp end task
+ !PORTABILITY: The use of substrings in OpenMP argument lists has been disallowed since OpenMP 5.2.
+ !ERROR: Cannot specify a step for a substring
+ !$omp task depend(in: a%field(1:4:2))
+ !$omp end task
+ !PORTABILITY: The use of substrings in OpenMP argument lists has been disallowed since OpenMP 5.2.
+ !ERROR: Cannot specify a step for a substring
+ !$omp task depend(iterator(i=1:2), in: a(1:i)%field(1:4:2))
+ !$omp end task
+
+ ! Without a step, these substrings remain accepted as an extension.
+ !PORTABILITY: The use of substrings in OpenMP argument lists has been disallowed since OpenMP 5.2.
+ !$omp task depend(in: a(1)%field(1:4))
+ !$omp end task
+ !PORTABILITY: The use of substrings in OpenMP argument lists has been disallowed since OpenMP 5.2.
+ !$omp task depend(in: a(1:2)%field(1:4))
+ !$omp end task
+
+ ! An array character component uses array section rules instead.
+ !ERROR: 'array' in DEPEND clause must not specify a stride
+ !$omp task depend(in: a(1)%array(1:4:2))
+ !$omp end task
+ !$omp task depend(in: a(1)%array(1:4))
+ !$omp end task
+end subroutine
>From 67e37a949c21bd78445a5f4a550907e82013d301 Mon Sep 17 00:00:00 2001
From: "Chi-Chun, Chen" <chichun.chen at hpe.com>
Date: Sun, 11 Oct 2026 01:24:01 -0500
Subject: [PATCH 8/8] Simplify iterator lowering and trim duplicate tests
Use capture-only iterator callbacks and bind induction variables as block
arguments are created, eliminating the temporary induction-value vector.
Remove unused-iterator HLFIR cases covered by the per-locator and LLVM
checks. Reduce repeated stride diagnostics and remove unused declarations
from the positive AFFINITY tests.
---
flang/lib/Lower/OpenMP/ClauseProcessor.cpp | 33 +++++++----------
.../test/Lower/OpenMP/affinity-part-refs.f90 | 22 ++++--------
flang/test/Lower/OpenMP/depend-iterator.f90 | 32 -----------------
flang/test/Lower/OpenMP/task-affinity.f90 | 35 -------------------
.../Semantics/OpenMP/affinity-part-refs.f90 | 9 -----
.../Semantics/OpenMP/substring-strides.f90 | 30 ++--------------
6 files changed, 21 insertions(+), 140 deletions(-)
diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
index bc1777a63e6ec..ff628bcc310cc 100644
--- a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
+++ b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
@@ -280,7 +280,6 @@ static mlir::Value buildIteratorOp(Fortran::lower::AbstractConverter &converter,
mlir::Location loc, mlir::Type iterTy,
llvm::ArrayRef<IteratorRange> ranges,
BodyFn &&bodyGen) {
-
auto &builder = converter.getFirOpBuilder();
llvm::SmallVector<mlir::Value> lbs, ubs, steps;
@@ -302,16 +301,11 @@ static mlir::Value buildIteratorOp(Fortran::lower::AbstractConverter &converter,
mlir::Region ® = itOp.getRegion();
mlir::Block *body = builder.createBlock(®);
- llvm::SmallVector<mlir::Value> ivs;
- ivs.reserve(ranges.size());
- for (const IteratorRange &r : ranges)
- ivs.push_back(body->addArgument(r.lb.getType(), loc));
-
Fortran::lower::SymMap &symMap = converter.getSymbolMap();
Fortran::lower::SymMapScope scope(symMap);
- for (size_t i = 0; i < ranges.size(); ++i) {
- const Fortran::semantics::Symbol &ivSym = *ranges[i].ivSym;
- mlir::Value ivVal = ivs[i];
+ for (const IteratorRange &r : ranges) {
+ const Fortran::semantics::Symbol &ivSym = *r.ivSym;
+ mlir::Value ivVal = body->addArgument(r.lb.getType(), loc);
mlir::Type ivTy = converter.genType(ivSym);
if (ivVal.getType() != ivTy)
ivVal = fir::ConvertOp::create(builder, loc, ivTy, ivVal);
@@ -330,7 +324,7 @@ static mlir::Value buildIteratorOp(Fortran::lower::AbstractConverter &converter,
symMap.addVariableDefinition(ivSym, declareOp, /*force=*/true);
}
- mlir::omp::YieldOp::create(builder, loc, bodyGen(builder, loc, ivs));
+ mlir::omp::YieldOp::create(builder, loc, bodyGen());
return itOp.getResult();
}
@@ -1089,13 +1083,12 @@ bool ClauseProcessor::processAffinity(
llvm::SmallVector<IteratorRange> objectRanges =
getIteratorRangesForObject(object, iteratorRanges);
if (!objectRanges.empty()) {
- mlir::Value iterHandle = buildIteratorOp(
- converter, clauseLocation, iterTy, objectRanges,
- [&](fir::FirOpBuilder &builder, mlir::Location loc,
- llvm::ArrayRef<mlir::Value> /*ivs*/) -> mlir::Value {
- lower::StatementContext iterStmtCtx;
- return genEntry(object, iterStmtCtx);
- });
+ mlir::Value iterHandle =
+ buildIteratorOp(converter, clauseLocation, iterTy, objectRanges,
+ [&]() -> mlir::Value {
+ lower::StatementContext iterStmtCtx;
+ return genEntry(object, iterStmtCtx);
+ });
result.iterated.push_back(iterHandle);
} else {
result.affinityVars.push_back(genEntry(object, stmtCtx));
@@ -1519,12 +1512,12 @@ bool ClauseProcessor::processDepend(lower::SymMap &symMap,
if (!objectRanges.empty()) {
mlir::Value iterHandle = buildIteratorOp(
converter, clauseLocation, iterTy, objectRanges,
- [&](fir::FirOpBuilder &builder, mlir::Location loc,
- llvm::ArrayRef<mlir::Value> /*ivs*/) -> mlir::Value {
+ [&]() -> mlir::Value {
lower::StatementContext iterStmtCtx;
mlir::Value addr =
genDependVar(object, converter.getSymbolMap(), iterStmtCtx);
- return fir::ConvertOp::create(builder, loc, ptrTy, addr);
+ return fir::ConvertOp::create(builder, clauseLocation, ptrTy,
+ addr);
});
result.dependIterated.push_back(iterHandle);
result.dependIteratedKinds.push_back(dependTypeOperand);
diff --git a/flang/test/Lower/OpenMP/affinity-part-refs.f90 b/flang/test/Lower/OpenMP/affinity-part-refs.f90
index 0dd4d7a78aac2..cb78c7b80d32a 100644
--- a/flang/test/Lower/OpenMP/affinity-part-refs.f90
+++ b/flang/test/Lower/OpenMP/affinity-part-refs.f90
@@ -3,12 +3,11 @@
! These locators must not be rejected by the earlier-part section guard.
-subroutine scalar_parent(a, b, v)
+subroutine scalar_parent(a)
type t
integer :: field(4)
end type
type(t) :: a(8)
- integer :: b(100), v(8)
!$omp task affinity(iterator(i=1:2): a(i)%field(1))
!$omp end task
end
@@ -17,12 +16,11 @@ subroutine scalar_parent(a, b, v)
! CHECK: omp.affinity_entry
! CHECK: omp.task affinity
-subroutine final_section(a, b, v)
+subroutine final_section(a)
type t
integer :: field(4)
end type
type(t) :: a(8)
- integer :: b(100), v(8)
!$omp task affinity(iterator(i=1:2): a(1)%field(i:i+1))
!$omp end task
end
@@ -31,11 +29,7 @@ subroutine final_section(a, b, v)
! CHECK: omp.affinity_entry
! CHECK: omp.task affinity
-subroutine ordinary_expression(a, b, v)
- type t
- integer :: field(4)
- end type
- type(t) :: a(8)
+subroutine ordinary_expression(b, v)
integer :: b(100), v(8)
!$omp task affinity(b(sum(v(::2))))
!$omp end task
@@ -44,11 +38,7 @@ subroutine ordinary_expression(a, b, v)
! CHECK: omp.affinity_entry
! CHECK: omp.task affinity
-subroutine iterator_expression(a, b, v)
- type t
- integer :: field(4)
- end type
- type(t) :: a(8)
+subroutine iterator_expression(b, v)
integer :: b(100), v(8)
!$omp task affinity(iterator(i=1:2): b(sum(v(::2))+i))
!$omp end task
@@ -58,12 +48,12 @@ subroutine iterator_expression(a, b, v)
! CHECK: omp.affinity_entry
! CHECK: omp.task affinity
-subroutine parent_expression(a, b, v)
+subroutine parent_expression(a, v)
type t
integer :: field(4)
end type
type(t) :: a(8)
- integer :: b(100), v(8)
+ integer :: v(8)
!$omp task affinity(iterator(i=1:2): a(sum(v(::2)))%field(i))
!$omp end task
end
diff --git a/flang/test/Lower/OpenMP/depend-iterator.f90 b/flang/test/Lower/OpenMP/depend-iterator.f90
index 42d6a4f8d7688..275aebe09aa4a 100644
--- a/flang/test/Lower/OpenMP/depend-iterator.f90
+++ b/flang/test/Lower/OpenMP/depend-iterator.f90
@@ -10,38 +10,6 @@
! task
!===============================================================================
-! The unused j range must not suppress a(i) when m < 3.
-subroutine depend_unused_iterator(m)
- integer :: m
- integer :: a(4)
-
- !$omp task depend(iterator(i = 1:2, j = 3:m), in: a(i))
- !$omp end task
-end subroutine
-
-! CHECK-LABEL: func.func @_QPdepend_unused_iterator(
-! CHECK: %[[A:.*]]:2 = hlfir.declare
-! CHECK-SAME: uniq_name("_QFdepend_unused_iteratorEa")
-! CHECK: %[[M:.*]]:2 = hlfir.declare
-! CHECK-SAME: uniq_name("_QFdepend_unused_iteratorEm")
-! CHECK: %[[I_LB:.*]] = arith.constant 1 : i32
-! CHECK: %[[I_UB:.*]] = arith.constant 2 : i32
-! CHECK: %[[I_STEP:.*]] = arith.constant 1 : i32
-! CHECK: %[[IT_I:.*]] = omp.iterator(%[[IV_I:.*]]: i32) =
-! CHECK-SAME: (%[[I_LB]] to %[[I_UB]] step %[[I_STEP]]) {
-! CHECK: fir.store %[[IV_I]] to %[[MEM_I:.*]] : !fir.ref<i32>
-! CHECK: %[[DECL_I:.*]]:2 = hlfir.declare %[[MEM_I]]
-! CHECK: %[[LD_I:.*]] = fir.load %[[DECL_I]]#0 : !fir.ref<i32>
-! CHECK: %[[IDX_I:.*]] = fir.convert %[[LD_I]] : (i32) -> i64
-! CHECK: %[[COOR_I:.*]] = hlfir.designate %[[A]]#0 (%[[IDX_I]])
-! CHECK: %[[PTR_I:.*]] = fir.convert %[[COOR_I]]
-! CHECK-SAME: (!fir.ref<i32>) -> !llvm.ptr
-! CHECK: omp.yield(%[[PTR_I]] : !llvm.ptr)
-! CHECK: } -> !omp.iterated<!llvm.ptr>
-! CHECK-NOT: omp.iterator
-! CHECK: omp.task depend(
-! CHECK-SAME: taskdependin -> %[[IT_I]] : !omp.iterated<!llvm.ptr>) {
-
! Each locator uses its own iterator subset; c remains non-iterated.
subroutine depend_per_locator(m)
integer :: m
diff --git a/flang/test/Lower/OpenMP/task-affinity.f90 b/flang/test/Lower/OpenMP/task-affinity.f90
index 331570895b37d..645dd836f9687 100644
--- a/flang/test/Lower/OpenMP/task-affinity.f90
+++ b/flang/test/Lower/OpenMP/task-affinity.f90
@@ -259,41 +259,6 @@ subroutine task_affinity_poly()
! Iterator tests
-! The unused j range must not suppress a(i) when m < 3.
-subroutine affinity_unused_iterator(m)
- integer :: m
- integer :: a(4)
-
- !$omp task affinity(iterator(i = 1:2, j = 3:m) : a(i))
- !$omp end task
-end subroutine
-
-! CHECK-LABEL: func.func @_QPaffinity_unused_iterator(
-! CHECK: %[[A:.*]]:2 = hlfir.declare
-! CHECK-SAME: uniq_name("_QFaffinity_unused_iteratorEa")
-! CHECK: %[[M:.*]]:2 = hlfir.declare
-! CHECK-SAME: uniq_name("_QFaffinity_unused_iteratorEm")
-! CHECK: %[[I_LB:.*]] = arith.constant 1 : i32
-! CHECK: %[[I_UB:.*]] = arith.constant 2 : i32
-! CHECK: %[[I_STEP:.*]] = arith.constant 1 : i32
-! CHECK: %[[IT_I:.*]] = omp.iterator(%[[IV_I:.*]]: i32) =
-! CHECK-SAME: (%[[I_LB]] to %[[I_UB]] step %[[I_STEP]]) {
-! CHECK: fir.store %[[IV_I]] to %[[MEM_I:.*]] : !fir.ref<i32>
-! CHECK: %[[DECL_I:.*]]:2 = hlfir.declare %[[MEM_I]]
-! CHECK: %[[LD_I:.*]] = fir.load %[[DECL_I]]#0 : !fir.ref<i32>
-! CHECK: %[[IDX_I:.*]] = fir.convert %[[LD_I]] : (i32) -> i64
-! CHECK: %[[COOR_I:.*]] = hlfir.designate %[[A]]#0 (%[[IDX_I]])
-! CHECK: %[[SIZE_I:.*]] = arith.constant 4 : i64
-! CHECK: %[[PTR_I:.*]] = fir.convert %[[COOR_I]]
-! CHECK-SAME: (!fir.ref<i32>) -> !fir.ref<i8>
-! CHECK: %[[ENTRY_I:.*]] = omp.affinity_entry %[[PTR_I]], %[[SIZE_I]]
-! CHECK: omp.yield(%[[ENTRY_I]] :
-! CHECK-SAME: !omp.affinity_entry_ty<!fir.ref<i8>, i64>)
-! CHECK: } -> !omp.iterated<!omp.affinity_entry_ty<!fir.ref<i8>, i64>>
-! CHECK-NOT: omp.iterator
-! CHECK: omp.task affinity(%[[IT_I]] :
-! CHECK-SAME: !omp.iterated<!omp.affinity_entry_ty<!fir.ref<i8>, i64>>) {
-
! Each locator uses its own iterator subset; c remains non-iterated.
subroutine affinity_per_locator(m)
integer :: m
diff --git a/flang/test/Semantics/OpenMP/affinity-part-refs.f90 b/flang/test/Semantics/OpenMP/affinity-part-refs.f90
index e34ec287d71cd..1cf17e7227d5a 100644
--- a/flang/test/Semantics/OpenMP/affinity-part-refs.f90
+++ b/flang/test/Semantics/OpenMP/affinity-part-refs.f90
@@ -20,20 +20,11 @@ subroutine earlier_part_strides(a, k)
!$omp task affinity(a(1:8:2)%nested%field(1))
!$omp end task
!ERROR: 'a' in AFFINITY clause must not specify a stride
- !$omp task affinity(iterator(i=1:2): a(1:8:2)%nested%field(i))
- !$omp end task
- !ERROR: 'a' in AFFINITY clause must not specify a stride
!$omp task affinity(a(1:8:k)%nested%field(1))
!$omp end task
!ERROR: 'a' in AFFINITY clause must not specify a stride
- !$omp task affinity(iterator(i=1:2): a(1:8:k)%nested%field(i))
- !$omp end task
- !ERROR: 'a' in AFFINITY clause must not specify a stride
!$omp task affinity(a(::2)%nested%field(1))
!$omp end task
- !ERROR: 'a' in AFFINITY clause must not specify a stride
- !$omp task affinity(iterator(i=1:2): a(::2)%nested%field(i))
- !$omp end task
end subroutine
subroutine intermediate_part_stride(a)
diff --git a/flang/test/Semantics/OpenMP/substring-strides.f90 b/flang/test/Semantics/OpenMP/substring-strides.f90
index c79f27d83fab7..1dcb7885d5881 100644
--- a/flang/test/Semantics/OpenMP/substring-strides.f90
+++ b/flang/test/Semantics/OpenMP/substring-strides.f90
@@ -60,6 +60,7 @@ subroutine affinity_substring_strides(a, s)
!$omp end task
end subroutine
+! Representative DEPEND cases exercise the shared checks above.
subroutine depend_substring_strides(a, s)
type t
character(8) :: field
@@ -74,37 +75,10 @@ subroutine depend_substring_strides(a, s)
!$omp end task
!PORTABILITY: The use of substrings in OpenMP argument lists has been disallowed since OpenMP 5.2.
!ERROR: Cannot specify a step for a substring
- !$omp task depend(in: s(1::2))
- !$omp end task
- !PORTABILITY: The use of substrings in OpenMP argument lists has been disallowed since OpenMP 5.2.
- !ERROR: Cannot specify a step for a substring
- !$omp task depend(in: s(:8:2))
- !$omp end task
- !PORTABILITY: The use of substrings in OpenMP argument lists has been disallowed since OpenMP 5.2.
- !ERROR: Cannot specify a step for a substring
- !$omp task depend(in: a(1)%field(1:4:2))
- !$omp end task
- !PORTABILITY: The use of substrings in OpenMP argument lists has been disallowed since OpenMP 5.2.
- !ERROR: Cannot specify a step for a substring
- !$omp task depend(in: a(1:2)%field(1:4:2))
- !$omp end task
- !PORTABILITY: The use of substrings in OpenMP argument lists has been disallowed since OpenMP 5.2.
- !ERROR: Cannot specify a step for a substring
- !$omp task depend(in: a(1:2)%field(::2))
- !$omp end task
- !PORTABILITY: The use of substrings in OpenMP argument lists has been disallowed since OpenMP 5.2.
- !ERROR: Cannot specify a step for a substring
- !$omp task depend(in: a%field(1:4:2))
- !$omp end task
- !PORTABILITY: The use of substrings in OpenMP argument lists has been disallowed since OpenMP 5.2.
- !ERROR: Cannot specify a step for a substring
!$omp task depend(iterator(i=1:2), in: a(1:i)%field(1:4:2))
!$omp end task
- ! Without a step, these substrings remain accepted as an extension.
- !PORTABILITY: The use of substrings in OpenMP argument lists has been disallowed since OpenMP 5.2.
- !$omp task depend(in: a(1)%field(1:4))
- !$omp end task
+ ! Without a step, the substring remains accepted as an extension.
!PORTABILITY: The use of substrings in OpenMP argument lists has been disallowed since OpenMP 5.2.
!$omp task depend(in: a(1:2)%field(1:4))
!$omp end task
More information about the Mlir-commits
mailing list