On Tue, Sep 22, 2026 at 10:17:01AM +0200, Jakub Jelinek wrote:
> Hi!
> 
> 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).
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
> 
> 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.
> 
> --- a/gcc/builtins.cc 2026-09-16 22:17:08.702383790 +0200
> +++ b/gcc/builtins.cc 2026-09-21 12:48:35.777166119 +0200
> @@ -6949,8 +6949,7 @@ expand_builtin_atomic_fetch_op (machine_
>  {
>    rtx val, mem, ret;
>    enum memmodel model;
> -  tree fndecl;
> -  tree addr;
> +  tree fndecl, addr, oldval;
>  
>    model = get_memmodel (CALL_EXPR_ARG (exp, 2));
>  
> @@ -6977,6 +6976,13 @@ expand_builtin_atomic_fetch_op (machine_
>  
>    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
> @@ -6993,6 +6999,7 @@ expand_builtin_atomic_fetch_op (machine_
>    /* 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,
> @@ -7072,6 +7079,9 @@ expand_ifn_atomic_bit_test_and (gcall *c
>    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);
> --- a/gcc/testsuite/gcc.dg/pr127492.c 2026-09-21 13:41:47.160775175 +0200
> +++ b/gcc/testsuite/gcc.dg/pr127492.c 2026-09-21 13:48:58.216043364 +0200
> @@ -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

Hi Jakub,

Runtime target check is missing, which causes test fails on simple
targets like pru-unknown-elf where long long atomics are not supported.

Do you think the following would be a suitable solution? It seems to
work for x86_64 and pru-unknown-elf:

/* { dg-additional-options "-DT_INT128" { target sync_int_128_runtime } } */
/* { dg-additional-options "-DT_LONGLONG" { target sync_long_long_runtime } } */

#ifdef T_INT128
#define T __int128
#elif defined(T_LONGLONG)
#define T long long
#else
#define T float
#endif

T v = 1;

int
main ()
{
#if defined(T_INT128) || defined(T_LONGLONG)
  T r = __atomic_add_fetch (&v, v, __ATOMIC_RELAXED);
  if (r != 2 || v != 2)
    __builtin_abort ();
#endif
  return 0;
}


> +T v = 1;
> +
> +int
> +main ()
> +{
> +  T r = __atomic_add_fetch (&v, v, __ATOMIC_RELAXED);
> +  if (r != 2 || v != 2)
> +    __builtin_abort ();

return is missing, so program could exit with 

Regards,
Dimitar
> +}
> 
>       Jakub
> 

Reply via email to