diff mbox series

bpf: create modifier for mem operand for xchg and cmpxchg

Message ID 20240715153349.412657-1-cupertino.miranda@oracle.com
State New
Headers show
Series bpf: create modifier for mem operand for xchg and cmpxchg | expand

Commit Message

Cupertino Miranda July 15, 2024, 3:33 p.m. UTC
Both xchg and cmpxchg instructions, in the pseudo-C dialect, do not
expect their memory address operand to be surrounded by parentheses.
For example, it should be output as "w0 =cmpxchg32_32(r8+8,w0,w2)"
instead of "w0 =cmpxchg32_32((r8+8),w0,w2)".

This patch implements an operand modifier 'M' which marks the
instruction templates that do not expect the parentheses, and adds it do
xchg and cmpxchg templates.

gcc/ChangeLog:
	* config/bpf/atomic.md (atomic_compare_and_swap,
	atomic_exchange): Add operand modifier %M to the first
	operand.
	* config/bpf/bpf.cc (no_parentheses_mem_operand): Create
	variable.
	(bpf_print_operand): Set no_parentheses_mem_operand variable if
	%M operand is used.
	(bpf_print_operand_address): Conditionally output parentheses.

gcc/testsuite/ChangeLog:
	* gcc.target/bpf/pseudoc-atomic-memaddr-op.c: Add test.
---
 gcc/config/bpf/atomic.md                      |  4 +--
 gcc/config/bpf/bpf.cc                         | 20 ++++++++---
 .../bpf/pseudoc-atomic-memaddr-op.c           | 36 +++++++++++++++++++
 3 files changed, 54 insertions(+), 6 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/bpf/pseudoc-atomic-memaddr-op.c

Comments

David Faust July 18, 2024, 6:18 p.m. UTC | #1
On 7/15/24 08:33, Cupertino Miranda wrote:
> Both xchg and cmpxchg instructions, in the pseudo-C dialect, do not
> expect their memory address operand to be surrounded by parentheses.
> For example, it should be output as "w0 =cmpxchg32_32(r8+8,w0,w2)"
> instead of "w0 =cmpxchg32_32((r8+8),w0,w2)".

After some brief searching, looks like these extra parens in [cmp]xchg*
are an unintended consequence of:

 bb5f619a938 bpf: fix printing of memory operands in pseudoc asm dialect

> 
> This patch implements an operand modifier 'M' which marks the
> instruction templates that do not expect the parentheses, and adds it do
> xchg and cmpxchg templates.

One very minor nit below, otherwise LGTM. Please apply.
Thanks for the fix!

