[flang-commits] [flang] [mlir] Reland "[flang][OpenMP] Fix lowering of LINEAR iteration variables (#188851)" (PR #194623)
Leandro Lupori via flang-commits
flang-commits at lists.llvm.org
Tue Apr 28 06:36:30 PDT 2026
https://github.com/luporl created https://github.com/llvm/llvm-project/pull/194623
Linear iteration variables were being treated as private. This fixes
one of the issues reported in #170784.
The regressions in the OpenMP V&V and Fujitsu testsuites happened
because the users iterator was apparently becoming invalid, after one of
its uses was replaced. This was fixed by making a copy of the list of
users.
>From 1fc3ba9351b48e0100dc363d1717ecaa40c2a16c Mon Sep 17 00:00:00 2001
From: Leandro Lupori <leandro.lupori at linaro.org>
Date: Fri, 24 Apr 2026 20:32:36 +0000
Subject: [PATCH 1/2] Reland "[flang][OpenMP] Fix lowering of LINEAR iteration
variables (#188851)"
Linear iteration variables were being treated as private. This fixes
one of the issues reported in #170784.
The regressions in the OpenMP V&V and Fujitsu testsuites happened
because the users iterator was apparently becoming invalid, after one of
its uses was replaced. This was fixed by making a copy of the list of
users.
---
.../lib/Lower/OpenMP/DataSharingProcessor.cpp | 13 ++--
flang/lib/Lower/OpenMP/OpenMP.cpp | 5 +-
.../Lower/OpenMP/composite_simd_linear.f90 | 25 ++++----
.../OpenMP/distribute-parallel-do-simd.f90 | 25 ++++----
flang/test/Lower/OpenMP/distribute-simd.f90 | 6 +-
flang/test/Lower/OpenMP/linear_modifier.f90 | 4 +-
.../Lower/OpenMP/loop-pointer-variable.f90 | 10 +--
flang/test/Lower/OpenMP/ordered-simd.f90 | 4 +-
flang/test/Lower/OpenMP/wsloop-simd.f90 | 10 +--
.../OpenMP/OpenMPToLLVMIRTranslation.cpp | 64 ++++++++++++++-----
.../Target/LLVMIR/openmp-simd-linear.mlir | 34 ++++++++++
11 files changed, 135 insertions(+), 65 deletions(-)
create mode 100644 mlir/test/Target/LLVMIR/openmp-simd-linear.mlir
diff --git a/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp b/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp
index e392497d30de7..561d3bb906aed 100644
--- a/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp
+++ b/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp
@@ -237,11 +237,6 @@ void DataSharingProcessor::collectSymbolsForPrivatization() {
// Such cases are suggested to be clearly documented and explained
// instead of being silently skipped
auto isException = [&](const Fortran::semantics::Symbol *sym) -> bool {
- // `OmpPreDetermined` symbols cannot be exceptions since
- // their privatized symbols are heavily used in FIR.
- if (sym->test(Fortran::semantics::Symbol::Flag::OmpPreDetermined))
- return false;
-
// The handling of linear clause is deferred to the OpenMP
// IRBuilder which is responsible for all its aspects,
// including privatization. Privatizing linear variables at this point would
@@ -265,6 +260,11 @@ void DataSharingProcessor::collectSymbolsForPrivatization() {
// draw a relation between %linear and %arg0. Hence skip.
if (sym->test(Fortran::semantics::Symbol::Flag::OmpLinear))
return true;
+
+ // `OmpPreDetermined` symbols cannot be exceptions since
+ // their privatized symbols are heavily used in FIR.
+ if (sym->test(Fortran::semantics::Symbol::Flag::OmpPreDetermined))
+ return false;
return false;
};
@@ -538,6 +538,9 @@ void DataSharingProcessor::collectPrivatizedSymbols(
for (const auto *sym : allSymbols) {
if (semantics::omp::IsPrivatizable(*sym) &&
+ // Linear symbols are privatized by OpenMP IRBuilder. See comments
+ // in collectSymbolsForPrivatization() for more details.
+ !sym->test(semantics::Symbol::Flag::OmpLinear) &&
!symbolsInNestedRegions.contains(sym) &&
!explicitlyPrivatizedSymbols.contains(sym) &&
shouldCollectSymbol(sym) && clauseScopes.contains(&sym->owner())) {
diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index fd1a8b9cd5a42..ad4fdeebbfe2c 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -717,7 +717,10 @@ static mlir::Operation *
createAndSetPrivatizedLoopVar(lower::AbstractConverter &converter,
mlir::Location loc, mlir::Value indexVal,
const semantics::Symbol *sym) {
- assert(converter.isPresentShallowLookup(*sym) &&
+ // The handling of linear symbols is deferred to the OpenMP IRBuilder,
+ // which is responsible for all its aspects, including privatization.
+ assert((converter.isPresentShallowLookup(*sym) ||
+ sym->test(semantics::Symbol::Flag::OmpLinear)) &&
"Expected symbol to be in symbol table.");
return setLoopVar(converter, loc, indexVal, sym);
}
diff --git a/flang/test/Lower/OpenMP/composite_simd_linear.f90 b/flang/test/Lower/OpenMP/composite_simd_linear.f90
index 38ef80292326d..ff290fc3dc4af 100644
--- a/flang/test/Lower/OpenMP/composite_simd_linear.f90
+++ b/flang/test/Lower/OpenMP/composite_simd_linear.f90
@@ -9,8 +9,8 @@ subroutine do_simd
!CHECK: %{{.*}} = arith.constant 1 : i32
!CHECK: %[[IV_STEP:.*]] = arith.constant 1 : i32
!CHECK: omp.wsloop {
-!DEFAULT: omp.simd linear(%[[X]]#0 : !fir.ref<i32> = %[[CONST]] : i32, %[[I]]#0 : !fir.ref<i32> = %[[IV_STEP]] : i32) private(@_QFdo_simdEi_private_i32 {{.*}} -> %arg0 : !fir.ref<i32>) {
-!OPENMP52: omp.simd linear(val(%[[X]]#0 : !fir.ref<i32> = %[[CONST]] : i32), val(%[[I]]#0 : !fir.ref<i32> = %[[IV_STEP]] : i32)) private(@_QFdo_simdEi_private_i32 {{.*}} -> %arg0 : !fir.ref<i32>) {
+!DEFAULT: omp.simd linear(%[[X]]#0 : !fir.ref<i32> = %[[CONST]] : i32, %[[I]]#0 : !fir.ref<i32> = %[[IV_STEP]] : i32) {
+!OPENMP52: omp.simd linear(val(%[[X]]#0 : !fir.ref<i32> = %[[CONST]] : i32), val(%[[I]]#0 : !fir.ref<i32> = %[[IV_STEP]] : i32)) {
!CHECK: }
!CHECK: } {linear_var_types = [i32, i32], omp.composite}
!CHECK: } {omp.composite}
@@ -23,10 +23,11 @@ end subroutine do_simd
subroutine distribute_simd
+!CHECK: %[[I:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFdistribute_simdEi"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
!CHECK: omp.teams {
-!CHECK: omp.distribute private(@_QFdistribute_simdEi_private_i32 {{.*}} -> %[[ARG0:.*]] : !fir.ref<i32>) {
+!CHECK: omp.distribute {
!DEFAULT: omp.simd linear({{.*}}) {
-!OPENMP52: omp.simd linear(val({{.*}})) private(@_QFdistribute_simdEi_private_i32 %[[ARG0]] -> {{.*}} : !fir.ref<i32>) {
+!OPENMP52: omp.simd linear(val({{.*}})) {
!CHECK: } {linear_var_types = [i32], omp.composite}
!CHECK: } {omp.composite}
integer :: i
@@ -47,8 +48,8 @@ subroutine distribute_parallel_do
!CHECK: %[[CONST]] = arith.constant 1 : i32
!CHECK: omp.distribute {
!CHECK: omp.wsloop {
-!DEFAULT: omp.simd linear(%[[I]]#0 : !fir.ref<i32> = %[[CONST]] : i32) private(@_QFdistribute_parallel_doEi_private_i32 %[[I]]#0 -> %arg0 : !fir.ref<i32>) {
-!OPENMP52: omp.simd linear(val(%[[I]]#0 : !fir.ref<i32> = %[[CONST]] : i32)) private(@_QFdistribute_parallel_doEi_private_i32 %[[I]]#0 -> %arg0 : !fir.ref<i32>) {
+!DEFAULT: omp.simd linear(%[[I]]#0 : !fir.ref<i32> = %[[CONST]] : i32) {
+!OPENMP52: omp.simd linear(val(%[[I]]#0 : !fir.ref<i32> = %[[CONST]] : i32)) {
!$omp teams
!$omp distribute parallel do simd linear(i:1)
do i = 1, N
@@ -66,8 +67,8 @@ subroutine parallel_do
!CHECK: %{{.*}} = arith.constant 1 : i32
!CHECK: %[[IV_STEP:.*]] = arith.constant 1 : i32
!CHECK: omp.wsloop {
-!DEFAULT: omp.simd linear(%[[X]]#0 : !fir.ref<i32> = %[[LINEAR_STEP]] : i32, %[[I]]#0 : !fir.ref<i32> = %[[IV_STEP]] : i32) private(@_QFparallel_doEi_private_i32 %[[I]]#0 -> %arg0 : !fir.ref<i32>) {
-!OPENMP52: omp.simd linear(val(%[[X]]#0 : !fir.ref<i32> = %[[LINEAR_STEP]] : i32), val(%[[I]]#0 : !fir.ref<i32> = %[[IV_STEP]] : i32)) private(@_QFparallel_doEi_private_i32 %[[I]]#0 -> %arg0 : !fir.ref<i32>) {
+!DEFAULT: omp.simd linear(%[[X]]#0 : !fir.ref<i32> = %[[LINEAR_STEP]] : i32, %[[I]]#0 : !fir.ref<i32> = %[[IV_STEP]] : i32) {
+!OPENMP52: omp.simd linear(val(%[[X]]#0 : !fir.ref<i32> = %[[LINEAR_STEP]] : i32), val(%[[I]]#0 : !fir.ref<i32> = %[[IV_STEP]] : i32)) {
integer :: x
!$omp parallel do simd linear(x:2)
do i = 1, N
@@ -84,8 +85,8 @@ subroutine teams_distribute
!CHECK: {{.*}} = arith.constant 1 : i32
!CHECK: %[[IV_STEP:.*]] = arith.constant 1 : i32
!CHECK: omp.distribute {
-!DEFAULT: omp.simd linear(%[[X]]#0 : !fir.ref<i32> = %[[LINEAR_STEP]] : i32, %[[I]]#0 : !fir.ref<i32> = %[[IV_STEP]] : i32) private(@_QFteams_distributeEi_private_i32 %[[I]]#0 -> %arg0 : !fir.ref<i32>) {
-!OPENMP52: omp.simd linear(val(%[[X]]#0 : !fir.ref<i32> = %[[LINEAR_STEP]] : i32), val(%[[I]]#0 : !fir.ref<i32> = %[[IV_STEP]] : i32)) private(@_QFteams_distributeEi_private_i32 %[[I]]#0 -> %arg0 : !fir.ref<i32>) {
+!DEFAULT: omp.simd linear(%[[X]]#0 : !fir.ref<i32> = %[[LINEAR_STEP]] : i32, %[[I]]#0 : !fir.ref<i32> = %[[IV_STEP]] : i32) {
+!OPENMP52: omp.simd linear(val(%[[X]]#0 : !fir.ref<i32> = %[[LINEAR_STEP]] : i32), val(%[[I]]#0 : !fir.ref<i32> = %[[IV_STEP]] : i32)) {
integer :: x
!$omp teams distribute simd linear(x)
do i = 1, N
@@ -104,8 +105,8 @@ subroutine teams_distribute_parallel_do
!CHECK: %[[IV_STEP:.*]] = arith.constant 1 : i32
!CHECK: omp.distribute {
!CHECK: omp.wsloop {
-!DEFAULT: omp.simd linear(%[[X]]#0 : !fir.ref<i32> = %c1_i32 : i32, %[[I]]#0 : !fir.ref<i32> = %c1_i32_1 : i32) private(@_QFteams_distribute_parallel_doEi_private_i32 %[[I]]#0 -> %arg0 : !fir.ref<i32>) {
-!OPENMP52: omp.simd linear(val(%[[X]]#0 : !fir.ref<i32> = %c1_i32 : i32), val(%[[I]]#0 : !fir.ref<i32> = %c1_i32_1 : i32)) private(@_QFteams_distribute_parallel_doEi_private_i32 %[[I]]#0 -> %arg0 : !fir.ref<i32>) {
+!DEFAULT: omp.simd linear(%[[X]]#0 : !fir.ref<i32> = %c1_i32 : i32, %[[I]]#0 : !fir.ref<i32> = %c1_i32_1 : i32) {
+!OPENMP52: omp.simd linear(val(%[[X]]#0 : !fir.ref<i32> = %c1_i32 : i32), val(%[[I]]#0 : !fir.ref<i32> = %c1_i32_1 : i32)) {
integer :: x
!$omp teams distribute parallel do simd linear(x)
do i = 1, N
diff --git a/flang/test/Lower/OpenMP/distribute-parallel-do-simd.f90 b/flang/test/Lower/OpenMP/distribute-parallel-do-simd.f90
index 89d8fd951f85f..2543e9470452a 100644
--- a/flang/test/Lower/OpenMP/distribute-parallel-do-simd.f90
+++ b/flang/test/Lower/OpenMP/distribute-parallel-do-simd.f90
@@ -13,8 +13,8 @@ subroutine distribute_parallel_do_simd_num_threads()
! CHECK: omp.parallel num_threads({{.*}}) {
! CHECK: omp.distribute {
! CHECK-NEXT: omp.wsloop {
- ! DEFAULT-NEXT: omp.simd linear({{.*}}) private({{.*}}) {
- ! OPENMP52-NEXT: omp.simd linear(val({{.*}})) private({{.*}}) {
+ ! DEFAULT-NEXT: omp.simd linear({{.*}}) {
+ ! OPENMP52-NEXT: omp.simd linear(val({{.*}})) {
! CHECK-NEXT: omp.loop_nest
!$omp distribute parallel do simd num_threads(10)
do index_ = 1, 10
@@ -31,8 +31,8 @@ subroutine distribute_parallel_do_simd_dist_schedule()
! CHECK: omp.parallel {
! CHECK: omp.distribute dist_schedule_static dist_schedule_chunk_size({{.*}}) {
! CHECK-NEXT: omp.wsloop {
- ! DEFAULT-NEXT: omp.simd linear({{.*}}) private({{.*}}) {
- ! OPENMP52-NEXT: omp.simd linear(val({{.*}})) private({{.*}}) {
+ ! DEFAULT-NEXT: omp.simd linear({{.*}}) {
+ ! OPENMP52-NEXT: omp.simd linear(val({{.*}})) {
! CHECK-NEXT: omp.loop_nest
!$omp distribute parallel do simd dist_schedule(static, 4)
do index_ = 1, 10
@@ -49,8 +49,8 @@ subroutine distribute_parallel_do_simd_schedule()
! CHECK: omp.parallel {
! CHECK: omp.distribute {
! CHECK-NEXT: omp.wsloop schedule(static = {{.*}}) {
- ! DEFAULT-NEXT: omp.simd linear({{.*}}) private({{.*}}) {
- ! OPENMP52-NEXT: omp.simd linear(val({{.*}})) private({{.*}}) {
+ ! DEFAULT-NEXT: omp.simd linear({{.*}}) {
+ ! OPENMP52-NEXT: omp.simd linear(val({{.*}})) {
! CHECK-NEXT: omp.loop_nest
!$omp distribute parallel do simd schedule(static, 4)
do index_ = 1, 10
@@ -67,8 +67,8 @@ subroutine distribute_parallel_do_simd_simdlen()
! CHECK: omp.parallel {
! CHECK: omp.distribute {
! CHECK-NEXT: omp.wsloop {
- ! DEFAULT-NEXT: omp.simd linear({{.*}}) simdlen(4) private({{.*}}) {
- ! OPENMP52-NEXT: omp.simd linear(val({{.*}})) simdlen(4) private({{.*}}) {
+ ! DEFAULT-NEXT: omp.simd linear({{.*}}) simdlen(4) {
+ ! OPENMP52-NEXT: omp.simd linear(val({{.*}})) simdlen(4) {
! CHECK-NEXT: omp.loop_nest
!$omp distribute parallel do simd simdlen(4)
do index_ = 1, 10
@@ -92,13 +92,12 @@ subroutine distribute_parallel_do_simd_private()
! CHECK: omp.parallel {
! CHECK: omp.distribute {
! CHECK-NEXT: omp.wsloop {
- ! DEFAULT-NEXT: omp.simd linear(%{{.*}}) private(@{{.*}} %[[X]]#0 -> %[[X_ARG:[^,]+]],
- ! DEFAULT-SAME: @{{.*}} %[[INDEX]]#0 -> %[[INDEX_ARG:.*]] : !fir.ref<i64>, !fir.ref<i32>) {
- ! OPENMP52-NEXT: omp.simd linear(val(%{{.*}})) private(@{{.*}} %[[X]]#0 -> %[[X_ARG:[^,]+]],
- ! OPENMP52-SAME: @{{.*}} %[[INDEX]]#0 -> %[[INDEX_ARG:.*]] : !fir.ref<i64>, !fir.ref<i32>) {
+ ! DEFAULT-NEXT: omp.simd linear(%{{.*}}) private(@{{.*}} %[[X]]#0 -> %[[X_ARG:[^:]+]]
+ ! DEFAULT-SAME: : !fir.ref<i64>) {
+ ! OPENMP52-NEXT: omp.simd linear(val(%{{.*}})) private(@{{.*}} %[[X]]#0 -> %[[X_ARG:[^:]+]]
+ ! OPENMP52-SAME: : !fir.ref<i64>) {
! CHECK-NEXT: omp.loop_nest
! CHECK: %[[X_PRIV:.*]]:2 = hlfir.declare %[[X_ARG]]
- ! CHECK: %[[INDEX_PRIV:.*]]:2 = hlfir.declare %[[INDEX_ARG]]
!$omp distribute parallel do simd private(x)
do index_ = 1, 10
end do
diff --git a/flang/test/Lower/OpenMP/distribute-simd.f90 b/flang/test/Lower/OpenMP/distribute-simd.f90
index d0316d1a136ab..f06282a10d9f0 100644
--- a/flang/test/Lower/OpenMP/distribute-simd.f90
+++ b/flang/test/Lower/OpenMP/distribute-simd.f90
@@ -61,17 +61,17 @@ end subroutine distribute_simd_simdlen
! CHECK-LABEL: func.func @_QPdistribute_simd_private(
subroutine distribute_simd_private()
integer, allocatable :: tmp
+ ! CHECK: %[[INDEX:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFdistribute_simd_privateEindex_"}
! CHECK: omp.teams
!$omp teams
! CHECK: omp.distribute
! CHECK: omp.simd
- ! CHECK-SAME: private(@[[PRIV_BOX_SYM:.*]] %{{.*}} -> %[[PRIV_BOX:.*]], @[[PRIV_IVAR_SYM:.*]] %{{.*}} -> %[[PRIV_IVAR:.*]] : !fir.ref<!fir.box<!fir.heap<i32>>>, !fir.ref<i32>)
+ ! CHECK-SAME: private(@[[PRIV_BOX_SYM:.*]] %{{.*}} -> %[[PRIV_BOX:.*]] : !fir.ref<!fir.box<!fir.heap<i32>>>)
! CHECK-NEXT: omp.loop_nest (%[[IVAR:.*]]) : i32
!$omp distribute simd private(tmp)
do index_ = 1, 10
! CHECK: %[[PRIV_BOX_DECL:.*]]:2 = hlfir.declare %[[PRIV_BOX]]
- ! CHECK: %[[PRIV_IVAR_DECL:.*]]:2 = hlfir.declare %[[PRIV_IVAR]]
- ! CHECK: hlfir.assign %[[IVAR]] to %[[PRIV_IVAR_DECL]]#0
+ ! CHECK: hlfir.assign %[[IVAR]] to %[[INDEX]]#0
end do
!$omp end distribute simd
!$omp end teams
diff --git a/flang/test/Lower/OpenMP/linear_modifier.f90 b/flang/test/Lower/OpenMP/linear_modifier.f90
index 8364e5d698f06..624fa170cc1bc 100644
--- a/flang/test/Lower/OpenMP/linear_modifier.f90
+++ b/flang/test/Lower/OpenMP/linear_modifier.f90
@@ -42,8 +42,8 @@ subroutine do_simd_linear
!CHECK: %{{.*}} = arith.constant 1 : i32
!CHECK: %[[IV_STEP:.*]] = arith.constant 1 : i32
!CHECK: omp.wsloop {
-!OPENMP52: omp.simd linear(val(%[[X]]#0 : !fir.ref<i32> = %[[CONST]] : i32), val(%[[I]]#0 : !fir.ref<i32> = %[[IV_STEP]] : i32)) private({{.*}}) {
-!OPENMP45: omp.simd linear(%[[X]]#0 : !fir.ref<i32> = %[[CONST]] : i32, %[[I]]#0 : !fir.ref<i32> = %[[IV_STEP]] : i32) private({{.*}}) {
+!OPENMP52: omp.simd linear(val(%[[X]]#0 : !fir.ref<i32> = %[[CONST]] : i32), val(%[[I]]#0 : !fir.ref<i32> = %[[IV_STEP]] : i32)) {
+!OPENMP45: omp.simd linear(%[[X]]#0 : !fir.ref<i32> = %[[CONST]] : i32, %[[I]]#0 : !fir.ref<i32> = %[[IV_STEP]] : i32) {
integer :: x
!$omp do simd linear(x:1)
do i = 1, 10
diff --git a/flang/test/Lower/OpenMP/loop-pointer-variable.f90 b/flang/test/Lower/OpenMP/loop-pointer-variable.f90
index 0ca5d3a197dc5..5a2ca05be7ccf 100644
--- a/flang/test/Lower/OpenMP/loop-pointer-variable.f90
+++ b/flang/test/Lower/OpenMP/loop-pointer-variable.f90
@@ -8,6 +8,7 @@ program loop_var
integer, pointer :: ip1, ip2
integer, allocatable :: ia1
+!CHECK: %[[IA1:.*]]:2 = hlfir.declare %{{.*}} {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFEia1"}
!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: %[[IP1_PVT_DECL:.*]]:2 = hlfir.declare %[[IP1_PVT]] {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QFEip1"} : (!fir.ref<!fir.box<!fir.ptr<i32>>>) -> (!fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.ref<!fir.box<!fir.ptr<i32>>>)
@@ -28,13 +29,12 @@ program loop_var
end do
!$omp end do
-!CHECK: omp.simd private(@_QFEia1_private_box_heap_i32 %{{.*}}#0 -> %[[IA1_PVT:.*]] : !fir.ref<!fir.box<!fir.heap<i32>>>)
+!CHECK: omp.simd
!CHECK: omp.loop_nest (%[[IA1_INDX:.*]]) : i64 = ({{.*}}) to ({{.*}}) inclusive step ({{.*}})
-!CHECK: %[[IA1_PVT_DECL:.*]]:2 = hlfir.declare %[[IA1_PVT]] {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFEia1"} : (!fir.ref<!fir.box<!fir.heap<i32>>>) -> (!fir.ref<!fir.box<!fir.heap<i32>>>, !fir.ref<!fir.box<!fir.heap<i32>>>)
-!CHECK: %[[IA1:.*]] = fir.convert %[[IA1_INDX]] : (i64) -> i32
-!CHECK: %[[IA1_BOX:.*]] = fir.load %[[IA1_PVT_DECL]]#0 : !fir.ref<!fir.box<!fir.heap<i32>>>
+!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: %[[IA1_ADDR:.*]] = fir.box_addr %[[IA1_BOX]] : (!fir.box<!fir.heap<i32>>) -> !fir.heap<i32>
-!CHECK: hlfir.assign %[[IA1]] to %[[IA1_ADDR]] : i32, !fir.heap<i32>
+!CHECK: hlfir.assign %[[IA1_INDX_I32]] to %[[IA1_ADDR]] : i32, !fir.heap<i32>
!CHECK: omp.yield
!$omp simd
do ia1 = 1, 10
diff --git a/flang/test/Lower/OpenMP/ordered-simd.f90 b/flang/test/Lower/OpenMP/ordered-simd.f90
index 849900993319a..5947c782414ca 100644
--- a/flang/test/Lower/OpenMP/ordered-simd.f90
+++ b/flang/test/Lower/OpenMP/ordered-simd.f90
@@ -7,7 +7,7 @@ subroutine ordered_simd(n)
integer :: n, a(n), b(n), c(n), i
! CHECK-LABEL: func @_QPordered_simd
-! CHECK: omp.simd linear({{.*}}) private({{.*}}) {
+! CHECK: omp.simd linear({{.*}}) {
! CHECK: omp.loop_nest (%{{.*}}) : i32 = (%{{.*}}) to (%{{.*}}) inclusive step (%{{.*}}) {
! CHECK: omp.ordered.region par_level_simd {
! CHECK: omp.terminator
@@ -34,7 +34,7 @@ subroutine ws_ordered_simd(n)
! CHECK-LABEL: func @_QPws_ordered_simd
! CHECK: omp.wsloop ordered(0) {
-! CHECK: omp.simd linear({{.*}}) private({{.*}}) {
+! CHECK: omp.simd linear({{.*}}) {
! CHECK: omp.loop_nest (%{{.*}}) : i32 = (%{{.*}}) to (%{{.*}}) inclusive step (%{{.*}}) {
! CHECK: omp.ordered.region par_level_simd {
! CHECK: omp.terminator
diff --git a/flang/test/Lower/OpenMP/wsloop-simd.f90 b/flang/test/Lower/OpenMP/wsloop-simd.f90
index 03e35de04cace..541ec86c1b7e5 100644
--- a/flang/test/Lower/OpenMP/wsloop-simd.f90
+++ b/flang/test/Lower/OpenMP/wsloop-simd.f90
@@ -70,15 +70,15 @@ end subroutine do_simd_reduction
! CHECK-LABEL: func.func @_QPdo_simd_private(
subroutine do_simd_private()
integer, allocatable :: tmp
+ ! CHECK: %[[I_DECL:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFdo_simd_privateEi"}
! CHECK: omp.wsloop
! CHECK-NEXT: omp.simd
- ! CHECK-SAME: private(@[[PRIV_BOX_SYM:.*]] %{{.*}} -> %[[PRIV_BOX:.*]], @[[PRIV_IVAR_SYM:.*]] %{{.*}} -> %[[PRIV_IVAR:.*]] : !fir.ref<!fir.box<!fir.heap<i32>>>, !fir.ref<i32>)
+ ! CHECK-SAME: private(@[[PRIV_BOX_SYM:.*]] %{{.*}} -> %[[PRIV_BOX:.*]] : !fir.ref<!fir.box<!fir.heap<i32>>>)
! CHECK-NEXT: omp.loop_nest (%[[IVAR:.*]]) : i32
!$omp do simd private(tmp)
do i=1, 10
! CHECK: %[[PRIV_BOX_DECL:.*]]:2 = hlfir.declare %[[PRIV_BOX]]
- ! CHECK: %[[PRIV_IVAR_DECL:.*]]:2 = hlfir.declare %[[PRIV_IVAR]]
- ! CHECK: hlfir.assign %[[IVAR]] to %[[PRIV_IVAR_DECL]]#0
+ ! CHECK: hlfir.assign %[[IVAR]] to %[[I_DECL]]#0
! CHECK: %[[PRIV_BOX_LOAD:.*]] = fir.load %[[PRIV_BOX_DECL]]
! CHECK: hlfir.assign %{{.*}} to %[[PRIV_BOX_DECL]]#0
! CHECK: omp.yield
@@ -92,12 +92,12 @@ subroutine do_simd_lastprivate_firstprivate()
! CHECK: omp.wsloop
! CHECK-SAME: private(@[[FIRSTPRIVATE_A_SYM:.*]] %{{.*}} -> %[[FIRSTPRIVATE_A:.*]] : !fir.ref<i32>)
! CHECK-NEXT: omp.simd
- ! CHECK-SAME: private(@[[PRIVATE_A_SYM:.*]] %{{.*}} -> %[[PRIVATE_A:.*]], @[[PRIVATE_I_SYM:.*]] %{{.*}} -> %[[PRIVATE_I:.*]] : !fir.ref<i32>, !fir.ref<i32>)
+ ! CHECK-SAME: linear({{.*}}#0 : !fir.ref<i32> = %{{[^:]*}} : i32)
+ ! CHECK-SAME: private(@[[PRIVATE_A_SYM:.*]] %{{.*}} -> %[[PRIVATE_A:.*]] : !fir.ref<i32>)
!$omp do simd lastprivate(a) firstprivate(a)
do i = 1, 10
! CHECK: %[[FIRSTPRIVATE_A_DECL:.*]]:2 = hlfir.declare %[[FIRSTPRIVATE_A]]
! CHECK: %[[PRIVATE_A_DECL:.*]]:2 = hlfir.declare %[[PRIVATE_A]]
- ! CHECK: %[[PRIVATE_I_DECL:.*]]:2 = hlfir.declare %[[PRIVATE_I]]
a = a + 1
end do
!$omp end do simd
diff --git a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
index 8614aed1ab80c..05cf73665e0ef 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
@@ -278,17 +278,41 @@ class LinearClauseProcessor {
}
}
- // Rewrite all uses of the original variable in `BBName`
- // with the linear variable in-place
- void rewriteInPlace(llvm::IRBuilderBase &builder, const std::string &BBName,
+ // Rewrite all uses of the original variable, in the basic blocks whose names
+ // start with `prefix`, with the linear variable in-place.
+ void rewriteInPlace(llvm::IRBuilderBase &builder, llvm::BasicBlock *startBB,
+ llvm::BasicBlock *endBB, llvm::StringRef prefix,
size_t varIndex) {
- llvm::SmallVector<llvm::User *> users;
- for (llvm::User *user : linearOrigVal[varIndex]->users())
- users.push_back(user);
- for (auto *user : users) {
+ llvm::SmallVector<llvm::BasicBlock *, 32> worklist;
+ llvm::SmallPtrSet<llvm::BasicBlock *, 32> visited;
+ llvm::SmallPtrSet<llvm::BasicBlock *, 32> matchingBBs;
+
+ assert(startBB && endBB && "Invalid startBB/endBB");
+
+ // Traverse basic blocks from startBB to endBB and save those
+ // whose names start with the specified prefix.
+ worklist.push_back(startBB);
+ visited.insert(startBB);
+
+ while (!worklist.empty()) {
+ llvm::BasicBlock *bb = worklist.pop_back_val();
+
+ if (bb->hasName() && bb->getName().starts_with(prefix))
+ matchingBBs.insert(bb);
+
+ if (bb == endBB)
+ continue;
+
+ for (llvm::BasicBlock *succ : llvm::successors(bb)) {
+ if (visited.insert(succ).second)
+ worklist.push_back(succ);
+ }
+ }
+
+ // Rewrite all uses in the matching BBs.
+ for (auto *user : linearOrigVal[varIndex]->users()) {
if (auto *userInst = dyn_cast<llvm::Instruction>(user)) {
- if (userInst->getParent()->getName().str().find(BBName) !=
- std::string::npos)
+ if (matchingBBs.contains(userInst->getParent()))
user->replaceUsesOfWith(linearOrigVal[varIndex],
linearLoopBodyTemps[varIndex]);
}
@@ -3609,6 +3633,7 @@ convertOmpWsloop(Operation &opInst, llvm::IRBuilderBase &builder,
linearClauseProcessor.initLinearStep(moduleTranslation, linearStep);
}
+ llvm::BasicBlock *sourceBlock = builder.GetInsertBlock();
llvm::Expected<llvm::BasicBlock *> regionBlock = convertOmpOpRegions(
wsloopOp.getRegion(), "omp.wsloop.region", builder, moduleTranslation);
@@ -3676,8 +3701,10 @@ convertOmpWsloop(Operation &opInst, llvm::IRBuilderBase &builder,
if (failed(handleError(afterBarrierIP, *loopOp)))
return failure();
for (size_t index = 0; index < wsloopOp.getLinearVars().size(); index++)
- linearClauseProcessor.rewriteInPlace(builder, "omp.loop_nest.region",
- index);
+ linearClauseProcessor.rewriteInPlace(
+ builder, sourceBlock->getSingleSuccessor(), *regionBlock,
+ "omp.loop_nest.region", index);
+
builder.restoreIP(oldIP);
}
@@ -4048,15 +4075,18 @@ convertOmpSimd(Operation &opInst, llvm::IRBuilderBase &builder,
});
for (size_t index = 0; index < simdOp.getLinearVars().size(); index++) {
- linearClauseProcessor.rewriteInPlace(builder, "omp.loop_nest.region",
- index);
+ llvm::BasicBlock *startBB = sourceBlock->getSingleSuccessor();
+ llvm::BasicBlock *endBB = *regionBlock;
+ linearClauseProcessor.rewriteInPlace(builder, startBB, endBB,
+ "omp.loop_nest.region", index);
+
if (hasOrderedRegions) {
// Also rewrite uses in ordered regions so they read the current value
- linearClauseProcessor.rewriteInPlace(builder, "omp.ordered.region",
- index);
+ linearClauseProcessor.rewriteInPlace(builder, startBB, endBB,
+ "omp.ordered.region", index);
// Also rewrite uses in finalize blocks (code after ordered regions)
- linearClauseProcessor.rewriteInPlace(builder, "omp_region.finalize",
- index);
+ linearClauseProcessor.rewriteInPlace(builder, startBB, endBB,
+ "omp_region.finalize", index);
}
}
diff --git a/mlir/test/Target/LLVMIR/openmp-simd-linear.mlir b/mlir/test/Target/LLVMIR/openmp-simd-linear.mlir
new file mode 100644
index 0000000000000..1722d1437ad79
--- /dev/null
+++ b/mlir/test/Target/LLVMIR/openmp-simd-linear.mlir
@@ -0,0 +1,34 @@
+// Ensure that omp.simd with the linear clause is translated correctly even
+// when otehr loop nests exist in the same function.
+// RUN: mlir-translate -mlir-to-llvmir -split-input-file %s | FileCheck %s
+
+omp.private {type = private} @test_simd_linear_private_i32 : i32
+llvm.func @test_simd_linear() {
+ %0 = llvm.mlir.constant(1 : i64) : i64
+ %1 = llvm.mlir.constant(1 : i32) : i32
+ %2 = llvm.mlir.constant(2 : i32) : i32
+ %3 = llvm.mlir.constant(10 : i32) : i32
+ %4 = llvm.alloca %0 x i32 {bindc_name = "j"} : (i64) -> !llvm.ptr
+ %5 = llvm.alloca %0 x i32 {bindc_name = "i"} : (i64) -> !llvm.ptr
+ omp.parallel {
+ omp.wsloop private(@test_simd_linear_private_i32 %5 -> %arg0 : !llvm.ptr) {
+ omp.loop_nest (%arg1) : i32 = (%1) to (%3) inclusive step (%1) {
+ llvm.store %arg1, %arg0 : i32, !llvm.ptr
+ llvm.store %2, %4 : i32, !llvm.ptr
+ omp.simd linear(%4 : !llvm.ptr = %1 : i32) {
+ omp.loop_nest (%arg2) : i32 = (%1) to (%3) inclusive step (%1) {
+ llvm.store %arg2, %4 : i32, !llvm.ptr
+ omp.yield
+ }
+ } {linear_var_types = [i32]}
+ omp.yield
+ }
+ }
+ omp.terminator
+ }
+ llvm.return
+}
+
+// CHECK-LABEL: void @test_simd_linear()
+// CHECK-NOT: %.linear_result
+// CHECK: %.linear_result = alloca i32
>From 7d62f924161b9a16f134667a18391ed54047978f Mon Sep 17 00:00:00 2001
From: Leandro Lupori <leandro.lupori at linaro.org>
Date: Mon, 27 Apr 2026 17:12:56 -0300
Subject: [PATCH 2/2] Fix regressions in OpenMP V&V and Fujitsu testsuites
The users iterator apparently becomes invalid after one of its uses is
replaced. Fix this by making a copy of the list of users.
---
.../OpenMP/OpenMPToLLVMIRTranslation.cpp | 3 +-
.../Target/LLVMIR/openmp-simd-linear.mlir | 56 +++++++++++++++++--
2 files changed, 54 insertions(+), 5 deletions(-)
diff --git a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
index 05cf73665e0ef..25933ec1570a1 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
@@ -310,7 +310,8 @@ class LinearClauseProcessor {
}
// Rewrite all uses in the matching BBs.
- for (auto *user : linearOrigVal[varIndex]->users()) {
+ llvm::SmallVector<llvm::User *> users(linearOrigVal[varIndex]->users());
+ for (auto *user : users) {
if (auto *userInst = dyn_cast<llvm::Instruction>(user)) {
if (matchingBBs.contains(userInst->getParent()))
user->replaceUsesOfWith(linearOrigVal[varIndex],
diff --git a/mlir/test/Target/LLVMIR/openmp-simd-linear.mlir b/mlir/test/Target/LLVMIR/openmp-simd-linear.mlir
index 1722d1437ad79..4ab6e17386691 100644
--- a/mlir/test/Target/LLVMIR/openmp-simd-linear.mlir
+++ b/mlir/test/Target/LLVMIR/openmp-simd-linear.mlir
@@ -1,7 +1,13 @@
// Ensure that omp.simd with the linear clause is translated correctly even
-// when otehr loop nests exist in the same function.
+// when other loop nests exist in the same function.
// RUN: mlir-translate -mlir-to-llvmir -split-input-file %s | FileCheck %s
+// -----
+
+// CHECK-LABEL: void @test_simd_linear()
+// CHECK-NOT: %.linear_result
+// CHECK: %.linear_result = alloca i32
+
omp.private {type = private} @test_simd_linear_private_i32 : i32
llvm.func @test_simd_linear() {
%0 = llvm.mlir.constant(1 : i64) : i64
@@ -29,6 +35,48 @@ llvm.func @test_simd_linear() {
llvm.return
}
-// CHECK-LABEL: void @test_simd_linear()
-// CHECK-NOT: %.linear_result
-// CHECK: %.linear_result = alloca i32
+
+// -----
+
+// CHECK-LABEL: @test_simd_linear2({{.*}})
+// CHECK: omp.loop_nest.region:
+// CHECK: store i32 %{{.*}}, ptr %.linear_result
+// CHECK: %{{.*}} = load i32, ptr %.linear_result
+// CHECK: omp.region.cont1:
+
+llvm.func @test_simd_linear2(%a : !llvm.ptr) {
+ %c0_i64 = llvm.mlir.constant(0 : index) : i64
+ %c1_i64 = llvm.mlir.constant(1 : index) : i64
+ %c100_i64 = llvm.mlir.constant(100 : index) : i64
+ %c1_i32 = llvm.mlir.constant(1 : i32) : i32
+ %c100_i32 = llvm.mlir.constant(100 : i32) : i32
+
+ %i_ptr = llvm.alloca %c0_i64 x i32 {bindc_name = "i"} : (i64) -> !llvm.ptr
+ llvm.br ^bb1(%c1_i32, %c100_i64 : i32, i64)
+^bb1(%i: i32, %iv: i64): // 2 preds: ^bb0, ^bb2
+ %1 = llvm.icmp "sgt" %iv, %c0_i64 : i64
+ llvm.cond_br %1, ^bb2, ^bb3
+^bb2: // pred: ^bb1
+ llvm.store %i, %i_ptr : i32, !llvm.ptr
+ %2 = llvm.load %i_ptr : !llvm.ptr -> i32
+ %i_next = llvm.add %2, %c1_i32 overflow<nsw> : i32
+ %iv_next = llvm.sub %iv, %c1_i64 : i64
+ llvm.br ^bb1(%i_next, %iv_next : i32, i64)
+^bb3: // pred: ^bb1
+ llvm.store %i, %i_ptr : i32, !llvm.ptr
+ omp.simd linear(%i_ptr : !llvm.ptr = %c1_i32 : i32) {
+ omp.loop_nest (%arg0) : i32 = (%c1_i32) to (%c100_i32) inclusive step (%c1_i32) {
+ llvm.store %arg0, %i_ptr : i32, !llvm.ptr
+ %i2 = llvm.load %i_ptr : !llvm.ptr -> i32
+ %3 = llvm.sext %i2 : i32 to i64
+ %4 = llvm.sub %3, %c1_i64 overflow<nsw, nuw> : i64
+ %5 = llvm.mul %4, %c1_i64 overflow<nsw, nuw> : i64
+ %6 = llvm.mul %5, %c1_i64 overflow<nsw, nuw> : i64
+ %7 = llvm.add %6, %c0_i64 overflow<nsw, nuw> : i64
+ %8 = llvm.getelementptr nusw|nuw %a[%7] : (!llvm.ptr, i64) -> !llvm.ptr, i32
+ llvm.store %i2, %8 : i32, !llvm.ptr
+ omp.yield
+ }
+ } {linear_var_types = [i32]}
+ llvm.return
+}
More information about the flang-commits
mailing list