[flang-commits] [flang] [flang][OpenMP] Don't emit a privatization barrier for TASKLOOP (PR #228826)

via flang-commits flang-commits at lists.llvm.org
Sat Oct 3 22:25:57 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-flang-openmp

Author: Aditya Trivedi (adit4443ya)

<details>
<summary>Changes</summary>

Task privates are initialized by the encountering thread alone, so the barrier is unnecessary and deadlocks when one thread runs the taskloop (e.g. inside MASTER or SINGLE).

Fixes #<!-- -->186286

---
Full diff: https://github.com/llvm/llvm-project/pull/228826.diff


4 Files Affected:

- (modified) flang/lib/Lower/OpenMP/DataSharingProcessor.cpp (+7-2) 
- (modified) flang/lib/Lower/OpenMP/DataSharingProcessor.h (+2-1) 
- (modified) flang/lib/Lower/OpenMP/OpenMP.cpp (+1-1) 
- (added) flang/test/Lower/OpenMP/taskloop-lastprivate-barrier.f90 (+69) 


``````````diff
diff --git a/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp b/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp
index 8d0d191058cfb..77c37ec2d84df 100644
--- a/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp
+++ b/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp
@@ -123,7 +123,7 @@ void DataSharingProcessor::processStep1(
 
   privatize(clauseOps, dir);
 
-  insertBarrier(clauseOps);
+  insertBarrier(clauseOps, dir);
 }
 
 void DataSharingProcessor::processStep2(mlir::Operation *op, bool isLoop) {
@@ -382,7 +382,12 @@ bool DataSharingProcessor::needBarrier() {
 }
 
 void DataSharingProcessor::insertBarrier(
-    mlir::omp::PrivateClauseOps *clauseOps) {
+    mlir::omp::PrivateClauseOps *clauseOps,
+    std::optional<llvm::omp::Directive> dir) {
+  // Task privates are set up by the encountering thread only; no barrier.
+  if (dir && llvm::omp::taskGeneratingSet.test(*dir))
+    return;
+
   if (!needBarrier())
     return;
 
diff --git a/flang/lib/Lower/OpenMP/DataSharingProcessor.h b/flang/lib/Lower/OpenMP/DataSharingProcessor.h
index 25d848c8baffc..d0e2f1116e014 100644
--- a/flang/lib/Lower/OpenMP/DataSharingProcessor.h
+++ b/flang/lib/Lower/OpenMP/DataSharingProcessor.h
@@ -150,7 +150,8 @@ class DataSharingProcessor {
       const omp::ObjectList &objects,
       llvm::SetVector<const semantics::Symbol *> &symbolSet);
   void collectSymbolsForPrivatization();
-  void insertBarrier(mlir::omp::PrivateClauseOps *clauseOps);
+  void insertBarrier(mlir::omp::PrivateClauseOps *clauseOps,
+                     std::optional<llvm::omp::Directive> dir);
   void collectDefaultSymbols();
   void collectImplicitSymbols();
   void collectPreDeterminedSymbols();
diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index 99a7882a658c8..3534b202c4c91 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -5307,7 +5307,7 @@ static mlir::omp::TaskloopContextOp genStandaloneTaskloop(
   DataSharingProcessor dsp(converter, semaCtx, item->clauses, eval,
                            /*shouldCollectPreDeterminedSymbols=*/true,
                            enableDelayedPrivatization, symTable);
-  dsp.processStep1(&taskloopClauseOps);
+  dsp.processStep1(&taskloopClauseOps, llvm::omp::Directive::OMPD_taskloop);
 
   if (hasPrivatizedArrayElementReduction(inReductionObjects,
                                          dsp.getAllSymbolsToPrivatize()))
diff --git a/flang/test/Lower/OpenMP/taskloop-lastprivate-barrier.f90 b/flang/test/Lower/OpenMP/taskloop-lastprivate-barrier.f90
new file mode 100644
index 0000000000000..61e12ad247234
--- /dev/null
+++ b/flang/test/Lower/OpenMP/taskloop-lastprivate-barrier.f90
@@ -0,0 +1,69 @@
+! TASKLOOP must not request a privatization barrier; worksharing loops still do.
+
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -o - %s 2>&1 | FileCheck %s
+! RUN: bbc -emit-hlfir -fopenmp -o - %s 2>&1 | FileCheck %s
+
+! Allocatable privatizer reads the original (mold).
+! CHECK-LABEL: func.func @_QPtaskloop_lastprivate_allocatable
+! CHECK:         omp.taskloop.context private(@{{.*}}Ea_private_box_heap_Uxi32
+! CHECK-NOT:     private_barrier
+! CHECK-SAME:    {
+! CHECK-NOT:     omp.barrier
+! CHECK:         omp.taskloop.wrapper
+subroutine taskloop_lastprivate_allocatable()
+  integer, allocatable :: a(:)
+  integer :: i
+  allocate(a(100))
+  a = -1
+  !$omp taskloop lastprivate(a)
+  do i = 1, 1
+    a(i) = i
+  end do
+  !$omp end taskloop
+end subroutine
+
+! Same variable firstprivate and lastprivate.
+! CHECK-LABEL: func.func @_QPtaskloop_first_and_lastprivate
+! CHECK:         omp.taskloop.context private(@{{.*}}Ex_firstprivate_i32
+! CHECK-NOT:     private_barrier
+! CHECK-SAME:    {
+! CHECK-NOT:     omp.barrier
+! CHECK:         omp.taskloop.wrapper
+subroutine taskloop_first_and_lastprivate()
+  integer :: x, i
+  x = 5
+  !$omp taskloop firstprivate(x) lastprivate(x)
+  do i = 1, 4
+    x = x + i
+  end do
+  !$omp end taskloop
+end subroutine
+
+! CHECK-LABEL: func.func @_QPtaskloop_nogroup_first_and_lastprivate
+! CHECK:         omp.taskloop.context nogroup private(@{{.*}}Ex_firstprivate_i32
+! CHECK-NOT:     private_barrier
+! CHECK-SAME:    {
+subroutine taskloop_nogroup_first_and_lastprivate()
+  integer :: x, i
+  x = 5
+  !$omp taskloop nogroup firstprivate(x) lastprivate(x)
+  do i = 1, 4
+    x = x + i
+  end do
+  !$omp end taskloop
+end subroutine
+
+! DO keeps the barrier.
+! CHECK-LABEL: func.func @_QPdo_first_and_lastprivate
+! CHECK:         omp.wsloop private(@{{.*}}Ex_firstprivate_i32 {{.*}}) private_barrier {
+subroutine do_first_and_lastprivate()
+  integer :: x, i
+  x = 5
+  !$omp parallel
+  !$omp do firstprivate(x) lastprivate(x)
+  do i = 1, 4
+    x = x + i
+  end do
+  !$omp end do
+  !$omp end parallel
+end subroutine

``````````

</details>


https://github.com/llvm/llvm-project/pull/228826


More information about the flang-commits mailing list