Hi!

On 2026-06-23T19:58:37+0200, Paul-Antoine Arras <[email protected]> wrote:
> On 22/06/2026 23:14, Tobias Burnus wrote:
>> [...], can you also add a -fdump-tree-… test to check for 
>> GOMP_atomic_{start,end}?
>
> Added atomic-builtins-1.c in the updated patch.

> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/gomp/atomic-builtins-1.c
> @@ -0,0 +1,13 @@
> +/* { dg-do compile } */
> +/* { dg-additional-options "-fdump-tree-ompexp" } */
> +
> +/* Check that an GIMPLE_OMP_ATOMIC statement expands to GOMP_atomic_start/end
> +   when atomic operations cannot be used and a mutex is required.  */
> +
> +void bar (__int128 a, __int128 b) {
> +  #pragma omp atomic capture
> +    b = a++;
> +}
> +
> +/* { dg-final { scan-tree-dump "GOMP_atomic_start" "ompexp" } } */
> +/* { dg-final { scan-tree-dump "GOMP_atomic_end" "ompexp" } } */

I see, for example, on 32-bit x86 (x86_64 with '-m32'):

    {+FAIL: c-c++-common/gomp/atomic-builtins-1.c (test for excess errors)+}
    {+UNRESOLVED: c-c++-common/gomp/atomic-builtins-1.c scan-tree-dump ompexp 
"GOMP_atomic_end"+}
    {+UNRESOLVED: c-c++-common/gomp/atomic-builtins-1.c scan-tree-dump ompexp 
"GOMP_atomic_start"+}

    {+FAIL: c-c++-common/gomp/atomic-builtins-1.c  -std=c++20 (test for excess 
errors)+}
    {+UNRESOLVED: c-c++-common/gomp/atomic-builtins-1.c  -std=c++20  
scan-tree-dump ompexp "GOMP_atomic_start"+}
    {+UNRESOLVED: c-c++-common/gomp/atomic-builtins-1.c  -std=c++20  
scan-tree-dump ompexp "GOMP_atomic_end"+}
    [Etc.]

    [...]/c-c++-common/gomp/atomic-builtins-1.c:7:6: error: variable or field 
'bar' declared void
    [...]/c-c++-common/gomp/atomic-builtins-1.c:7:11: error: expected 
primary-expression before '__int128'
    [...]/c-c++-common/gomp/atomic-builtins-1.c:7:23: error: expected 
primary-expression before '__int128'

That would be solved via 'int128' effective-target?

But, I also see, for example, on powerpc64le:

    {+PASS: c-c++-common/gomp/atomic-builtins-1.c (test for excess errors)+}
    {+FAIL: c-c++-common/gomp/atomic-builtins-1.c scan-tree-dump ompexp 
"GOMP_atomic_end"+}
    {+FAIL: c-c++-common/gomp/atomic-builtins-1.c scan-tree-dump ompexp 
"GOMP_atomic_start"+}

    {+PASS: c-c++-common/gomp/atomic-builtins-1.c  -std=c++20 (test for excess 
errors)+}
    {+FAIL: c-c++-common/gomp/atomic-builtins-1.c  -std=c++20  scan-tree-dump 
ompexp "GOMP_atomic_end"+}
    {+FAIL: c-c++-common/gomp/atomic-builtins-1.c  -std=c++20  scan-tree-dump 
ompexp "GOMP_atomic_start"+}
    [Etc.]

    $ cat < atomic-builtins-1.c.018t.ompexp
    
    [...]
    void bar (__int128 a, __int128 b)
    {
      __int128 unsigned D.4235;
      __int128 * D.4232;
      __int128 D.4234;
    
      <bb 2> :
      D.4232 = &a;
      D.4235 = __atomic_fetch_add_16 (D.4232, 1, 0);
      D.4234 = (__int128) D.4235;
      b = D.4234;
      return;
    
    }

How to restrict this test case accordingly -- I would've thought a new
'sync_int128' effective-target keyword?  But, I see we already have
(undocumented):

    # Return 1 if the target supports atomic operations on "int_128" values.
    
    proc check_effective_target_sync_int_128 { } {
        return 0
    }

Huh.  So, might use that (that is, skip test case for 'sync_int_128'),
and (separate patch) discuss with PowerPC back end maintainers whether
powerpc64le should 'return 1' here?  (..., and possibly also for
'check_effective_target_sync_int_128_runtime'?)


Grüße
 Thomas


