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

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


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

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

>From 7af11cbedae64971297be4395c50aad72f61b8b5 Mon Sep 17 00:00:00 2001
From: Aditya Trivedi <adit4443ya at gmail.com>
Date: Wed, 30 Sep 2026 13:53:53 +0530
Subject: [PATCH] [flang][OpenMP] Don't emit a privatization barrier for
 TASKLOOP

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
---
 .../lib/Lower/OpenMP/DataSharingProcessor.cpp |  9 ++-
 flang/lib/Lower/OpenMP/DataSharingProcessor.h |  3 +-
 flang/lib/Lower/OpenMP/OpenMP.cpp             |  2 +-
 .../OpenMP/taskloop-lastprivate-barrier.f90   | 69 +++++++++++++++++++
 4 files changed, 79 insertions(+), 4 deletions(-)
 create mode 100644 flang/test/Lower/OpenMP/taskloop-lastprivate-barrier.f90

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



More information about the flang-commits mailing list