https://gcc.gnu.org/g:e6acfce7078fd40b8a225e184e630817cdee5e91

commit r15-11631-ge6acfce7078fd40b8a225e184e630817cdee5e91
Author: Jakub Jelinek <[email protected]>
Date:   Tue Sep 22 14:58:22 2026 +0200

    builtins: Fix further fallback of atomic builtins [PR127492]
    
    This is a continuation of the PR127336 problem, just in a different file.
    If TER results in val being expanded as a MEM, we need to force it into
    a register before the atomic operation (and as a bonus for
    expand_builtin_atomic_fetch_op even better reuse it also for the atomic
    call itself).
    
    2026-09-22  Jakub Jelinek  <[email protected]>
    
            PR middle-end/127492
            * builtins.cc (expand_builtin_atomic_fetch_op): Force val into a
            pseudo if updates to mem could change its value.
            (expand_ifn_atomic_bit_test_and): Likewise.
    
            * gcc.dg/pr127492.c: New test.
    
    Reviewed-by: Richard Biener <[email protected]>
    (cherry picked from commit 325646488a306c36c28e84260b4dd551bd30a47f)

Diff:
---
 gcc/builtins.cc                 | 14 ++++++++++++--
 gcc/testsuite/gcc.dg/pr127492.c | 19 +++++++++++++++++++
 2 files changed, 31 insertions(+), 2 deletions(-)

diff --git a/gcc/builtins.cc b/gcc/builtins.cc
index 50a59755be1a..c53d1be606c6 100644
--- a/gcc/builtins.cc
+++ b/gcc/builtins.cc
@@ -6931,8 +6931,7 @@ expand_builtin_atomic_fetch_op (machine_mode mode, tree 
exp, rtx target,
 {
   rtx val, mem, ret;
   enum memmodel model;
-  tree fndecl;
-  tree addr;
+  tree fndecl, addr, oldval;
 
   model = get_memmodel (CALL_EXPR_ARG (exp, 2));
 
@@ -6959,6 +6958,13 @@ expand_builtin_atomic_fetch_op (machine_mode mode, tree 
exp, rtx target,
 
   gcc_assert (TREE_OPERAND (addr, 0) == fndecl);
   TREE_OPERAND (addr, 0) = builtin_decl_explicit (ext_call);
+  oldval = CALL_EXPR_ARG (exp, 1);
+
+  if (!ignore && reg_overlap_mentioned_p (mem, val))
+    {
+      val = force_reg (mode, val);
+      CALL_EXPR_ARG (exp, 1) = make_tree (TREE_TYPE (oldval), val);
+    }
 
   /* If we will emit code after the call, the call cannot be a tail call.
      If it is emitted as a tail call, a barrier is emitted after it, and
@@ -6975,6 +6981,7 @@ expand_builtin_atomic_fetch_op (machine_mode mode, tree 
exp, rtx target,
   /* Then issue the arithmetic correction to return the right result.  */
   if (!ignore)
     {
+      CALL_EXPR_ARG (exp, 1) = oldval;
       if (code == NOT)
        {
          ret = expand_simple_binop (mode, AND, ret, val, NULL_RTX, true,
@@ -7054,6 +7061,9 @@ expand_ifn_atomic_bit_test_and (gcall *call)
   if (maybe_expand_insn (icode, 5, ops))
     return;
 
+  if (reg_overlap_mentioned_p (mem, val))
+    val = force_reg (mode, val);
+
   rtx bitval = val;
   val = expand_simple_binop (mode, ASHIFT, const1_rtx,
                             val, NULL_RTX, true, OPTAB_DIRECT);
diff --git a/gcc/testsuite/gcc.dg/pr127492.c b/gcc/testsuite/gcc.dg/pr127492.c
new file mode 100644
index 000000000000..89c747602123
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr127492.c
@@ -0,0 +1,19 @@
+/* PR middle-end/127492 */
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+/* { dg-additional-options "-latomic" { target libatomic_available } } */
+
+#ifdef __SIZEOF_INT128__
+#define T __int128
+#else
+#define T long long
+#endif
+T v = 1;
+
+int
+main ()
+{
+  T r = __atomic_add_fetch (&v, v, __ATOMIC_RELAXED);
+  if (r != 2 || v != 2)
+    __builtin_abort ();
+}

Reply via email to