[flang-commits] [flang] [flang][OpenMP] Support ALLOCATABLE list items in LINEAR (PR #228827)
via flang-commits
flang-commits at lists.llvm.org
Sat Oct 3 22:26:11 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-flang-fir-hlfir
Author: Aditya Trivedi (adit4443ya)
<details>
<summary>Changes</summary>
Pass the allocatable's data address as the linear variable so it matches linear_var_types, and rebind the symbol in the loop body to a descriptor over that address so the body uses the private copy.
Fixes #<!-- -->182401
---
Full diff: https://github.com/llvm/llvm-project/pull/228827.diff
3 Files Affected:
- (modified) flang/lib/Lower/OpenMP/ClauseProcessor.cpp (+8-1)
- (modified) flang/lib/Lower/OpenMP/OpenMP.cpp (+55)
- (added) flang/test/Lower/OpenMP/linear-allocatable.f90 (+90)
``````````diff
diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
index e41223b5b16c0..0b5b3e73010b3 100644
--- a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
+++ b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
@@ -1804,7 +1804,14 @@ bool ClauseProcessor::processLinear(mlir::omp::LinearClauseOps &result,
for (const omp::Object &object : objects) {
semantics::Symbol *sym = object.sym();
- const mlir::Value variable = converter.getSymbolAddress(*sym);
+ mlir::Value variable = converter.getSymbolAddress(*sym);
+ // Pass an allocatable's data address so it matches linear_var_types.
+ if (!isDeclareSimd && semantics::IsAllocatable(sym->GetUltimate())) {
+ fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
+ mlir::Location loc = converter.getCurrentLocation();
+ mlir::Value box = fir::LoadOp::create(firOpBuilder, loc, variable);
+ variable = fir::BoxAddrOp::create(firOpBuilder, loc, box);
+ }
result.linearVars.push_back(variable);
mlir::Type ty = converter.genType(*sym);
typeAttrs.push_back(mlir::TypeAttr::get(ty));
diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index 99a7882a658c8..23f0605f29318 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -3030,6 +3030,60 @@ genFlushOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
operandRange);
}
+/// Rebind linear allocatables to an in-loop descriptor over the linear address.
+static void bindLinearAllocatables(
+ lower::AbstractConverter &converter, mlir::Location loc,
+ const ConstructQueue &queue,
+ llvm::ArrayRef<std::pair<mlir::omp::BlockArgOpenMPOpInterface,
+ const ObjectEntryBlockArgs &>>
+ wrapperArgs) {
+ llvm::SmallVector<mlir::Value> linearVars;
+ for (auto [argGeneratingOp, blockArgs] : wrapperArgs) {
+ mlir::Operation *wrapperOp = argGeneratingOp.getOperation();
+ if (auto simdOp = mlir::dyn_cast<mlir::omp::SimdOp>(wrapperOp))
+ llvm::append_range(linearVars, simdOp.getLinearVars());
+ else if (auto wsloopOp = mlir::dyn_cast<mlir::omp::WsloopOp>(wrapperOp))
+ llvm::append_range(linearVars, wsloopOp.getLinearVars());
+ }
+ if (linearVars.empty())
+ return;
+
+ fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
+ llvm::SmallPtrSet<const semantics::Symbol *, 4> boundSyms;
+ for (const UnitConstruct &unit : queue) {
+ for (const Clause &clause : unit.clauses) {
+ const auto *linear = std::get_if<clause::Linear>(&clause.u);
+ if (!linear)
+ continue;
+ for (const Object &object : std::get<ObjectList>(linear->t)) {
+ const semantics::Symbol *sym = object.sym();
+ if (!semantics::IsAllocatable(sym->GetUltimate()) ||
+ !boundSyms.insert(sym).second)
+ continue;
+
+ mlir::Value descAddr = converter.getSymbolAddress(*sym);
+ auto *dataAddr = llvm::find_if(linearVars, [&](mlir::Value var) {
+ auto boxAddr = var.getDefiningOp<fir::BoxAddrOp>();
+ auto load =
+ boxAddr ? boxAddr.getVal().getDefiningOp<fir::LoadOp>() : nullptr;
+ return load && load.getMemref() == descAddr;
+ });
+ if (dataAddr == linearVars.end())
+ continue;
+
+ mlir::Type boxType = fir::unwrapRefType(descAddr.getType());
+ mlir::Value box =
+ fir::EmboxOp::create(firOpBuilder, loc, boxType, *dataAddr);
+ mlir::Value newDescAddr = firOpBuilder.createTemporary(loc, boxType);
+ fir::StoreOp::create(firOpBuilder, loc, box, newDescAddr);
+ converter.bindSymbol(
+ *sym, fir::MutableBoxValue(newDescAddr, /*lenParameters=*/{},
+ /*mutableProperties=*/{}));
+ }
+ }
+ }
+}
+
static mlir::omp::LoopNestOp genLoopNestOp(
lower::AbstractConverter &converter, lower::SymMap &symTable,
semantics::SemanticsContext &semaCtx, lower::pft::Evaluation &eval,
@@ -3043,6 +3097,7 @@ static mlir::omp::LoopNestOp genLoopNestOp(
llvm::function_ref<void(mlir::Operation *)> loopPostIvCb = nullptr) {
auto ivCallback = [&](mlir::Operation *op) {
genLoopVars(op, converter, loc, iv, wrapperArgs);
+ bindLinearAllocatables(converter, loc, queue, wrapperArgs);
if (loopPostIvCb)
loopPostIvCb(op);
return llvm::SmallVector<const semantics::Symbol *>(iv);
diff --git a/flang/test/Lower/OpenMP/linear-allocatable.f90 b/flang/test/Lower/OpenMP/linear-allocatable.f90
new file mode 100644
index 0000000000000..c4ee243fce90c
--- /dev/null
+++ b/flang/test/Lower/OpenMP/linear-allocatable.f90
@@ -0,0 +1,90 @@
+! LINEAR on an allocatable: data address operand, rebuilt descriptor in body.
+
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -o - %s 2>&1 | FileCheck %s
+! RUN: bbc -emit-hlfir -fopenmp -o - %s 2>&1 | FileCheck %s
+
+! CHECK-LABEL: func.func @_QPsimd_linear_allocatable
+! CHECK: %[[A:.*]]:2 = hlfir.declare %{{.*}} {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFsimd_linear_allocatableEa"}
+! CHECK: %[[BOX:.*]] = fir.load %[[A]]#0 : !fir.ref<!fir.box<!fir.heap<i32>>>
+! CHECK: %[[ADDR:.*]] = fir.box_addr %[[BOX]] : (!fir.box<!fir.heap<i32>>) -> !fir.heap<i32>
+! CHECK: omp.simd linear(%[[ADDR]] : !fir.heap<i32> = %{{.*}} : i32
+! CHECK-SAME: linear_var_types([i32
+! CHECK: omp.loop_nest
+! CHECK: %[[NEW_BOX:.*]] = fir.embox %[[ADDR]] : (!fir.heap<i32>) -> !fir.box<!fir.heap<i32>>
+! CHECK: fir.store %[[NEW_BOX]] to %[[NEW_DESC:.*]] : !fir.ref<!fir.box<!fir.heap<i32>>>
+! CHECK: %[[PRIV_A:.*]]:2 = hlfir.declare %[[NEW_DESC]] {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFsimd_linear_allocatableEa"}
+! CHECK: hlfir.assign %{{.*}} to %[[PRIV_A]]#0 realloc : i32, !fir.ref<!fir.box<!fir.heap<i32>>>
+! CHECK: omp.yield
+subroutine simd_linear_allocatable()
+ integer, allocatable :: a
+ integer :: i
+ allocate(a)
+ a = 0
+ !$omp simd linear(a)
+ do i = 1, 2
+ a = 2
+ end do
+ !$omp end simd
+end subroutine
+
+! CHECK-LABEL: func.func @_QPdo_linear_allocatable
+! CHECK: %[[A:.*]]:2 = hlfir.declare %{{.*}} {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFdo_linear_allocatableEa"}
+! CHECK: %[[BOX:.*]] = fir.load %[[A]]#0 : !fir.ref<!fir.box<!fir.heap<i32>>>
+! CHECK: %[[ADDR:.*]] = fir.box_addr %[[BOX]] : (!fir.box<!fir.heap<i32>>) -> !fir.heap<i32>
+! CHECK: omp.wsloop linear(%[[ADDR]] : !fir.heap<i32> = %{{.*}} : i32
+! CHECK: omp.loop_nest
+! CHECK: %[[NEW_BOX:.*]] = fir.embox %[[ADDR]] : (!fir.heap<i32>) -> !fir.box<!fir.heap<i32>>
+! CHECK: fir.store %[[NEW_BOX]] to %[[NEW_DESC:.*]] : !fir.ref<!fir.box<!fir.heap<i32>>>
+! CHECK: %[[PRIV_A:.*]]:2 = hlfir.declare %[[NEW_DESC]] {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFdo_linear_allocatableEa"}
+! CHECK: hlfir.assign %{{.*}} to %[[PRIV_A]]#0 realloc : i32, !fir.ref<!fir.box<!fir.heap<i32>>>
+subroutine do_linear_allocatable()
+ integer, allocatable :: a
+ integer :: i
+ allocate(a)
+ a = 0
+ !$omp parallel do linear(a:2)
+ do i = 1, 10
+ a = a + 1
+ end do
+ !$omp end parallel do
+end subroutine
+
+! Composite: the linear operand moves to omp.wsloop.
+! CHECK-LABEL: func.func @_QPdo_simd_linear_allocatable
+! CHECK: %[[ADDR:.*]] = fir.box_addr %{{.*}} : (!fir.box<!fir.heap<i64>>) -> !fir.heap<i64>
+! CHECK: omp.wsloop linear(%[[ADDR]] : !fir.heap<i64> = %{{.*}} : i64
+! CHECK: omp.simd
+! CHECK: omp.loop_nest
+! CHECK: %[[NEW_BOX:.*]] = fir.embox %[[ADDR]] : (!fir.heap<i64>) -> !fir.box<!fir.heap<i64>>
+! CHECK: fir.store %[[NEW_BOX]] to %[[NEW_DESC:.*]] : !fir.ref<!fir.box<!fir.heap<i64>>>
+! CHECK: hlfir.declare %[[NEW_DESC]] {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFdo_simd_linear_allocatableEa"}
+subroutine do_simd_linear_allocatable()
+ integer(8), allocatable :: a
+ integer :: i
+ allocate(a)
+ a = 0
+ !$omp do simd linear(a)
+ do i = 1, 10
+ a = a + 1
+ end do
+ !$omp end do simd
+end subroutine
+
+! The original descriptor is used after the loop.
+! CHECK-LABEL: func.func @_QPoriginal_used_after_loop
+! CHECK: %[[A:.*]]:2 = hlfir.declare %{{.*}} {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QForiginal_used_after_loopEa"}
+! CHECK: omp.simd linear
+! CHECK: }
+! CHECK: hlfir.assign %{{.*}} to %[[A]]#0 realloc : i32, !fir.ref<!fir.box<!fir.heap<i32>>>
+subroutine original_used_after_loop()
+ integer, allocatable :: a
+ integer :: i
+ allocate(a)
+ a = 0
+ !$omp simd linear(a)
+ do i = 1, 2
+ a = 2
+ end do
+ !$omp end simd
+ a = 5
+end subroutine
``````````
</details>
https://github.com/llvm/llvm-project/pull/228827
More information about the flang-commits
mailing list