[flang-commits] [flang] [flang][OpenMP] Fix standalone SIMD directive post-loop variable value (PR #196731)

Michael Klemm via flang-commits flang-commits at lists.llvm.org
Fri Aug 14 08:33:50 PDT 2026


https://github.com/mjklemm updated https://github.com/llvm/llvm-project/pull/196731

>From 47ec854bdbb1eebf4bf061ef197cd3066fb432e3 Mon Sep 17 00:00:00 2001
From: Michael Klemm <michael.klemm at amd.com>
Date: Sat, 9 May 2026 16:34:59 +0200
Subject: [PATCH 1/2] [flang][OpenMP] Fix standalone SIMD directive post-loop
 variable value

The OpenMP API requires that the last value of a loop variable of a
standalone SIMD directive is preserved in the orginal variable.
---
 flang/lib/Semantics/resolve-directives.cpp            | 11 ++++++++++-
 .../test/Semantics/OpenMP/implicit_linear_symbols.f90 |  2 +-
 2 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index 15bb84d7e486f..b2c3dcf697baa 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -2251,9 +2251,18 @@ void OmpAttributeVisitor::PrivatizeAssociatedLoopIndex(
         continue;
       }
       if (auto *symbol{ResolveOmp(*iv, ivDSA, scope)}) {
-        SetSymbolDSA(*symbol, {Symbol::Flag::OmpPreDetermined, ivDSA});
+        Symbol::Flags ivFlags{Symbol::Flag::OmpPreDetermined, ivDSA};
+        // For a standalone SIMD loop variable set lastprivate so the original
+        // variable is correctly set to the last value of the loop variable as
+        // per the OpenMP spec
+        if (ivDSA == Symbol::Flag::OmpLinear &&
+            llvm::omp::topSimdSet.test(GetContext().directive))
+          ivFlags.set(Symbol::Flag::OmpLastPrivate);
+        SetSymbolDSA(*symbol, ivFlags);
         iv->symbol = symbol; // adjust the symbol within region
         AddToContextObjectWithDSA(*symbol, ivDSA);
+        if (ivFlags.test(Symbol::Flag::OmpLastPrivate))
+          AddToContextObjectWithDSA(*symbol, Symbol::Flag::OmpLastPrivate);
       }
     }
   }
diff --git a/flang/test/Semantics/OpenMP/implicit_linear_symbols.f90 b/flang/test/Semantics/OpenMP/implicit_linear_symbols.f90
index e57a063d8a9d0..7f8110dd931de 100644
--- a/flang/test/Semantics/OpenMP/implicit_linear_symbols.f90
+++ b/flang/test/Semantics/OpenMP/implicit_linear_symbols.f90
@@ -2,7 +2,7 @@
 !RUN: %flang_fc1 -fopenmp -fopenmp-version=60 -fdebug-dump-symbols %s 2>&1 | FileCheck %s --check-prefix=NOIMPLICIT
 
 
-!IMPLICIT: k2 (OmpLinear, OmpPreDetermined): {{.*}}
+!IMPLICIT: k2 (OmpLinear, OmpLastPrivate, OmpPreDetermined): {{.*}}
 !NOIMPLICIT: k2 (OmpLastPrivate, OmpPreDetermined): {{.*}}
 subroutine implicit_linear
   integer :: k1, k2

>From 8270df506b63fbaff87ccd11f770e56f6e0f3c0e Mon Sep 17 00:00:00 2001
From: Michael Klemm <michael.klemm at amd.com>
Date: Fri, 14 Aug 2026 17:30:12 +0200
Subject: [PATCH 2/2] Fix composite SIMD privatization

---
 .../flang/Semantics/openmp-directive-sets.h   | 37 +++++++++++--------
 flang/lib/Semantics/resolve-directives.cpp    |  7 +++-
 2 files changed, 28 insertions(+), 16 deletions(-)

diff --git a/flang/include/flang/Semantics/openmp-directive-sets.h b/flang/include/flang/Semantics/openmp-directive-sets.h
index c6966a8d836b0..34332baf74fb7 100644
--- a/flang/include/flang/Semantics/openmp-directive-sets.h
+++ b/flang/include/flang/Semantics/openmp-directive-sets.h
@@ -108,24 +108,31 @@ static const llvm::omp::DirectiveSet topSimdSet{
     Directive::OMPD_simd,
 };
 
+// Composite/combined SIMD constructs: SIMD paired with a worksharing or
+// loop-partitioning component (do, distribute, taskloop). For these, the
+// loop iteration variable follows the worksharing rule (private), not the
+// pure-SIMD rule (linear/lastprivate).
+static const llvm::omp::DirectiveSet compositeSimdSet{
+    Directive::OMPD_distribute_parallel_do_simd,
+    Directive::OMPD_distribute_simd,
+    Directive::OMPD_do_simd,
+    Directive::OMPD_masked_taskloop_simd,
+    Directive::OMPD_master_taskloop_simd,
+    Directive::OMPD_parallel_do_simd,
+    Directive::OMPD_parallel_masked_taskloop_simd,
+    Directive::OMPD_parallel_master_taskloop_simd,
+    Directive::OMPD_target_parallel_do_simd,
+    Directive::OMPD_target_teams_distribute_parallel_do_simd,
+    Directive::OMPD_target_teams_distribute_simd,
+    Directive::OMPD_taskloop_simd,
+    Directive::OMPD_teams_distribute_parallel_do_simd,
+    Directive::OMPD_teams_distribute_simd,
+};
+
 static const llvm::omp::DirectiveSet allSimdSet{
     llvm::omp::DirectiveSet{
-        Directive::OMPD_distribute_parallel_do_simd,
-        Directive::OMPD_distribute_simd,
-        Directive::OMPD_do_simd,
-        Directive::OMPD_masked_taskloop_simd,
-        Directive::OMPD_master_taskloop_simd,
-        Directive::OMPD_parallel_do_simd,
-        Directive::OMPD_parallel_masked_taskloop_simd,
-        Directive::OMPD_parallel_master_taskloop_simd,
-        Directive::OMPD_target_parallel_do_simd,
         Directive::OMPD_target_simd,
-        Directive::OMPD_target_teams_distribute_parallel_do_simd,
-        Directive::OMPD_target_teams_distribute_simd,
-        Directive::OMPD_taskloop_simd,
-        Directive::OMPD_teams_distribute_parallel_do_simd,
-        Directive::OMPD_teams_distribute_simd,
-    } | topSimdSet,
+    } | topSimdSet | compositeSimdSet,
 };
 
 static const llvm::omp::DirectiveSet topTargetSet{
diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index b2c3dcf697baa..c22a589bea293 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -2234,7 +2234,12 @@ void OmpAttributeVisitor::PrivatizeAssociatedLoopIndex(
 
   int64_t level{*depth.value};
   Symbol::Flag ivDSA;
-  if (!llvm::omp::allSimdSet.test(GetContext().directive)) {
+  const auto directive{GetContext().directive};
+  // For composite SIMD constructs (SIMD combined with do/distribute/taskloop),
+  // the loop iteration variable follows the worksharing rule (private), not
+  // the pure-SIMD rule (linear/lastprivate).
+  if (!llvm::omp::allSimdSet.test(directive) ||
+      llvm::omp::compositeSimdSet.test(directive)) {
     ivDSA = Symbol::Flag::OmpPrivate;
   } else if (level == 1 && version < 60) {
     ivDSA = Symbol::Flag::OmpLinear;



More information about the flang-commits mailing list