[flang-commits] [flang] [flang][OpenMp] Fix LINEAR steps and ALLOCATABLE loop iteration variables (PR #234112)
via flang-commits
flang-commits at lists.llvm.org
Wed Oct 21 01:48:02 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>
fixes https://github.com/llvm/llvm-project/issues/233992 and
fixes https://github.com/llvm/llvm-project/issues/233990
---
Full diff: https://github.com/llvm/llvm-project/pull/234112.diff
8 Files Affected:
- (modified) flang/lib/Lower/OpenMP/ClauseProcessor.cpp (+2-2)
- (modified) flang/lib/Lower/OpenMP/OpenMP.cpp (+4-9)
- (modified) flang/lib/Lower/OpenMP/Utils.cpp (+14-2)
- (modified) flang/lib/Lower/OpenMP/Utils.h (+2)
- (modified) flang/test/Lower/OpenMP/lastprivate-iv.f90 (+6-7)
- (modified) flang/test/Lower/OpenMP/linear-allocatable.f90 (+20)
- (modified) flang/test/Lower/OpenMP/loop-pointer-variable.f90 (+8-10)
- (modified) flang/test/Lower/OpenMP/simd-linear.f90 (+27)
``````````diff
diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
index 34961d3d44ba2..43fa51dfd9832 100644
--- a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
+++ b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
@@ -1787,7 +1787,7 @@ bool ClauseProcessor::processLinear(
clause.t)) {
mlir::Value operand =
fir::getBase(converter.genExprValue(toEvExpr(*mod), stmtCtx));
- result.linearStepVars.append(objects.size(), operand);
+ result.linearStepVars.push_back(operand);
} else {
// If nothing is present, add the default step of 1.
fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
@@ -1795,7 +1795,7 @@ bool ClauseProcessor::processLinear(
mlir::Type integerTy = ty.isInteger() ? ty : firOpBuilder.getI32Type();
mlir::Value operand =
firOpBuilder.createIntegerConstant(currentLocation, integerTy, 1);
- result.linearStepVars.append(objects.size(), operand);
+ result.linearStepVars.push_back(operand);
}
// Determine the linear modifier:
diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index abe1df79f6aef..abb4c53b3b122 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -1518,7 +1518,7 @@ genLoopVars(mlir::Operation *op, lower::AbstractConverter &converter,
std::size_t loopVarTypeSize = 0;
for (const semantics::Symbol *arg : args)
- loopVarTypeSize = std::max(loopVarTypeSize, arg->GetUltimate().size());
+ loopVarTypeSize = std::max(loopVarTypeSize, getLoopVarSize(*arg));
mlir::Type loopVarType = getLoopVarType(converter, loopVarTypeSize);
llvm::SmallVector<mlir::Type> tiv(args.size(), loopVarType);
llvm::SmallVector<mlir::Location> locs(args.size(), loc);
@@ -2464,14 +2464,9 @@ static void genSimdImplicitLinear(
variable) != clauseOps.linearVars.end())
continue;
- // TODO: Implicit linearization is skipped if iv is a pointer
- // or an allocatable, due to potential mismatch between the linear
- // variable type (example !fir.ref<!fir.box<!fir.heap<i32>>>)
- // and the linear step size (example: i64). Handle this type mismatch
- // gracefully.
+ // TODO: Implicit linearization is skipped if iv is a pointer.
if (loopVar->test(Fortran::semantics::Symbol::Flag::OmpLinear) &&
- !(Fortran::semantics::IsAllocatableOrPointer(*loopVar) ||
- Fortran::semantics::IsAllocatableOrPointer(loopVar->GetUltimate()))) {
+ !Fortran::semantics::IsPointer(loopVar->GetUltimate())) {
mlir::Type ty = converter.genType(*loopVar);
typeAttrs.push_back(mlir::TypeAttr::get(ty));
if (semaCtx.langOptions().getOpenMPVersion() >= 52)
@@ -3075,7 +3070,7 @@ static void genCanonicalLoopNest(
converter.genExprValue(*semantics::GetExpr(bounds->Upper()), stmtCtx));
// Get the integer kind for the loop variable and cast the loop bounds.
- size_t loopVarTypeSize = bounds->Name().thing.symbol->GetUltimate().size();
+ size_t loopVarTypeSize = getLoopVarSize(*bounds->Name().thing.symbol);
mlir::Type loopVarType = getLoopVarType(converter, loopVarTypeSize);
loopVarTypes.push_back(loopVarType);
mlir::Value loopStepVar = [&]() {
diff --git a/flang/lib/Lower/OpenMP/Utils.cpp b/flang/lib/Lower/OpenMP/Utils.cpp
index 9e37c02eac3f1..87016d2022e53 100644
--- a/flang/lib/Lower/OpenMP/Utils.cpp
+++ b/flang/lib/Lower/OpenMP/Utils.cpp
@@ -145,6 +145,18 @@ mlir::Type getLoopVarType(lower::AbstractConverter &converter,
return converter.getFirOpBuilder().getIntegerType(loopVarTypeSize);
}
+std::size_t getLoopVarSize(const semantics::Symbol &sym) {
+ const semantics::Symbol &ultimate = sym.GetUltimate();
+ // The storage of an ALLOCATABLE or POINTER is its descriptor; use the kind.
+ if (semantics::IsAllocatableOrPointer(ultimate))
+ if (const semantics::DeclTypeSpec *type = ultimate.GetType())
+ if (const semantics::IntrinsicTypeSpec *intrinsic = type->AsIntrinsic())
+ if (std::optional<std::int64_t> kind =
+ evaluate::ToInt64(intrinsic->kind()))
+ return *kind;
+ return ultimate.size();
+}
+
semantics::Symbol *
getIterationVariableSymbol(const lower::pft::Evaluation &eval) {
return eval.visit(common::visitors{
@@ -897,8 +909,8 @@ void collectLoopRelatedInfo(
currentLocation, firOpBuilder.getIntegerType(32), 1));
}
iv.push_back(bounds->Name().thing.symbol);
- loopVarTypeSize = std::max(
- loopVarTypeSize, bounds->Name().thing.symbol->GetUltimate().size());
+ loopVarTypeSize =
+ std::max(loopVarTypeSize, getLoopVarSize(*bounds->Name().thing.symbol));
if (--collapseValue) {
doConstructEval = tryGetNestedDoConstruct(*doConstructEval);
// No DO construct left to descend into: COLLAPSE (or a tile SIZES list)
diff --git a/flang/lib/Lower/OpenMP/Utils.h b/flang/lib/Lower/OpenMP/Utils.h
index c769380aabbb0..16775f8facbc5 100644
--- a/flang/lib/Lower/OpenMP/Utils.h
+++ b/flang/lib/Lower/OpenMP/Utils.h
@@ -154,6 +154,8 @@ omp::ObjectList gatherObjectsOf(omp::Object derivedTypeMember,
mlir::Type getLoopVarType(lower::AbstractConverter &converter,
std::size_t loopVarTypeSize);
+std::size_t getLoopVarSize(const semantics::Symbol &sym);
+
semantics::Symbol *
getIterationVariableSymbol(const lower::pft::Evaluation &eval);
diff --git a/flang/test/Lower/OpenMP/lastprivate-iv.f90 b/flang/test/Lower/OpenMP/lastprivate-iv.f90
index f40cfbc587fb0..bc0b2a0ead4c2 100644
--- a/flang/test/Lower/OpenMP/lastprivate-iv.f90
+++ b/flang/test/Lower/OpenMP/lastprivate-iv.f90
@@ -96,27 +96,26 @@ subroutine lastprivate_iv_i1
end subroutine
!CHECK: omp.wsloop private(@_QFlastprivate_iv_pointerEi_private_box_ptr_i32 %{{.*}}#0 -> %[[PRIVATE_IV:.*]] : !fir.ref<!fir.box<!fir.ptr<i32>>>) {
-!CHECK: omp.loop_nest (%[[LOOP_INDEX:.*]]) : i64
+!CHECK: omp.loop_nest (%[[LOOP_INDEX:.*]]) : i32
!CHECK: %[[PRIVATE_IV_DECL:.*]]:2 = hlfir.declare %[[PRIVATE_IV]] uniq_name("_QFlastprivate_iv_pointerEi") fortran_attrs<pointer> : (!fir.ref<!fir.box<!fir.ptr<i32>>>) -> (!fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.ref<!fir.box<!fir.ptr<i32>>>)
-!CHECK: %[[LOOP_INDEX_INCR:.*]] = arith.addi %[[LOOP_INDEX]], %{{.*}} : i64
+!CHECK: %[[LOOP_INDEX_INCR:.*]] = arith.addi %[[LOOP_INDEX]], %{{.*}} : i32
!CHECK: fir.if %{{.*}} {
!CHECK: %[[PRIVATE_IV_BOX:.*]] = fir.load %[[PRIVATE_IV_DECL]]#0 : !fir.ref<!fir.box<!fir.ptr<i32>>>
!CHECK: %[[PRIVATE_IV_ADDR:.*]] = fir.box_addr %[[PRIVATE_IV_BOX]] : (!fir.box<!fir.ptr<i32>>) -> !fir.ptr<i32>
-!CHECK: hlfir.assign %[[LOOP_INDEX_INCR]] to %[[PRIVATE_IV_ADDR]] : i64, !fir.ptr<i32>
+!CHECK: hlfir.assign %[[LOOP_INDEX_INCR]] to %[[PRIVATE_IV_ADDR]] : i32, !fir.ptr<i32>
!CHECK: }
!CHECK: omp.yield
!CHECK: }
!CHECK: }
!CHECK-FIR: omp.wsloop private(@_QFlastprivate_iv_pointerEi_private_box_ptr_i32 %{{.*}} -> %[[PRIVATE_IV:.*]] : !fir.ref<!fir.box<!fir.ptr<i32>>>) {
-!CHECK-FIR: omp.loop_nest (%[[LOOP_INDEX:.*]]) : i64
+!CHECK-FIR: omp.loop_nest (%[[LOOP_INDEX:.*]]) : i32
!CHECK-FIR: %[[PRIVATE_IV_DECL:.*]] = fir.declare %[[PRIVATE_IV]] uniq_name("_QFlastprivate_iv_pointerEi") fortran_attrs<pointer> : (!fir.ref<!fir.box<!fir.ptr<i32>>>) -> !fir.ref<!fir.box<!fir.ptr<i32>>>
-!CHECK-FIR: %[[LOOP_INDEX_INCR:.*]] = arith.addi %[[LOOP_INDEX]], %{{.*}} : i64
+!CHECK-FIR: %[[LOOP_INDEX_INCR:.*]] = arith.addi %[[LOOP_INDEX]], %{{.*}} : i32
!CHECK-FIR: fir.if %{{.*}} {
!CHECK-FIR: %[[PRIVATE_IV_BOX:.*]] = fir.load %[[PRIVATE_IV_DECL]] : !fir.ref<!fir.box<!fir.ptr<i32>>>
!CHECK-FIR: %[[PRIVATE_IV_ADDR:.*]] = fir.box_addr %[[PRIVATE_IV_BOX]] : (!fir.box<!fir.ptr<i32>>) -> !fir.ptr<i32>
-!CHECK-FIR: %[[LOOP_INDEX_CVT:.*]] = fir.convert %[[LOOP_INDEX_INCR]] : (i64) -> i32
-!CHECK-FIR: fir.store %[[LOOP_INDEX_CVT]] to %[[PRIVATE_IV_ADDR]] : !fir.ptr<i32>
+!CHECK-FIR: fir.store %[[LOOP_INDEX_INCR]] to %[[PRIVATE_IV_ADDR]] : !fir.ptr<i32>
!CHECK-FIR: }
!CHECK-FIR: omp.yield
!CHECK-FIR: }
diff --git a/flang/test/Lower/OpenMP/linear-allocatable.f90 b/flang/test/Lower/OpenMP/linear-allocatable.f90
index b6b62f5cf6872..8a9df5b6ab900 100644
--- a/flang/test/Lower/OpenMP/linear-allocatable.f90
+++ b/flang/test/Lower/OpenMP/linear-allocatable.f90
@@ -2,6 +2,9 @@
! RUN: %flang_fc1 -emit-hlfir -fopenmp -o - %s 2>&1 | FileCheck %s
! RUN: bbc -emit-hlfir -fopenmp -o - %s 2>&1 | FileCheck %s
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -o /dev/null %s 2>&1 | FileCheck %s --check-prefix=WARN --allow-empty
+
+! WARN-NOT: warning
! CHECK-LABEL: omp.private {type = linear} @_QFsimd_linear_allocatableEa_linear_box_heap_i32 : !fir.box<!fir.heap<i32>> init {
! CHECK: fir.allocmem i32
@@ -111,3 +114,20 @@ subroutine original_used_after_loop()
!$omp end simd
a = 5
end subroutine
+
+! An allocatable loop iteration variable is implicitly linear.
+! CHECK-LABEL: func.func @_QPimplicit_allocatable_iv
+! CHECK: %[[I:.*]]:2 = hlfir.declare %{{.*}} uniq_name("_QFimplicit_allocatable_ivEi") fortran_attrs<allocatable>
+! CHECK: omp.simd linear(@_QFimplicit_allocatable_ivEi_linear_box_heap_i32 %[[I]]#0 -> %{{.*}} : !fir.ref<!fir.box<!fir.heap<i32>>> = %{{.*}} : i32) linear_var_types([i32])
+! CHECK: omp.loop_nest (%{{.*}}) : i32 =
+subroutine implicit_allocatable_iv()
+ integer, allocatable :: i
+ integer :: k
+ allocate(i)
+ k = 0
+ !$omp simd
+ do i = 1, 4
+ k = k + 1
+ end do
+ !$omp end simd
+end subroutine
diff --git a/flang/test/Lower/OpenMP/loop-pointer-variable.f90 b/flang/test/Lower/OpenMP/loop-pointer-variable.f90
index 0738e849cc7a7..75c26fe610799 100644
--- a/flang/test/Lower/OpenMP/loop-pointer-variable.f90
+++ b/flang/test/Lower/OpenMP/loop-pointer-variable.f90
@@ -10,17 +10,15 @@ program loop_var
!CHECK: %[[IA1:.*]]:2 = hlfir.declare %{{.*}} uniq_name("_QFEia1") fortran_attrs<allocatable>
!CHECK: omp.wsloop private(@_QFEip1_private_box_ptr_i32 %{{.*}}#0 -> %[[IP1_PVT:.*]], @_QFEip2_private_box_ptr_i32 %{{.*}}#0 -> %[[IP2_PVT:.*]] : !fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.ref<!fir.box<!fir.ptr<i32>>>)
-!CHECK: omp.loop_nest (%[[IP1_INDX:.*]], %[[IP2_INDX:.*]]) : i64 = ({{.*}}) to ({{.*}}) inclusive step ({{.*}})
+!CHECK: omp.loop_nest (%[[IP1_INDX:.*]], %[[IP2_INDX:.*]]) : i32 = ({{.*}}) to ({{.*}}) inclusive step ({{.*}})
!CHECK: %[[IP1_PVT_DECL:.*]]:2 = hlfir.declare %[[IP1_PVT]] uniq_name("_QFEip1") fortran_attrs<pointer> : (!fir.ref<!fir.box<!fir.ptr<i32>>>) -> (!fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.ref<!fir.box<!fir.ptr<i32>>>)
!CHECK: %[[IP2_PVT_DECL:.*]]:2 = hlfir.declare %[[IP2_PVT]] uniq_name("_QFEip2") fortran_attrs<pointer> : (!fir.ref<!fir.box<!fir.ptr<i32>>>) -> (!fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.ref<!fir.box<!fir.ptr<i32>>>)
-!CHECK: %[[IP1:.*]] = fir.convert %[[IP1_INDX]] : (i64) -> i32
!CHECK: %[[IP1_BOX:.*]] = fir.load %[[IP1_PVT_DECL]]#0 : !fir.ref<!fir.box<!fir.ptr<i32>>>
!CHECK: %[[IP1_ADDR:.*]] = fir.box_addr %[[IP1_BOX]] : (!fir.box<!fir.ptr<i32>>) -> !fir.ptr<i32>
-!CHECK: hlfir.assign %[[IP1]] to %[[IP1_ADDR]] : i32, !fir.ptr<i32>
-!CHECK: %[[IP2:.*]] = fir.convert %[[IP2_INDX]] : (i64) -> i32
+!CHECK: hlfir.assign %[[IP1_INDX]] to %[[IP1_ADDR]] : i32, !fir.ptr<i32>
!CHECK: %[[IP2_BOX:.*]] = fir.load %[[IP2_PVT_DECL]]#0 : !fir.ref<!fir.box<!fir.ptr<i32>>>
!CHECK: %[[IP2_ADDR:.*]] = fir.box_addr %[[IP2_BOX]] : (!fir.box<!fir.ptr<i32>>) -> !fir.ptr<i32>
-!CHECK: hlfir.assign %[[IP2]] to %[[IP2_ADDR]] : i32, !fir.ptr<i32>
+!CHECK: hlfir.assign %[[IP2_INDX]] to %[[IP2_ADDR]] : i32, !fir.ptr<i32>
!CHECK: omp.yield
!$omp do collapse(2)
do ip1 = 1, 10
@@ -29,12 +27,12 @@ program loop_var
end do
!$omp end do
-!CHECK: omp.simd
-!CHECK: omp.loop_nest (%[[IA1_INDX:.*]]) : i64 = ({{.*}}) to ({{.*}}) inclusive step ({{.*}})
-!CHECK: %[[IA1_INDX_I32:.*]] = fir.convert %[[IA1_INDX]] : (i64) -> i32
-!CHECK: %[[IA1_BOX:.*]] = fir.load %[[IA1]]#0 : !fir.ref<!fir.box<!fir.heap<i32>>>
+!CHECK: omp.simd linear(@_QFEia1_linear_box_heap_i32 %[[IA1]]#0 -> %[[IA1_PVT:.*]] : !fir.ref<!fir.box<!fir.heap<i32>>> = %{{.*}} : i32) linear_var_types([i32])
+!CHECK: omp.loop_nest (%[[IA1_INDX:.*]]) : i32 = ({{.*}}) to ({{.*}}) inclusive step ({{.*}})
+!CHECK: %[[IA1_PVT_DECL:.*]]:2 = hlfir.declare %[[IA1_PVT]] uniq_name("_QFEia1") fortran_attrs<allocatable>
+!CHECK: %[[IA1_BOX:.*]] = fir.load %[[IA1_PVT_DECL]]#0 : !fir.ref<!fir.box<!fir.heap<i32>>>
!CHECK: %[[IA1_ADDR:.*]] = fir.box_addr %[[IA1_BOX]] : (!fir.box<!fir.heap<i32>>) -> !fir.heap<i32>
-!CHECK: hlfir.assign %[[IA1_INDX_I32]] to %[[IA1_ADDR]] : i32, !fir.heap<i32>
+!CHECK: hlfir.assign %[[IA1_INDX]] to %[[IA1_ADDR]] : i32, !fir.heap<i32>
!CHECK: omp.yield
!$omp simd
do ia1 = 1, 10
diff --git a/flang/test/Lower/OpenMP/simd-linear.f90 b/flang/test/Lower/OpenMP/simd-linear.f90
index ef2fcafff39bf..8f30e404d76c3 100644
--- a/flang/test/Lower/OpenMP/simd-linear.f90
+++ b/flang/test/Lower/OpenMP/simd-linear.f90
@@ -105,3 +105,30 @@ subroutine non_i32_type
!CHECK: }
!IMPLICIT: }
end subroutine
+
+!CHECK-LABEL: func.func @_QPmultiple_items
+!CHECK: %[[A:.*]]:2 = hlfir.declare {{.*}} uniq_name("_QFmultiple_itemsEa")
+!CHECK: %[[B:.*]]:2 = hlfir.declare {{.*}} uniq_name("_QFmultiple_itemsEb")
+!CHECK: %[[C:.*]]:2 = hlfir.declare {{.*}} uniq_name("_QFmultiple_itemsEc")
+!CHECK: %[[TWO_A:.*]] = arith.constant 2 : i32
+!CHECK: %[[TWO_B:.*]] = arith.constant 2 : i32
+!CHECK: %[[THREE:.*]] = arith.constant 3 : i32
+!CHECK: omp.simd linear(val(@{{[^ ]+}} %[[A]]#0 -> %{{[^ ]+}} : !fir.ref<i32> = %[[TWO_A]] : i32), val(@{{[^ ]+}} %[[B]]#0 -> %{{[^ ]+}} : !fir.ref<i32> = %[[TWO_B]] : i32), val(@{{[^ ]+}} %[[C]]#0 -> %{{[^ ]+}} : !fir.ref<i32> = %[[THREE]] : i32)) linear_var_types([i32, i32, i32])
+
+!IMPLICIT-LABEL: func.func @_QPmultiple_items
+!IMPLICIT: %[[I:.*]]:2 = hlfir.declare {{.*}} uniq_name("_QFmultiple_itemsEi")
+!IMPLICIT: %[[TWO_A:.*]] = arith.constant 2 : i32
+!IMPLICIT: %[[TWO_B:.*]] = arith.constant 2 : i32
+!IMPLICIT: %[[THREE:.*]] = arith.constant 3 : i32
+!IMPLICIT: %{{.*}} = arith.constant 1 : i32
+!IMPLICIT: %{{.*}} = arith.constant 4 : i32
+!IMPLICIT: %[[STEP:.*]] = arith.constant 1 : i32
+!IMPLICIT: omp.simd linear({{.*}} = %[[TWO_A]] : i32, {{.*}} = %[[TWO_B]] : i32, {{.*}} = %[[THREE]] : i32, @{{[^ ]+}} %[[I]]#0 -> %{{[^ ]+}} : !fir.ref<i32> = %[[STEP]] : i32)
+subroutine multiple_items
+ implicit none
+ integer :: a, b, c, i
+ !$omp simd linear(a,b:2) linear(c:3)
+ do i = 1, 4
+ end do
+ !$omp end simd
+end subroutine
``````````
</details>
https://github.com/llvm/llvm-project/pull/234112
More information about the flang-commits
mailing list