https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70821
Bug ID: 70821
Summary: x86_64: __atomic_fetch_add/sub() uses XADD rather than
DECL in some cases
Product: gcc
Version: 6.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: target
Assignee: unassigned at gcc dot gnu.org
Reporter: dhowells at redhat dot com
Target Milestone: ---
Created attachment 38346
--> https://gcc.gnu.org/bugzilla/attachment.cgi?id=38346&action=edit
Test program
__atomic_fetch_add/sub() uses XADD rather than DECL when subtracting 1 from the
counter if the result is acted upon, but where this could be done through the
condition flags. For instance:
static __always_inline bool atomic_sub_and_test(int i, atomic_t *v)
{
return __atomic_sub_fetch(&v->counter, i, __ATOMIC_SEQ_CST);
}
const char *test_atomic_dec_and_test(atomic_t *counter)
{
if (atomic_sub_and_test(1, counter))
return "foo";
return "bar";
}
produces:
17: 83 c8 ff or $0xffffffff,%eax
1a: f0 0f c1 07 lock xadd %eax,(%rdi)
1e: ba 00 00 00 00 mov $0x0,%edx
23: ff c8 dec %eax
25: b8 00 00 00 00 mov $0x0,%eax
2a: 48 0f 44 c2 cmove %rdx,%rax
2e: c3 retq
when it should produce something more like this, which I get when adding 1
instead of subtracting 1, but with a DECL rather than an INCL:
46: f0 ff 07 lock incl (%rdi)
49: ba 00 00 00 00 mov $0x0,%edx
4e: b8 00 00 00 00 mov $0x0,%eax
53: 48 0f 44 c2 cmove %rdx,%rax
57: c3 retq
Note that adding or subtracting 2 and testing the zeroness of the result gives
SUBL/ADDL as expected. If the result is not tested, DECL is generated as
expected:
13: f0 ff 0f lock decl (%rdi)
16: c3 retq
See the attached test program.
This is the case for both:
gcc version 5.3.1 20151207 (Red Hat 5.3.1-2) (GCC)
gcc version 6.0.0 20160219 (Red Hat Cross 6.0.0-0.1) (GCC)
The following version of gcc:
gcc version 4.8.5 20150623 (Red Hat 4.8.5-2.x) (GCC)
also produces XADD rather than INCL/DECL/ADDL/SUBL if the result is looked at
at all.