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 <[email protected]>
---
gcc/testsuite/gcc.dg/tree-ssa/pr123966.c | 71 ++++++++++++++++++++++++
gcc/tree-ssa-dce.cc | 23 ++++++++
2 files changed, 94 insertions(+)
create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr123966.c
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr123966.c
b/gcc/testsuite/gcc.dg/tree-ssa/pr123966.c
new file mode 100644
index 00000000000..7658f1d1945
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr123966.c
@@ -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" } } */
diff --git a/gcc/tree-ssa-dce.cc b/gcc/tree-ssa-dce.cc
index 7932607e889..a63cac2fa30 100644
--- a/gcc/tree-ssa-dce.cc
+++ b/gcc/tree-ssa-dce.cc
@@ -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,28 @@ 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_lhs (call)
+ && 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
--
2.34.1