[flang-commits] [flang] 43d1336 - [Flang][OpenMP] Fix Flang crash and incorrect ordering with OpenMP detached task (#194840)

via flang-commits flang-commits at lists.llvm.org
Thu May 7 03:45:41 PDT 2026


Author: Urvi Rav
Date: 2026-05-07T16:15:35+05:30
New Revision: 43d13365f875e6eeeb50b77cc1af49543cbece8d

URL: https://github.com/llvm/llvm-project/commit/43d13365f875e6eeeb50b77cc1af49543cbece8d
DIFF: https://github.com/llvm/llvm-project/commit/43d13365f875e6eeeb50b77cc1af49543cbece8d.diff

LOG: [Flang][OpenMP] Fix Flang crash and incorrect ordering with OpenMP detached task (#194840)

Fixes - [#194563](https://github.com/llvm/llvm-project/issues/194563)

This PR fixes the runtime crash and incorrect task ordering reported in
the testcase involving:
```
!$omp task if(.false.) depend(out:x) detach(ev)
```
The testcase had two issues:

**1. Segmentation fault near omp_fulfill_event(ev)**
The detach event handle was not being initialized or preserved correctly
before the nested task used it.
**2. Incorrect execution order**
The task with depend(in:x) was running before the detach event was
fulfilled, which violates OpenMP dependency semantics.

#### Changes in this PR

1. Treat `parallel master` as a top-level parallel construct in Flang
semantics to ensure correct data-sharing behavior.
2. Treat variables used in `detach(...)` as shared so the event handle
remains valid across tasks.
3. Fix `OMPIRBuilder` lowering for task `if(.false.)` to use merged-if0
behavior through the normal task runtime path, ensuring correct task
allocation, event creation, dependency registration, and proper waiting
until `omp_fulfill_event(ev)`.
4. Add an MLIR regression test for `if(false) + depend + detach`.

Added: 
    flang/test/Semantics/OpenMP/detach-symbols.f90

Modified: 
    flang/include/flang/Semantics/openmp-directive-sets.h
    flang/lib/Semantics/resolve-directives.cpp
    llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
    mlir/test/Target/LLVMIR/omptask_if_false.mlir

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Semantics/openmp-directive-sets.h b/flang/include/flang/Semantics/openmp-directive-sets.h
index 5e9979d032028..b99dd8fe07204 100644
--- a/flang/include/flang/Semantics/openmp-directive-sets.h
+++ b/flang/include/flang/Semantics/openmp-directive-sets.h
@@ -83,8 +83,10 @@ static const OmpDirectiveSet topParallelSet{
     Directive::OMPD_parallel_do,
     Directive::OMPD_parallel_do_simd,
     Directive::OMPD_parallel_loop,
+    Directive::OMPD_parallel_masked,
     Directive::OMPD_parallel_masked_taskloop,
     Directive::OMPD_parallel_masked_taskloop_simd,
+    Directive::OMPD_parallel_master,
     Directive::OMPD_parallel_master_taskloop,
     Directive::OMPD_parallel_master_taskloop_simd,
     Directive::OMPD_parallel_sections,

diff  --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index db6f4b013c05c..52cd445027d37 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -762,6 +762,17 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
         *parser::omp::GetOmpObjectList(x), Symbol::Flag::OmpLastPrivate);
     return false;
   }
+  bool Pre(const parser::OmpClause::Detach &x) {
+    // OpenMP 5.0: Variables in detach clause have predetermined shared
+    // data-sharing attribute
+    if (const auto *name{parser::Unwrap<parser::Name>(x.v.v)}) {
+      if (auto *symbol{name->symbol})
+        SetSymbolDSA(*symbol,
+            Symbol::Flags{
+                Symbol::Flag::OmpShared, Symbol::Flag::OmpPreDetermined});
+    }
+    return false;
+  }
   bool Pre(const parser::OmpClause::Copyin &x) {
     ResolveOmpObjectList(x.v, Symbol::Flag::OmpCopyIn);
     return false;

diff  --git a/flang/test/Semantics/OpenMP/detach-symbols.f90 b/flang/test/Semantics/OpenMP/detach-symbols.f90
new file mode 100644
index 0000000000000..eae5cc07ce67e
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/detach-symbols.f90
@@ -0,0 +1,17 @@
+! REQUIRES: openmp_runtime
+! RUN: %python %S/../test_symbols.py %s %flang_fc1 %openmp_flags -fopenmp-version=50
+
+! Test that variables in a DETACH clause get predetermined shared DSA.
+
+!DEF: /detach_symbol_dsa (Subroutine) Subprogram
+subroutine detach_symbol_dsa
+  !DEF: /omp_lib (ModFile) Module
+  !DEF: /omp_lib/omp_event_handle_kind PARAMETER, PUBLIC Use INTEGER(4)
+  use :: omp_lib, only: omp_event_handle_kind
+  !DEF: /detach_symbol_dsa/omp_event_handle_kind PARAMETER Use INTEGER(4)
+  !DEF: /detach_symbol_dsa/ev (OmpShared, OmpPreDetermined) ObjectEntity INTEGER(8)
+  integer(kind=omp_event_handle_kind) ev
+
+  !$omp task detach(ev)
+  !$omp end task
+end subroutine detach_symbol_dsa

diff  --git a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
index f00b4df505736..f17602e8e786c 100644
--- a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
+++ b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
@@ -2728,20 +2728,26 @@ OpenMPIRBuilder::InsertPointOrErrorTy OpenMPIRBuilder::createTask(
     // Task is untied iff (Flags & 1) == 0.
     // Task is final iff (Flags & 2) == 2.
     // Task is not final iff (Flags & 2) == 0.
-    // Task is mergeable iff (Flags & 4) == 4.
-    // Task is not mergeable iff (Flags & 4) == 0.
+    // Task is mergeable or merged-if0 iff (Flags & 4) == 4.
+    // Task is neither mergeable nor merged-if0 iff (Flags & 4) == 0.
+    // Task is detachable iff (Flags & 64) == 64.
+    // Task is not detachable iff (Flags & 64) == 0.
     // Task is priority iff (Flags & 32) == 32.
     // Task is not priority iff (Flags & 32) == 0.
     // TODO: Handle the other flags.
     Value *Flags = Builder.getInt32(Tied);
+    auto *ConstIfCondition = dyn_cast_or_null<ConstantInt>(IfCondition);
+    bool UseMergedIf0Path = ConstIfCondition && ConstIfCondition->isZero();
     if (Final) {
       Value *FinalFlag =
           Builder.CreateSelect(Final, Builder.getInt32(2), Builder.getInt32(0));
       Flags = Builder.CreateOr(FinalFlag, Flags);
     }
 
-    if (Mergeable)
+    if (Mergeable || UseMergedIf0Path)
       Flags = Builder.CreateOr(Builder.getInt32(4), Flags);
+    if (EventHandle)
+      Flags = Builder.CreateOr(Builder.getInt32(64), Flags);
     if (Priority)
       Flags = Builder.CreateOr(Builder.getInt32(32), Flags);
 
@@ -2861,7 +2867,7 @@ OpenMPIRBuilder::InsertPointOrErrorTy OpenMPIRBuilder::createTask(
     //    br label %exit
     //  exit:
     //    ...
-    if (IfCondition) {
+    if (IfCondition && !UseMergedIf0Path) {
       // `SplitBlockAndInsertIfThenElse` requires the block to have a
       // terminator.
       splitBB(Builder, /*CreateBranch=*/true, "if.end");

diff  --git a/mlir/test/Target/LLVMIR/omptask_if_false.mlir b/mlir/test/Target/LLVMIR/omptask_if_false.mlir
index c6014a76add6d..7f71496b9a605 100644
--- a/mlir/test/Target/LLVMIR/omptask_if_false.mlir
+++ b/mlir/test/Target/LLVMIR/omptask_if_false.mlir
@@ -10,8 +10,24 @@ llvm.func @foo_(%arg0: !llvm.ptr {fir.bindc_name = "n"}, %arg1: !llvm.ptr {fir.b
   llvm.return
 }
 
-// CHECK: call void @__kmpc_omp_wait_deps
-// CHECK-NEXT: call void @__kmpc_omp_task_begin_if0
-// CHECK-NEXT: call void @foo_..omp_par
-// CHECK-NEXT: call void @__kmpc_omp_task_complete_if0
+// CHECK: call ptr @__kmpc_omp_task_alloc(ptr @{{.+}}, i32 %{{.+}}, i32 5, i64 40, i64 16, ptr @foo_..omp_par)
+// CHECK: call i32 @__kmpc_omp_task_with_deps(ptr @{{.+}}, i32 %{{.+}}, ptr %{{.+}}, i32 1, ptr %{{.+}}, i32 0, ptr null)
+
+// CHECK-LABEL: define void @foo_detach_if_false
+llvm.func @foo_detach_if_false(%arg0: !llvm.ptr {fir.bindc_name = "n"}, %arg1: !llvm.ptr {fir.bindc_name = "ev"}) {
+  %0 = llvm.mlir.constant(false) : i1
+  omp.task if(%0) depend(taskdependin -> %arg0 : !llvm.ptr) detach(%arg1 : !llvm.ptr) {
+    omp.terminator
+  }
+  llvm.return
+}
+
+// CHECK: %[[TID:.+]] = call i32 @__kmpc_global_thread_num(ptr @{{.+}})
+// CHECK: %[[TASK:.+]] = call ptr @__kmpc_omp_task_alloc(ptr @{{.+}}, i32 %[[TID]], i32 69, i64 40, i64 0, ptr @foo_detach_if_false..omp_par)
+// CHECK: %[[EVENT:.+]] = call ptr @__kmpc_task_allow_completion_event(ptr @{{.+}}, i32 %[[TID]], ptr %[[TASK]])
+// CHECK: %[[INT_EVENT:.+]] = ptrtoint ptr %[[EVENT]] to i64
+// CHECK: store i64 %[[INT_EVENT]], ptr %{{.+}}, align 4
+// CHECK: call i32 @__kmpc_omp_task_with_deps(ptr @{{.+}}, i32 %[[TID]], ptr %[[TASK]], i32 1, ptr %{{.+}}, i32 0, ptr null)
+// CHECK-NOT: @__kmpc_omp_task_begin_if0
+// CHECK-NOT: @__kmpc_omp_task_complete_if0
 


        


More information about the flang-commits mailing list