> 
> gcc/ChangeLog:
> 	* config/bpf/atomic.md (atomic_compare_and_swap,
> 	atomic_exchange): Add operand modifier %M to the first
> 	operand.
> 	* config/bpf/bpf.cc (no_parentheses_mem_operand): Create
> 	variable.
> 	(bpf_print_operand): Set no_parentheses_mem_operand variable if
> 	%M operand is used.
> 	(bpf_print_operand_address): Conditionally output parentheses.
> 
> gcc/testsuite/ChangeLog:
> 	* gcc.target/bpf/pseudoc-atomic-memaddr-op.c: Add test.
> ---
>  gcc/config/bpf/atomic.md                      |  4 +--
>  gcc/config/bpf/bpf.cc                         | 20 ++++++++---
>  .../bpf/pseudoc-atomic-memaddr-op.c           | 36 +++++++++++++++++++
>  3 files changed, 54 insertions(+), 6 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.target/bpf/pseudoc-atomic-memaddr-op.c
> 
> diff --git a/gcc/config/bpf/atomic.md b/gcc/config/bpf/atomic.md
> index 65bd5f266a1..be4511bb51b 100644
> --- a/gcc/config/bpf/atomic.md
> +++ b/gcc/config/bpf/atomic.md
> @@ -129,7 +129,7 @@
>     (set (match_dup 1)
>          (match_operand:AMO 2 "nonmemory_operand" "0"))]
>    "bpf_has_v3_atomics"
> -  "{axchg<msuffix>\t%1,%0|%w0 = xchg<pcaxsuffix>(%1, %w0)}")
> +  "{axchg<msuffix>\t%1,%0|%w0 = xchg<pcaxsuffix>(%M1, %w0)}")
>  
>  ;; The eBPF atomic-compare-and-exchange instruction has the form
>  ;;   acmp [%dst+offset], %src
> @@ -182,4 +182,4 @@
>            (match_operand:AMO 3 "register_operand")]   ;; desired
>           UNSPEC_ACMP))]
>    "bpf_has_v3_atomics"
> -  "{acmp<msuffix>\t%1,%3|%w0 = cmpxchg<pcaxsuffix>(%1, %w0, %w3)}")
> +  "{acmp<msuffix>\t%1,%3|%w0 = cmpxchg<pcaxsuffix>(%M1, %w0, %w3)}")
> diff --git a/gcc/config/bpf/bpf.cc b/gcc/config/bpf/bpf.cc
> index 687e7ba49c1..a6b6e20731c 100644
> --- a/gcc/config/bpf/bpf.cc
> +++ b/gcc/config/bpf/bpf.cc
> @@ -835,6 +835,11 @@ bpf_print_register (FILE *file, rtx op, int code)
>      }
>  }
>  
> +/* Variable defined to implement 'M' operand modifier for the special cases
> +   where the parentheses should not be printed surrounding a memory address
> +   operand. */
> +static bool no_parentheses_mem_operand;
> +
>  /* Print an instruction operand.  This function is called in the macro
>     PRINT_OPERAND defined in bpf.h */
>  
> @@ -847,6 +852,7 @@ bpf_print_operand (FILE *file, rtx op, int code)
>        bpf_print_register (file, op, code);
>        break;
>      case MEM:
> +      no_parentheses_mem_operand = (code == 'M');
>        output_address (GET_MODE (op), XEXP (op, 0));
>        break;
>      case CONST_DOUBLE:
> @@ -891,6 +897,9 @@ bpf_print_operand (FILE *file, rtx op, int code)
>      }
>  }
>  
> +#define PAREN_OPEN  (asm_dialect == ASM_NORMAL ? "[" : no_parentheses_mem_operand ? "" : "(")
> +#define PAREN_CLOSE (asm_dialect == ASM_NORMAL ? "]" : no_parentheses_mem_operand ? "" : ")")
> +
>  /* Print an operand which is an address.  This function should handle
>     any legit address, as accepted by bpf_legitimate_address_p, and
>     also addresses that are valid in CALL instructions.
> @@ -904,9 +913,9 @@ bpf_print_operand_address (FILE *file, rtx addr)
>    switch (GET_CODE (addr))
>      {
>      case REG:
> -      fprintf (file, asm_dialect == ASM_NORMAL ? "[" : "(");
> +      fprintf (file, "%s", PAREN_OPEN);
>        bpf_print_register (file, addr, 0);
> -      fprintf (file, asm_dialect == ASM_NORMAL ? "+0]" : "+0)");
> +      fprintf (file, "+0%s", PAREN_CLOSE);
>        break;
>      case PLUS:
>        {
> @@ -923,14 +932,14 @@ bpf_print_operand_address (FILE *file, rtx addr)
>  		|| (GET_CODE (op1) == UNSPEC
>  		    && XINT (op1, 1) == UNSPEC_CORE_RELOC)))
>  	  {
> -            fprintf (file, asm_dialect == ASM_NORMAL ? "[" : "(");
> +	    fprintf (file, "%s", PAREN_OPEN);
>  	    bpf_print_register (file, op0, 0);
>  	    fprintf (file, "+");
>  	    if (GET_CODE (op1) == UNSPEC)
>  	      output_addr_const (file, XVECEXP (op1, 0, 0));
>  	    else
>  	      output_addr_const (file, op1);
> -            fprintf (file, asm_dialect == ASM_NORMAL ? "]" : ")");
> +	    fprintf (file, "%s", PAREN_CLOSE);
>  	  }
>  	else
>  	  fatal_insn ("invalid address in operand", addr);
> @@ -948,6 +957,9 @@ bpf_print_operand_address (FILE *file, rtx addr)
>      }
>  }
>  
> +#undef PAREN_OPEN
> +#undef PAREN_CLOSE
> +
>  /* Add a BPF builtin function with NAME, CODE and TYPE.  Return
>     the function decl or NULL_TREE if the builtin was not added.  */
>  
> diff --git a/gcc/testsuite/gcc.target/bpf/pseudoc-atomic-memaddr-op.c b/gcc/testsuite/gcc.target/bpf/pseudoc-atomic-memaddr-op.c
> new file mode 100644
> index 00000000000..758faf04cc2
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/bpf/pseudoc-atomic-memaddr-op.c
> @@ -0,0 +1,36 @@
> +/* { dg-do compile } */
> +/* { dg-options "-mv3-atomics -O2 -masm=pseudoc" } */
> +
> +int
> +foo (int *p, int *expected, int desired)
> +{
> +  return __atomic_compare_exchange (p, expected, &desired, 0,
> +				    __ATOMIC_ACQUIRE, __ATOMIC_RELAXED);
> +}
> +
> +int
> +foo64 (long *p, long *expected, long desired)
> +{
> +  return __atomic_compare_exchange (p, expected, &desired, 0,
> +				    __ATOMIC_ACQUIRE, __ATOMIC_RELAXED);
> +}
> +
> +int bar (int *p, int *new)

