]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
tree-ssa-dce: eliminate dead relaxed atomic loads with no LHS [PR123966]
authorEikansh Gupta <eikansh.gupta@oss.qualcomm.com>
Tue, 31 Mar 2026 11:21:00 +0000 (16:51 +0530)
committerAndrew Pinski <andrew.pinski@oss.qualcomm.com>
Fri, 24 Apr 2026 19:17:45 +0000 (12:17 -0700)
A relaxed atomic load whose result is never used has no observable
effect: the value is discarded and __ATOMIC_RELAXED provides no
inter-thread synchronisation guarantee.

Fix this by adding an early-return check for
BUILT_IN_ATOMIC_LOAD_1/2/4/8/16 calls that have no LHS and a
compile-time-constant relaxed memory order.

PR tree-optimization/123966

gcc/ChangeLog:
* tree-ssa-dce.cc (mark_stmt_if_obviously_necessary):
Don't mark a relaxed atomic load with no LHS as necessary.

gcc/testsuite/ChangeLog:
* gcc.dg/tree-ssa/pr123966.c: New test.

Signed-off-by: Eikansh Gupta <eikansh.gupta@oss.qualcomm.com>
gcc/testsuite/gcc.dg/tree-ssa/pr123966.c [new file with mode: 0644]
gcc/tree-ssa-dce.cc

diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr123966.c b/gcc/testsuite/gcc.dg/tree-ssa/pr123966.c
new file mode 100644 (file)
index 0000000..7658f1d
--- /dev/null
@@ -0,0 +1,71 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-cddce1" } */
+
+unsigned char  g1;
+unsigned short g2;
+unsigned int   g4;
+unsigned long long g8;
+
+/* Relaxed loads, result unused -- must be eliminated.  */
+void test_relaxed_1 (void)
+{
+  unsigned char r;
+  __atomic_load (&g1, &r, 0);
+}
+
+void test_relaxed_2 (void)
+{
+  unsigned short r;
+  __atomic_load (&g2, &r, 0);
+}
+
+void test_relaxed_4 (void)
+{
+  unsigned int r;
+  __atomic_load (&g4, &r, 0);
+}
+
+void test_relaxed_8 (void)
+{
+  unsigned long long r;
+  __atomic_load (&g8, &r, 0);
+}
+
+/* Non-relaxed orders, result unused -- must be preserved.  */
+void test_acquire (void)
+{
+  unsigned int r;
+  __atomic_load (&g4, &r, 2);
+}
+
+void test_seqcst (void)
+{
+  unsigned int r;
+  __atomic_load (&g4, &r, 5);
+}
+
+void test_consume (void)
+{
+  unsigned int r;
+  __atomic_load (&g4, &r, 1);
+}
+
+/* Runtime order -- must be preserved (order unknown at compile time).  */
+void test_runtime (int order)
+{
+  unsigned int r;
+  __atomic_load (&g4, &r, order);
+}
+
+/* Relaxed load but result is used -- must be preserved.  */
+unsigned int test_used (void)
+{
+  unsigned int r;
+  __atomic_load (&g4, &r, 0);
+  return r;
+}
+
+/* { dg-final { scan-tree-dump-times "__atomic_load_1" 0 "cddce1" } } */
+/* { dg-final { scan-tree-dump-times "__atomic_load_2" 0 "cddce1" } } */
+/* { dg-final { scan-tree-dump-times "__atomic_load_8" 0 "cddce1" } } */
+/* { dg-final { scan-tree-dump-times "__atomic_load_4" 5 "cddce1" } } */
index 7932607e889ff66e78537b34716b7f0836c3400e..bc8ae6d10f90d568ea6c81fa8fbd3f4db012c3ff 100644 (file)
@@ -70,6 +70,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-ssa.h"
 #include "ipa-modref-tree.h"
 #include "ipa-modref.h"
+#include "memmodel.h"
 
 static struct stmt_stats
 {
@@ -408,6 +409,29 @@ mark_stmt_if_obviously_necessary (gimple *stmt, bool aggressive)
        if (is_removable_cxa_atexit_call (call))
          return;
 
+       /* A relaxed atomic load with no LHS has no observable effect:
+          the value is discarded and relaxed ordering provides no
+          inter-thread synchronisation guarantee.  Don't mark it
+          necessary so DCE can remove it. */
+       if (gimple_call_builtin_p (call, BUILT_IN_NORMAL))
+         switch (DECL_FUNCTION_CODE (gimple_call_fndecl (call)))
+           {
+           case BUILT_IN_ATOMIC_LOAD_1:
+           case BUILT_IN_ATOMIC_LOAD_2:
+           case BUILT_IN_ATOMIC_LOAD_4:
+           case BUILT_IN_ATOMIC_LOAD_8:
+           case BUILT_IN_ATOMIC_LOAD_16:
+             {
+             tree model_arg = gimple_call_arg (call, 1);
+             if (TREE_CODE (model_arg) == INTEGER_CST
+                 && is_mm_relaxed (memmodel_from_int (tree_to_uhwi (model_arg))))
+               return;
+             break;
+             }
+           default:
+             break;
+           }
+
        /* IFN_GOACC_LOOP calls are necessary in that they are used to
           represent parameter (i.e. step, bound) of a lowered OpenACC
           partitioned loop.  But this kind of partitioned loop might not