[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:01 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-flang-openmp

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