nit: style - return type should be on its own line

> +{
> +  int old;
> +  __atomic_exchange (p, new, &old, __ATOMIC_RELAXED);
> +  return old;
> +}
> +
> +int bar64 (long *p, long *new)

same here

> +{
> +  long old;
> +  __atomic_exchange (p, new, &old, __ATOMIC_SEQ_CST);
> +  return old;
> +}
> +
> +/* { dg-final { scan-assembler "r. = cmpxchg_64\\(r.\\+0, r., r.\\)" } } */
> +/* { dg-final { scan-assembler "w. = cmpxchg32_32\\(r.\\+0, w., w.\\)" } } */
> +/* { dg-final { scan-assembler-times "w. = xchg32_32\\(r.\\+0, w.\\)" 1 } } */
> +/* { dg-final { scan-assembler-times "r. = xchg_64\\(r.\\+0, r.\\)" 1 } } */
> +
Cupertino Miranda July 19, 2024, 12:20 p.m. UTC | #2
Fixed and pushed!

Thanks,
Cupertino

David Faust writes:

> On 7/15/24 08:33, Cupertino Miranda wrote:
>> Both xchg and cmpxchg instructions, in the pseudo-C dialect, do not
>> expect their memory address operand to be surrounded by parentheses.
>> For example, it should be output as "w0 =cmpxchg32_32(r8+8,w0,w2)"
>> instead of "w0 =cmpxchg32_32((r8+8),w0,w2)".
>
> After some brief searching, looks like these extra parens in [cmp]xchg*
> are an unintended consequence of:
>
>  bb5f619a938 bpf: fix printing of memory operands in pseudoc asm dialect
>
>>
>> This patch implements an operand modifier 'M' which marks the
>> instruction templates that do not expect the parentheses, and adds it do
>> xchg and cmpxchg templates.
>
> One very minor nit below, otherwise LGTM. Please apply.
> Thanks for the fix!
>
>>
>> gcc/ChangeLog:
>> 	* config/bpf/atomic.md (atomic_compare_and_swap,
>> 	atomic_exchange): Add operand modifier %M to the first
>> 	operand.
>> 	* config/bpf/bpf.cc (no_parentheses_mem_operand): Create
>> 	variable.
>> 	(bpf_print_operand): Set no_parentheses_mem_operand variable if
>> 	%M operand is used.
>> 	(bpf_print_operand_address): Conditionally output parentheses.
>>
>> gcc/testsuite/ChangeLog:
>> 	* gcc.target/bpf/pseudoc-atomic-memaddr-op.c: Add test.
>> ---
>>  gcc/config/bpf/atomic.md                      |  4 +--
>>  gcc/config/bpf/bpf.cc                         | 20 ++++++++---
>>  .../bpf/pseudoc-atomic-memaddr-op.c           | 36 +++++++++++++++++++
>>  3 files changed, 54 insertions(+), 6 deletions(-)
>>  create mode 100644 gcc/testsuite/gcc.target/bpf/pseudoc-atomic-memaddr-op.c
>>
>> diff --git a/gcc/config/bpf/atomic.md b/gcc/config/bpf/atomic.md
>> index 65bd5f266a1..be4511bb51b 100644
>> --- a/gcc/config/bpf/atomic.md
>> +++ b/gcc/config/bpf/atomic.md
>> @@ -129,7 +129,7 @@
>>     (set (match_dup 1)
>>          (match_operand:AMO 2 "nonmemory_operand" "0"))]
>>    "bpf_has_v3_atomics"
>> -  "{axchg<msuffix>\t%1,%0|%w0 = xchg<pcaxsuffix>(%1, %w0)}")
>> +  "{axchg<msuffix>\t%1,%0|%w0 = xchg<pcaxsuffix>(%M1, %w0)}")
>>
>>  ;; The eBPF atomic-compare-and-exchange instruction has the form
>>  ;;   acmp [%dst+offset], %src
>> @@ -182,4 +182,4 @@
>>            (match_operand:AMO 3 "register_operand")]   ;; desired
>>           UNSPEC_ACMP))]
>>    "bpf_has_v3_atomics"
>> -  "{acmp<msuffix>\t%1,%3|%w0 = cmpxchg<pcaxsuffix>(%1, %w0, %w3)}")
>> +  "{acmp<msuffix>\t%1,%3|%w0 = cmpxchg<pcaxsuffix>(%M1, %w0, %w3)}")
>> diff --git a/gcc/config/bpf/bpf.cc b/gcc/config/bpf/bpf.cc
>> index 687e7ba49c1..a6b6e20731c 100644
>> --- a/gcc/config/bpf/bpf.cc
>> +++ b/gcc/config/bpf/bpf.cc
>> @@ -835,6 +835,11 @@ bpf_print_register (FILE *file, rtx op, int code)
>>      }
>>  }
>>
>> +/* Variable defined to implement 'M' operand modifier for the special cases
>> +   where the parentheses should not be printed surrounding a memory address
>> +   operand. */
>> +static bool no_parentheses_mem_operand;
>> +
>>  /* Print an instruction operand.  This function is called in the macro
>>     PRINT_OPERAND defined in bpf.h */
>>
>> @@ -847,6 +852,7 @@ bpf_print_operand (FILE *file, rtx op, int code)
>>        bpf_print_register (file, op, code);
>>        break;
>>      case MEM:
>> +      no_parentheses_mem_operand = (code == 'M');
>>        output_address (GET_MODE (op), XEXP (op, 0));
>>        break;
>>      case CONST_DOUBLE:
>> @@ -891,6 +897,9 @@ bpf_print_operand (FILE *file, rtx op, int code)
>>      }
>>  }
>>
>> +#define PAREN_OPEN  (asm_dialect == ASM_NORMAL ? "[" : no_parentheses_mem_operand ? "" : "(")
>> +#define PAREN_CLOSE (asm_dialect == ASM_NORMAL ? "]" : no_parentheses_mem_operand ? "" : ")")
>> +
>>  /* Print an operand which is an address.  This function should handle
>>     any legit address, as accepted by bpf_legitimate_address_p, and
>>     also addresses that are valid in CALL instructions.
>> @@ -904,9 +913,9 @@ bpf_print_operand_address (FILE *file, rtx addr)
>>    switch (GET_CODE (addr))
>>      {
>>      case REG:
>> -      fprintf (file, asm_dialect == ASM_NORMAL ? "[" : "(");
>> +      fprintf (file, "%s", PAREN_OPEN);
>>        bpf_print_register (file, addr, 0);
>> -      fprintf (file, asm_dialect == ASM_NORMAL ? "+0]" : "+0)");
>> +      fprintf (file, "+0%s", PAREN_CLOSE);
>>        break;
>>      case PLUS:
>>        {
>> @@ -923,14 +932,14 @@ bpf_print_operand_address (FILE *file, rtx addr)
>>  		|| (GET_CODE (op1) == UNSPEC
>>  		    && XINT (op1, 1) == UNSPEC_CORE_RELOC)))
>>  	  {
>> -            fprintf (file, asm_dialect == ASM_NORMAL ? "[" : "(");
>> +	    fprintf (file, "%s", PAREN_OPEN);
>>  	    bpf_print_register (file, op0, 0);
>>  	    fprintf (file, "+");
>>  	    if (GET_CODE (op1) == UNSPEC)
>>  	      output_addr_const (file, XVECEXP (op1, 0, 0));
>>  	    else
>>  	      output_addr_const (file, op1);
>> -            fprintf (file, asm_dialect == ASM_NORMAL ? "]" : ")");
>> +	    fprintf (file, "%s", PAREN_CLOSE);
>>  	  }
>>  	else
>>  	  fatal_insn ("invalid address in operand", addr);
>> @@ -948,6 +957,9 @@ bpf_print_operand_address (FILE *file, rtx addr)
>>      }
>>  }
>>
>> +#undef PAREN_OPEN
>> +#undef PAREN_CLOSE
>> +
>>  /* Add a BPF builtin function with NAME, CODE and TYPE.  Return
>>     the function decl or NULL_TREE if the builtin was not added.  */
>>
>> diff --git a/gcc/testsuite/gcc.target/bpf/pseudoc-atomic-memaddr-op.c b/gcc/testsuite/gcc.target/bpf/pseudoc-atomic-memaddr-op.c
>> new file mode 100644
>> index 00000000000..758faf04cc2
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.target/bpf/pseudoc-atomic-memaddr-op.c
>> @@ -0,0 +1,36 @@
>> +/* { dg-do compile } */
>> +/* { dg-options "-mv3-atomics -O2 -masm=pseudoc" } */
>> +
>> +int
>> +foo (int *p, int *expected, int desired)
>> +{
>> +  return __atomic_compare_exchange (p, expected, &desired, 0,
>> +				    __ATOMIC_ACQUIRE, __ATOMIC_RELAXED);
>> +}
>> +
>> +int
>> +foo64 (long *p, long *expected, long desired)
>> +{
>> +  return __atomic_compare_exchange (p, expected, &desired, 0,
>> +				    __ATOMIC_ACQUIRE, __ATOMIC_RELAXED);
>> +}
>> +
>> +int bar (int *p, int *new)
>
> nit: style - return type should be on its own line
>
>> +{
>> +  int old;
>> +  __atomic_exchange (p, new, &old, __ATOMIC_RELAXED);
>> +  return old;
>> +}
>> +
>> +int bar64 (long *p, long *new)
>
> same here
>
>> +{
>> +  long old;
>> +  __atomic_exchange (p, new, &old, __ATOMIC_SEQ_CST);
>> +  return old;
>> +}
>> +
>> +/* { dg-final { scan-assembler "r. = cmpxchg_64\\(r.\\+0, r., r.\\)" } } */
>> +/* { dg-final { scan-assembler "w. = cmpxchg32_32\\(r.\\+0, w., w.\\)" } } */
>> +/* { dg-final { scan-assembler-times "w. = xchg32_32\\(r.\\+0, w.\\)" 1 } } */
>> +/* { dg-final { scan-assembler-times "r. = xchg_64\\(r.\\+0, r.\\)" 1 } } */
>> +
diff mbox series

