[all-commits] [llvm/llvm-project] abd72b: [OpenMP] Publish target-init team state with acq_r...

Abid Qadeer via All-commits all-commits at lists.llvm.org
Mon Jul 13 01:58:13 PDT 2026


  Branch: refs/heads/main
  Home:   https://github.com/llvm/llvm-project
  Commit: abd72b0eb7807a98c261a6cac35a969f954a76cd
      https://github.com/llvm/llvm-project/commit/abd72b0eb7807a98c261a6cac35a969f954a76cd
  Author: Abid Qadeer <haqadeer at amd.com>
  Date:   2026-07-13 (Mon, 13 Jul 2026)

  Changed paths:
    A offload/test/offloading/fortran/target-teams-if-runtime-init.f90
    M openmp/device/src/Kernel.cpp

  Log Message:
  -----------
  [OpenMP] Publish target-init team state with acq_rel barrier (#208701)

In __kmpc_target_init, thread 0 initializes the team state in LDS
(HasThreadState = 0, ThreadStates = nullptr) and then releases the other
threads with synchronize::threadsAligned(atomic::relaxed). Because the
relaxed ordering emits no memory fence, the initializing LDS stores are
not guaranteed to be visible to the worker threads before they proceed.
A worker thread can then read the uninitialized team state and produce
wrong results or crash. This is the flow that causes the race as I
understand it.

```
__kmpc_target_init                                    (Kernel.cpp:107)
  -> initializeRuntime                                (Kernel.cpp:38)
       -> state::init                                         (State.cpp:286)
            -> TeamState.init(IsSPMD)                 (State.cpp:295)
                 -> HasThreadState = false            (State.cpp:248)   // <-- the value later read stale
               ThreadStates = nullptr                 (State.cpp:296)
  -> synchronize::threadsAligned(atomic::relaxed)     (Kernel.cpp:115)  // <-- insufficient barrier:
     //     relaxed emits no fence, so the state stores above are not published to the other threads

        ... worker threads continue past the barrier ...

__kmpc_parallel_60                                    (Parallelism.cpp:143)
  if (OMP_UNLIKELY(!if_expr || state::HasThreadState || ...))   (Parallelism.cpp:158)
        ^ reads HasThreadState from LDS; a stale/unpublished value (!= 0)
          diverts the worker onto the wrong (serialized) path
```
The fix changes the barrier at Kernel.cpp:115 from atomic::relaxed to
atomic::acq_rel so that the memory fences are emitted.

Reproducing the problem requires an `if` clause with a non-constant
condition on the target region. The worker's read of HasThreadState
originates from the serialized-region check in __kmpc_parallel_60. When
the `if` condition is constant (or absent), the optimizer can prove that
branch is dead and eliminates the HasThreadState load entirely, so the
race has nothing to observe. A non-constant `if` keeps if_expr, and
hence the LDS read alive, exposing the problem.

I have added a Fortran offload regression test that launches a target
region many times to make the timing-dependent race likely to surface.

Fixes https://github.com/llvm/llvm-project/issues/208698.

Assisted-by: Cursor



To unsubscribe from these emails, change your notification settings at https://github.com/llvm/llvm-project/settings/notifications


More information about the All-commits mailing list