https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67401
Bug ID: 67401 Summary: Incorrect expand of __atomic_compare_exchange_8 using __sync_val_compare_and_swap_8 Product: gcc Version: 6.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: middle-end Assignee: unassigned at gcc dot gnu.org Reporter: danglin at gcc dot gnu.org Target Milestone: --- Host: hppa-unknown-linux-gnu Target: hppa-unknown-linux-gnu Build: hppa-unknown-linux-gnu Created attachment 36271 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=36271&action=edit .s file The following testcase is incorrectly compiled on hppa-unknown-linux-gnu if I enable support for __sync_val_compare_and_swap_8 in linux-atomic.c: extern volatile _Atomic unsigned long long mem; void foo (void) { for (int i = 0; i < 10000; i++) mem -= 1; } This hunk is wrong when the testcase is compiled at -O1: .L4: ldw -184(%r30),%r3 ldw -180(%r30),%r4 addi -1,%r4,%r29 subb %r3,%r0,%r28 stw %r28,0(%r6) stw %r29,4(%r6) copy %r3,%r23 copy %r4,%r24 bl __sync_val_compare_and_swap_8,%r2 copy %r5,%r26 copy %r3,%r23 copy %r4,%r24 copy %r28,%r25 copy %r29,%r26 bl __ucmpdi2,%r2 nop comiclr,<> 1,%r28,%r19 ldi 1,%r19 comiclr,= 0,%r19,%r0 b,n .L3 stw %r28,-184(%r30) stw %r29,-180(%r30) .L3: The call to __ucmpdi2 clobbers register %r28. This is the most significant half of the DImode value returned by __sync_val_compare_and_swap_8. As a result, the store "stw %r28,-184(%r30)" results in the wrong value being passed to __sync_val_compare_and_swap_8 on the next iteration. I think the return value from __sync_val_compare_and_swap_8 should be copied to a pseudo to prevent this from happening. I'm not sure why __ucmpdi2is used here. Usually, DImode compare operations are done inline without using a libcall. This pessimizes the code.