[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
Sun Oct 4 01:49:01 PDT 2026


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

>From 8092f0e0911453f81df1586be8c536b4cf833cb9 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 0b20eb1c16dc1..67def1a85c6c1 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -5178,7 +5178,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