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.

Reply via email to