[flang-commits] [flang] 8305195 - [flang][OpenMP] incorrect handling for local variable in OpenMP parallel workshare firstprivate(P) (#195616)

via flang-commits flang-commits at lists.llvm.org
Wed Sep 2 23:29:53 PDT 2026


Author: SunilKuravinakop
Date: 2026-09-03T11:59:47+05:30
New Revision: 83051952abc253395a811902921d2683d0a494ee

URL: https://github.com/llvm/llvm-project/commit/83051952abc253395a811902921d2683d0a494ee
DIFF: https://github.com/llvm/llvm-project/commit/83051952abc253395a811902921d2683d0a494ee.diff

LOG: [flang][OpenMP] incorrect handling for local variable in OpenMP parallel workshare firstprivate(P) (#195616)

Changes to handle "!$omp parallel workshare firstprivate(P)" where P is
an array. Handling the creation and initialization of the local copy
properly.

This also Fixes
[195337](https://github.com/llvm/llvm-project/issues/195337) .

---------
 Sunil Kuravinakop <koops at hpe.com>

Added: 
    flang/test/Lower/OpenMP/Todo/workshare-firstprivate-polymorphic.f90
    flang/test/Lower/OpenMP/workshare-firstprivate.f90

Modified: 
    llvm/include/llvm/Frontend/OpenMP/ConstructDecompositionT.h

Removed: 
    


################################################################################
diff  --git a/flang/test/Lower/OpenMP/Todo/workshare-firstprivate-polymorphic.f90 b/flang/test/Lower/OpenMP/Todo/workshare-firstprivate-polymorphic.f90
new file mode 100644
index 0000000000000..5fbcf2c13c179
--- /dev/null
+++ b/flang/test/Lower/OpenMP/Todo/workshare-firstprivate-polymorphic.f90
@@ -0,0 +1,23 @@
+! Tests that firstprivate of a polymorphic variable in a parallel workshare
+! region is not yet supported.
+
+! RUN: %not_todo_cmd %flang_fc1 -emit-hlfir -fopenmp -o - %s 2>&1 | FileCheck %s
+
+module shapes
+  type :: shape
+    real :: area
+  end type
+end module
+
+subroutine poly_workshare_firstprivate(p, a, n)
+  use shapes
+  implicit none
+  integer :: n
+  class(shape), allocatable :: p(:)
+  real :: a(n)
+
+  !CHECK: not yet implemented: create polymorphic host associated copy
+  !$omp parallel workshare firstprivate(p)
+    a = p%area + 1.0
+  !$omp end parallel workshare
+end subroutine

diff  --git a/flang/test/Lower/OpenMP/workshare-firstprivate.f90 b/flang/test/Lower/OpenMP/workshare-firstprivate.f90
new file mode 100644
index 0000000000000..7625f9e111fcc
--- /dev/null
+++ b/flang/test/Lower/OpenMP/workshare-firstprivate.f90
@@ -0,0 +1,53 @@
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=51 %s -o - | FileCheck %s --check-prefix HLFIR
+! RUN: %flang_fc1 -emit-fir -fopenmp -fopenmp-version=51 %s -o - | FileCheck %s --check-prefix FIR
+
+! firstprivate on "parallel workshare" is applied to the parallel leaf, so it
+! uses the standard omp.private delayed privatization. After the LowerWorkshare
+! pass the private clause is preserved on omp.parallel; array assignments are
+! workshared (omp.wsloop) while FORALL runs in omp.single.
+
+! HLFIR: omp.private {type = firstprivate} @{{.*}}_firstprivate_box_ptr_Uxi32 : !fir.box<!fir.ptr<!fir.array<?xi32>>>
+! HLFIR: omp.private {type = firstprivate} @{{.*}}_firstprivate_box_heap_Uxi32 : !fir.box<!fir.heap<!fir.array<?xi32>>>
+! HLFIR: hlfir.assign %{{.*}} to %{{.*}} realloc
+
+! Pointer firstprivate, array assignment -> workshared loop.
+subroutine test_ptr(p)
+  integer, pointer, intent(in) :: p(:)
+  integer :: a(4)
+  !$omp parallel workshare firstprivate(p)
+    a = p + 1
+  !$omp end parallel workshare
+end subroutine
+
+! FIR-LABEL: func.func @{{.*}}test_ptr(
+! FIR:         omp.parallel private(@{{.*}}test_ptrEp_firstprivate{{.*}} -> %{{.*}} :
+! FIR-SAME:        !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>) {
+! FIR:           omp.wsloop
+
+! Allocatable firstprivate, array assignment -> workshared loop.
+subroutine test_alloc(p)
+  integer, allocatable :: p(:)
+  integer :: a(4)
+  !$omp parallel workshare firstprivate(p)
+    a = p + 1
+  !$omp end parallel workshare
+end subroutine
+
+! FIR-LABEL: func.func @{{.*}}test_alloc(
+! FIR:         omp.parallel private(@{{.*}}test_allocEp_firstprivate{{.*}} -> %{{.*}} :
+! FIR-SAME:        !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) {
+! FIR:           omp.wsloop
+
+! FORALL body runs in omp.single (not workshared).
+subroutine test_forall(p)
+  integer, pointer, intent(in) :: p(:)
+  integer :: i
+  !$omp parallel workshare firstprivate(p)
+    forall (i=1:size(p)) p(i) = i*i
+  !$omp end parallel workshare
+end subroutine
+
+! FIR-LABEL: func.func @{{.*}}test_forall(
+! FIR:         omp.parallel private(@{{.*}}test_forallEp_firstprivate{{.*}} -> %{{.*}} :
+! FIR-SAME:        !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>) {
+! FIR:           omp.single

diff  --git a/llvm/include/llvm/Frontend/OpenMP/ConstructDecompositionT.h b/llvm/include/llvm/Frontend/OpenMP/ConstructDecompositionT.h
index 7bd55875eec45..ffb340e610f40 100644
--- a/llvm/include/llvm/Frontend/OpenMP/ConstructDecompositionT.h
+++ b/llvm/include/llvm/Frontend/OpenMP/ConstructDecompositionT.h
@@ -612,17 +612,20 @@ bool ConstructDecompositionT<C, H>::applyClause(
   }
 
   // [5.2:340:8]
-  auto findWorksharing = [&]() {
+  // Match only a worksharing construct that accepts firstprivate; "workshare"
+  // does not, so it falls through to "parallel" per [5.2:340:10].
+  auto findWorksharingAcceptingFirstprivate = [&]() {
     auto worksharing = getWorksharing();
     for (auto &leaf : leafs) {
       auto found = llvm::find(worksharing, leaf.id);
-      if (found != std::end(worksharing))
+      if (found != std::end(worksharing) &&
+          llvm::omp::isAllowedClauseForDirective(leaf.id, input->id, version))
         return &leaf;
     }
     return static_cast<typename decltype(leafs)::value_type *>(nullptr);
   };
 
-  auto dirWorksharing = findWorksharing();
+  auto dirWorksharing = findWorksharingAcceptingFirstprivate();
   if (dirWorksharing != nullptr) {
     dirWorksharing->clauses.push_back(input);
     applied = true;


        


More information about the flang-commits mailing list