On 22/06/2026 23:14, Tobias Burnus wrote:
Paul-Antoine Arras wrote:
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.

LGTM. However, can you also add a -fdump-tree-… test to check for GOMP_atomic_{start,end}?

Added atomic-builtins-1.c in the updated patch.

Thanks,
--
PA
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