Patch

diff --git a/gcc/config/bpf/atomic.md b/gcc/config/bpf/atomic.md
index 65bd5f266a1..be4511bb51b 100644
--- a/gcc/config/bpf/atomic.md
+++ b/gcc/config/bpf/atomic.md
@@ -129,7 +129,7 @@ 
    (set (match_dup 1)
         (match_operand:AMO 2 "nonmemory_operand" "0"))]
   "bpf_has_v3_atomics"
-  "{axchg<msuffix>\t%1,%0|%w0 = xchg<pcaxsuffix>(%1, %w0)}")
+  "{axchg<msuffix>\t%1,%0|%w0 = xchg<pcaxsuffix>(%M1, %w0)}")
 
 ;; The eBPF atomic-compare-and-exchange instruction has the form
 ;;   acmp [%dst+offset], %src
@@ -182,4 +182,4 @@ 
           (match_operand:AMO 3 "register_operand")]   ;; desired
          UNSPEC_ACMP))]
   "bpf_has_v3_atomics"
-  "{acmp<msuffix>\t%1,%3|%w0 = cmpxchg<pcaxsuffix>(%1, %w0, %w3)}")
+  "{acmp<msuffix>\t%1,%3|%w0 = cmpxchg<pcaxsuffix>(%M1, %w0, %w3)}")
diff --git a/gcc/config/bpf/bpf.cc b/gcc/config/bpf/bpf.cc
index 687e7ba49c1..a6b6e20731c 100644
--- a/gcc/config/bpf/bpf.cc
+++ b/gcc/config/bpf/bpf.cc
@@ -835,6 +835,11 @@  bpf_print_register (FILE *file, rtx op, int code)
     }
 }
 