> From 49a94a74b852eb8cc078dcb3e152971389d8bc17 Mon Sep 17 00:00:00 2001
> From: Paul-Antoine Arras <[email protected]>
> Date: Fri, 19 Jun 2026 16:53:21 +0200
> Subject: [PATCH v2 4/4] openmp: Add GOMP_reduction_start and
>  GOMP_reduction_end
>
> When lowering reduction clauses, the compiler brackets the critical section
> around the accumulation step with calls to GOMP_atomic_start and
> GOMP_atomic_end. These are the same entry points used for `#pragma omp atomic'
> constructs, so OMPT cannot distinguish reductions from user atomics.
>
> Introduce dedicated GOMP_reduction_start and GOMP_reduction_end entry
> points in libgomp. Update omp-low to emit calls to the new builtins
> instead.
>
> Also register the new builtins as memory barriers to avoid illegal 
> optimisations
> in later passes.
>
> gcc/ChangeLog:
>
>       * omp-builtins.def (BUILT_IN_GOMP_REDUCTION_START): New builtin.
>       (BUILT_IN_GOMP_REDUCTION_END): New builtin.
>       * omp-low.cc (lower_reduction_clauses): Replace
>       BUILT_IN_GOMP_ATOMIC_START / BUILT_IN_GOMP_ATOMIC_END with
>       BUILT_IN_GOMP_REDUCTION_START / BUILT_IN_GOMP_REDUCTION_END.
>       (lower_omp_sections): Likewise.
>       (lower_omp_scope): Likewise.
>       (lower_omp_for): Likewise.
>       * tree-ssa-alias.cc (check_fnspec): Handle
>       BUILT_IN_GOMP_REDUCTION_START and BUILT_IN_GOMP_REDUCTION_END as
>       memory barriers.
>
> libgomp/ChangeLog:
>
>       * atomic.c (GOMP_reduction_start): New function.
>       (GOMP_reduction_end): New function.
>       * libgomp.map (GOMP_6.0.2): Export GOMP_reduction_start and
>       GOMP_reduction_end.
>       * libgomp_g.h (GOMP_reduction_start): New declaration.
>       (GOMP_reduction_end): New declaration.
>
> gcc/testsuite/ChangeLog:
>
>       * c-c++-common/gomp/atomic-builtins-1.c: New test.
>       * c-c++-common/gomp/reduction-builtins-1.c: New test.
> ---
>  gcc/omp-builtins.def                          |  4 ++
>  gcc/omp-low.cc                                | 19 ++++----
>  .../c-c++-common/gomp/atomic-builtins-1.c     | 13 +++++
>  .../c-c++-common/gomp/reduction-builtins-1.c  | 47 +++++++++++++++++++
>  gcc/tree-ssa-alias.cc                         |  2 +
>  libgomp/atomic.c                              | 12 +++++
>  libgomp/libgomp.map                           |  2 +
>  libgomp/libgomp_g.h                           |  2 +
>  8 files changed, 92 insertions(+), 9 deletions(-)
>  create mode 100644 gcc/testsuite/c-c++-common/gomp/atomic-builtins-1.c
>  create mode 100644 gcc/testsuite/c-c++-common/gomp/reduction-builtins-1.c
>
> diff --git a/gcc/omp-builtins.def b/gcc/omp-builtins.def
> index 0a9dde8f618..d7440a42761 100644
> --- a/gcc/omp-builtins.def
> +++ b/gcc/omp-builtins.def
> @@ -98,6 +98,10 @@ DEF_GOMP_BUILTIN (BUILT_IN_GOMP_ATOMIC_START, 
> "GOMP_atomic_start",
>                 BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
>  DEF_GOMP_BUILTIN (BUILT_IN_GOMP_ATOMIC_END, "GOMP_atomic_end",
>                 BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
> +DEF_GOMP_BUILTIN (BUILT_IN_GOMP_REDUCTION_START, "GOMP_reduction_start",
> +               BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
> +DEF_GOMP_BUILTIN (BUILT_IN_GOMP_REDUCTION_END, "GOMP_reduction_end",
> +               BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
>  DEF_GOMP_BUILTIN (BUILT_IN_GOMP_BARRIER, "GOMP_barrier_ext", BT_FN_VOID_INT,
>                 ATTR_NOTHROW_LEAF_LIST)
>  DEF_GOMP_BUILTIN (BUILT_IN_GOMP_BARRIER_CANCEL, "GOMP_barrier_cancel_ext",
> diff --git a/gcc/omp-low.cc b/gcc/omp-low.cc
> index 9160cdae640..1a383d31c51 100644
> --- a/gcc/omp-low.cc
> +++ b/gcc/omp-low.cc
> @@ -8000,8 +8000,9 @@ lower_reduction_clauses (tree clauses, gimple_seq 
> *stmt_seqp,
>       }
>      }
>  
> -  stmt = gimple_build_call (builtin_decl_explicit 
> (BUILT_IN_GOMP_ATOMIC_START),
> -                         0);
> +  stmt
> +    = gimple_build_call (builtin_decl_explicit 
> (BUILT_IN_GOMP_REDUCTION_START),
> +                      0);
>    gimple_seq_add_stmt (stmt_seqp, stmt);
>  
>    gimple_seq_add_seq (stmt_seqp, sub_seq);
> @@ -8012,7 +8013,7 @@ lower_reduction_clauses (tree clauses, gimple_seq 
> *stmt_seqp,
>        *clist = NULL;
>      }
>  
> -  stmt = gimple_build_call (builtin_decl_explicit (BUILT_IN_GOMP_ATOMIC_END),
> +  stmt = gimple_build_call (builtin_decl_explicit 
> (BUILT_IN_GOMP_REDUCTION_END),
>                           0);
>    gimple_seq_add_stmt (stmt_seqp, stmt);
>  }
> @@ -8716,11 +8717,11 @@ lower_omp_sections (gimple_stmt_iterator *gsi_p, 
> omp_context *ctx)
>                          &clist, ctx);
>    if (clist)
>      {
> -      tree fndecl = builtin_decl_explicit (BUILT_IN_GOMP_ATOMIC_START);
> +      tree fndecl = builtin_decl_explicit (BUILT_IN_GOMP_REDUCTION_START);
>        gcall *g = gimple_build_call (fndecl, 0);
>        gimple_seq_add_stmt (&olist, g);
>        gimple_seq_add_seq (&olist, clist);
> -      fndecl = builtin_decl_explicit (BUILT_IN_GOMP_ATOMIC_END);
> +      fndecl = builtin_decl_explicit (BUILT_IN_GOMP_REDUCTION_END);
>        g = gimple_build_call (fndecl, 0);
>        gimple_seq_add_stmt (&olist, g);
>      }
> @@ -8995,11 +8996,11 @@ lower_omp_scope (gimple_stmt_iterator *gsi_p, 
> omp_context *ctx)
>                          &bind_body, &clist, ctx);
>    if (clist)
>      {
> -      tree fndecl = builtin_decl_explicit (BUILT_IN_GOMP_ATOMIC_START);
> +      tree fndecl = builtin_decl_explicit (BUILT_IN_GOMP_REDUCTION_START);
>        gcall *g = gimple_build_call (fndecl, 0);
>        gimple_seq_add_stmt (&bind_body, g);
>        gimple_seq_add_seq (&bind_body, clist);
> -      fndecl = builtin_decl_explicit (BUILT_IN_GOMP_ATOMIC_END);
> +      fndecl = builtin_decl_explicit (BUILT_IN_GOMP_REDUCTION_END);
>        g = gimple_build_call (fndecl, 0);
>        gimple_seq_add_stmt (&bind_body, g);
>      }
> @@ -11952,11 +11953,11 @@ lower_omp_for (gimple_stmt_iterator *gsi_p, 
> omp_context *ctx)
>  
>    if (clist)
>      {
> -      tree fndecl = builtin_decl_explicit (BUILT_IN_GOMP_ATOMIC_START);
> +      tree fndecl = builtin_decl_explicit (BUILT_IN_GOMP_REDUCTION_START);
>        gcall *g = gimple_build_call (fndecl, 0);
>        gimple_seq_add_stmt (&body, g);
>        gimple_seq_add_seq (&body, clist);
> -      fndecl = builtin_decl_explicit (BUILT_IN_GOMP_ATOMIC_END);
> +      fndecl = builtin_decl_explicit (BUILT_IN_GOMP_REDUCTION_END);
>        g = gimple_build_call (fndecl, 0);
>        gimple_seq_add_stmt (&body, g);
>      }
> diff --git a/gcc/testsuite/c-c++-common/gomp/atomic-builtins-1.c 
> b/gcc/testsuite/c-c++-common/gomp/atomic-builtins-1.c
> new file mode 100644
> index 00000000000..75b34319ddb
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/gomp/atomic-builtins-1.c
> @@ -0,0 +1,13 @@
> +/* { dg-do compile } */
> +/* { dg-additional-options "-fdump-tree-ompexp" } */
> +
> +/* Check that an GIMPLE_OMP_ATOMIC statement expands to GOMP_atomic_start/end
> +   when atomic operations cannot be used and a mutex is required.  */
> +
> +void bar (__int128 a, __int128 b) {
> +  #pragma omp atomic capture
> +    b = a++;
> +}
> +
> +/* { dg-final { scan-tree-dump "GOMP_atomic_start" "ompexp" } } */
> +/* { dg-final { scan-tree-dump "GOMP_atomic_end" "ompexp" } } */
> diff --git a/gcc/testsuite/c-c++-common/gomp/reduction-builtins-1.c 
> b/gcc/testsuite/c-c++-common/gomp/reduction-builtins-1.c
> new file mode 100644
> index 00000000000..bef786be374
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/gomp/reduction-builtins-1.c
> @@ -0,0 +1,47 @@
> +/* { dg-do compile } */
> +/* { dg-additional-options "-fdump-tree-omplower" } */
> +
> +/* Check that, for reductions, critical sections are bracketed with
> +   GOMP_reduction_start/end rather than GOMP_atomic_start/end. Two scalar
> +   reductions force the critical-section path (a single scalar reduction 
> would
> +   use an atomic update instead).  */
> +
> +void foo (int);
> +
> +void r_for (int n) {
> +  int a = 0, b = 0, i;
> +  #pragma omp parallel
> +  #pragma omp for reduction(+: a, b)
> +  for (i = 0; i < n; i++) { a += i; b += i; }
> +}
> +
> +void r_sections (void) {
> +  int a = 0, b = 0;
> +  #pragma omp parallel
> +  #pragma omp sections reduction(+: a, b)
> +  { foo (a + b); }
> +}
> +
> +void r_scope (void) {
> +  int a = 0, b = 0;
> +  #pragma omp parallel
> +  #pragma omp scope reduction(+: a, b)
> +  foo (a + b);
> +}
> +
> +void r_teams (void) {
> +  int a = 0, b = 0;
> +  #pragma omp teams reduction(+: a, b)
> +  foo (a + b);
> +}
> +
> +void r_parallel (void) {
> +  int a = 0, b = 0;
> +  #pragma omp parallel reduction(+: a, b)
> +  foo (a + b);
> +}
> +
> +/* { dg-final { scan-tree-dump-times "GOMP_reduction_start \\(" 5 "omplower" 
> } } */
> +/* { dg-final { scan-tree-dump-times "GOMP_reduction_end \\(" 5 "omplower" } 
> } */
> +/* { dg-final { scan-tree-dump-not "GOMP_atomic_start" "omplower" } } */
> +/* { dg-final { scan-tree-dump-not "GOMP_atomic_end" "omplower" } } */
> diff --git a/gcc/tree-ssa-alias.cc b/gcc/tree-ssa-alias.cc
> index 9f3dd2adac0..467ef1c215f 100644
> --- a/gcc/tree-ssa-alias.cc
> +++ b/gcc/tree-ssa-alias.cc
> @@ -2807,6 +2807,8 @@ check_fnspec (gcall *call, ao_ref *ref, bool clobber)
>  #undef DEF_SYNC_BUILTIN
>        case BUILT_IN_GOMP_ATOMIC_START:
>        case BUILT_IN_GOMP_ATOMIC_END:
> +      case BUILT_IN_GOMP_REDUCTION_START:
> +      case BUILT_IN_GOMP_REDUCTION_END:
>        case BUILT_IN_GOMP_BARRIER:
>        case BUILT_IN_GOMP_BARRIER_CANCEL:
>        case BUILT_IN_GOMP_TASKWAIT:
> diff --git a/libgomp/atomic.c b/libgomp/atomic.c
> index df5b810eaef..0167cdfa40a 100644
> --- a/libgomp/atomic.c
> +++ b/libgomp/atomic.c
> @@ -48,6 +48,18 @@ GOMP_atomic_end (void)
>    gomp_mutex_unlock (&atomic_lock);
>  }
>  
> +void
> +GOMP_reduction_start (void)
> +{
> +  gomp_mutex_lock (&atomic_lock);
> +}
> +
> +void
> +GOMP_reduction_end (void)
> +{
> +  gomp_mutex_unlock (&atomic_lock);
> +}
> +
>  #if !GOMP_MUTEX_INIT_0
>  static void __attribute__((constructor))
>  initialize_atomic (void)
> diff --git a/libgomp/libgomp.map b/libgomp/libgomp.map
> index 92ef5c298f4..e2985347bf7 100644
> --- a/libgomp/libgomp.map
> +++ b/libgomp/libgomp.map
> @@ -489,6 +489,8 @@ GOMP_6.0.2 {
>       GOMP_distribute_static_worksharing;
>       GOMP_barrier_ext;
>       GOMP_barrier_cancel_ext;
> +     GOMP_reduction_start;
> +     GOMP_reduction_end;
>  } GOMP_6.0.1;
>  
>  OACC_2.0 {
> diff --git a/libgomp/libgomp_g.h b/libgomp/libgomp_g.h
> index 89ed7b3462e..892ad3a5581 100644
> --- a/libgomp/libgomp_g.h
> +++ b/libgomp/libgomp_g.h
> @@ -51,6 +51,8 @@ extern void GOMP_critical_start (void);
>  extern void GOMP_critical_end (void);
>  extern void GOMP_critical_name_start (void **);
>  extern void GOMP_critical_name_end (void **);
> +extern void GOMP_reduction_start (void);
> +extern void GOMP_reduction_end (void);
>  
>  /* loop.c */
>  
> -- 
> 2.53.0

Reply via email to