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.