+/* Variable defined to implement 'M' operand modifier for the special cases
+   where the parentheses should not be printed surrounding a memory address
+   operand. */
+static bool no_parentheses_mem_operand;
+
 /* Print an instruction operand.  This function is called in the macro
    PRINT_OPERAND defined in bpf.h */
 
@@ -847,6 +852,7 @@  bpf_print_operand (FILE *file, rtx op, int code)
       bpf_print_register (file, op, code);
       break;
     case MEM:
+      no_parentheses_mem_operand = (code == 'M');
       output_address (GET_MODE (op), XEXP (op, 0));
       break;
     case CONST_DOUBLE:
@@ -891,6 +897,9 @@  bpf_print_operand (FILE *file, rtx op, int code)
     }
 }
 
+#define PAREN_OPEN  (asm_dialect == ASM_NORMAL ? "[" : no_parentheses_mem_operand ? "" : "(")
+#define PAREN_CLOSE (asm_dialect == ASM_NORMAL ? "]" : no_parentheses_mem_operand ? "" : ")")
+
 /* Print an operand which is an address.  This function should handle
    any legit address, as accepted by bpf_legitimate_address_p, and
    also addresses that are valid in CALL instructions.
@@ -904,9 +913,9 @@  bpf_print_operand_address (FILE *file, rtx addr)
   switch (GET_CODE (addr))
     {
     case REG:
-      fprintf (file, asm_dialect == ASM_NORMAL ? "[" : "(");
+      fprintf (file, "%s", PAREN_OPEN);
       bpf_print_register (file, addr, 0);
-      fprintf (file, asm_dialect == ASM_NORMAL ? "+0]" : "+0)");
+      fprintf (file, "+0%s", PAREN_CLOSE);
       break;
     case PLUS:
       {
@@ -923,14 +932,14 @@  bpf_print_operand_address (FILE *file, rtx addr)
 		|| (GET_CODE (op1) == UNSPEC
 		    && XINT (op1, 1) == UNSPEC_CORE_RELOC)))
 	  {
-            fprintf (file, asm_dialect == ASM_NORMAL ? "[" : "(");
+	    fprintf (file, "%s", PAREN_OPEN);
 	    bpf_print_register (file, op0, 0);
 	    fprintf (file, "+");
 	    if (GET_CODE (op1) == UNSPEC)
 	      output_addr_const (file, XVECEXP (op1, 0, 0));
 	    else
 	      output_addr_const (file, op1);
-            fprintf (file, asm_dialect == ASM_NORMAL ? "]" : ")");
+	    fprintf (file, "%s", PAREN_CLOSE);
 	  }
 	else
 	  fatal_insn ("invalid address in operand", addr);
@@ -948,6 +957,9 @@  bpf_print_operand_address (FILE *file, rtx addr)
     }
 }
 
+#undef PAREN_OPEN
+#undef PAREN_CLOSE
+
 /* Add a BPF builtin function with NAME, CODE and TYPE.  Return
    the function decl or NULL_TREE if the builtin was not added.  */
 
