https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116677

            Bug ID: 116677
           Summary: ARM: Incorrect code generated when testing value of
                    returned struct
           Product: gcc
           Version: 13.3.0
               URL: https://gcc.godbolt.org/z/j3e51Y3TW
            Status: UNCONFIRMED
          Keywords: wrong-code
          Severity: normal
          Priority: P3
         Component: c
          Assignee: unassigned at gcc dot gnu.org
          Reporter: wvangulik at xs4all dot nl
  Target Milestone: ---
            Target: arm

Given the following code:
struct sockaddr_storage {
  char offset[4];
  int  sin_addr;
};

struct sockaddr_in {
  char offset[4];
  int  sin_addr;
};

struct a {
    char offset[8];
    struct sockaddr_storage c;
};

struct sockaddr_storage str_to_ip();

static inline int isany(const struct sockaddr_storage *ip_addr)
{
    return (((struct sockaddr_in*)ip_addr)->sin_addr == 0);
}

static inline int isany_nocast(const struct sockaddr_storage *ip_addr)
{
    return ip_addr->sin_addr == 0;
}

int failing(struct a *p)
{
    // inline function isany is mixedup with the return of str_to_ip
    p->c = str_to_ip();
    return isany(&p->c);
}

int correct(struct a *p)
{
    // Using a local stack variable forces the compiler to use the returned
structure
    struct sockaddr_storage c = str_to_ip();
    p->c = c;
    return isany(&c);
}

Compiled on Godbolt ARM GCC 13.3.0 and -O2.
Tried several other version on Godbolt 
GCC 5 (!) is the last one that is correct.

It generates:
failing:
        push    {r4, r5, lr}
        mov     r4, r0
        sub     sp, sp, #12
        mov     r5, sp
        mov     r0, r5        <= Setup r0 for the returned struct
        bl      str_to_ip
        add     r3, r4, #8    <= setup r3 to 'p->c'
        ldr     r2, [r4, #12] <==== Incorrect!! 'p->c' is not yet updated
        ldm     r5, {r0, r1}  <= copy struct-on-stack to registers
        stm     r3, {r0, r1}  <= copy registers back to 'p->c'. 'p->c' is now
updated
        clz     r0, r2
        lsrs    r0, r0, #5
        add     sp, sp, #12
        pop     {r4, r5, pc}
correct:
        push    {r4, r5, lr}
        mov     r4, r0
        sub     sp, sp, #12
        mov     r5, sp
        mov     r0, r5
        bl      str_to_ip
        add     r3, r4, #8
        ldr     r2, [sp, #4] <== this is correct, sp+4 contains returned object
        ldm     r5, {r0, r1}
        stm     r3, {r0, r1}
        clz     r0, r2
        lsrs    r0, r0, #5
        add     sp, sp, #12
        pop     {r4, r5, pc}

Some additional info:
The cast is part of the problem. Removing the cast fixes the problem.
It is very fragile. In our production code it compiles some places correct and
at least one incorrect.

Reply via email to