https://gcc.gnu.org/g:d50e9f17fffa9b047dcf02eb9e1fe499178a0f02
commit r17-1806-gd50e9f17fffa9b047dcf02eb9e1fe499178a0f02 Author: Paul-Antoine Arras <[email protected]> Date: Fri Jun 19 16:53:21 2026 +0200 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. Diff: --- 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(-) diff --git a/gcc/omp-builtins.def b/gcc/omp-builtins.def index 0a9dde8f6187..d7440a42761b 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 30a4d02f2e20..dbdbc4079f4d 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 000000000000..75b34319ddb6 --- /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 000000000000..bef786be374a --- /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 9f3dd2adac0b..467ef1c215f1 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 df5b810eaef8..0167cdfa40ae 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 92ef5c298f4d..e2985347bf77 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 89ed7b3462e3..892ad3a55810 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 */