diff --git a/gcc/testsuite/gcc.target/bpf/pseudoc-atomic-memaddr-op.c b/gcc/testsuite/gcc.target/bpf/pseudoc-atomic-memaddr-op.c
new file mode 100644
index 00000000000..758faf04cc2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/bpf/pseudoc-atomic-memaddr-op.c
@@ -0,0 +1,36 @@ 
+/* { dg-do compile } */
+/* { dg-options "-mv3-atomics -O2 -masm=pseudoc" } */
+
+int
+foo (int *p, int *expected, int desired)
+{
+  return __atomic_compare_exchange (p, expected, &desired, 0,
+				    __ATOMIC_ACQUIRE, __ATOMIC_RELAXED);
+}
+
+int
+foo64 (long *p, long *expected, long desired)
+{
+  return __atomic_compare_exchange (p, expected, &desired, 0,
+				    __ATOMIC_ACQUIRE, __ATOMIC_RELAXED);
+}
+
+int bar (int *p, int *new)
+{
+  int old;
+  __atomic_exchange (p, new, &old, __ATOMIC_RELAXED);
+  return old;
+}
+
+int bar64 (long *p, long *new)
+{
+  long old;
+  __atomic_exchange (p, new, &old, __ATOMIC_SEQ_CST);
+  return old;
+}
+
+/* { dg-final { scan-assembler "r. = cmpxchg_64\\(r.\\+0, r., r.\\)" } } */
+/* { dg-final { scan-assembler "w. = cmpxchg32_32\\(r.\\+0, w., w.\\)" } } */
+/* { dg-final { scan-assembler-times "w. = xchg32_32\\(r.\\+0, w.\\)" 1 } } */
+/* { dg-final { scan-assembler-times "r. = xchg_64\\(r.\\+0, r.\\)" 1 } } */
+