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

            Bug ID: 63347
           Summary: m68k misoptimisation with -fschedule-insns
           Product: gcc
           Version: 4.7.4
            Status: UNCONFIRMED
          Severity: major
          Priority: P3
         Component: target
          Assignee: unassigned at gcc dot gnu.org
          Reporter: jifl-bugzilla at jifvik dot org

The following minimal test case (derived from much larger code) demonstrates a
problem which I could reproduce on m68k-elf-gcc 4.7.4. It can be built with
simply:

m68k-elf-gcc -c -O1 -fschedule-insns foo.c

extern int printf(const char *fmt, ...);

int print_info(unsigned int *ip_addr)
{
    int invalid = 0;

    if (ip_addr) {
        unsigned int haddr = *ip_addr;
        printf("%d.%d.%d.%d",
               (int)((haddr >> 24) & 0xff),
               (int)((haddr >> 16) & 0xff),
               (int)((haddr >> 8) & 0xff),
               (int)((haddr >> 0) & 0xff));
        if (0x0 == haddr) {
            invalid = 1;
        }
        printf("\n");
    } else {
        invalid = 1;
    }

    return invalid;
}

The problem manifests with the 'tstl' instruction corresponding to the 'if
(0x0==haddr)' simply disappearing, resulting in an incorrect return value.
Here's the relevant section of asm for a working version (without
-fschedule-insns):

  48:   4fef 0014       lea %sp@(20),%sp
  4c:   4a82            tstl %d2
  4e:   57c2            seq %d2
  50:   49c2            extbl %d2
  52:   4482            negl %d2
  54:   4879 0000 0000  pea 0 <print_info>
                        56: R_68K_32    .rodata.str1.1+0xc

%d2 is later moved to %d0 to give the return value.


and for a broken version:
  4c:   4fef 0014       lea %sp@(20),%sp
  50:   4879 0000 0000  pea 0 <print_info>
                        52: R_68K_32    .rodata.str1.1+0xc
  56:   57c2            seq %d2
  58:   49c2            extbl %d2
  5a:   4482            negl %d2

The 'tstl' insn is gone!

If you want to make this an executable, I added on the following which
demonstrates the problem:
int main(int argc, char *argv[])
{
    unsigned int myaddr;
    int ret;

    myaddr = 0x0;
    ret = print_info(&myaddr);
    if (!ret)
        printf("FAIL: addr 0 returned %d\n", ret);

    myaddr = 0x01020304;
    ret = print_info(&myaddr);
    if (ret)
        printf("FAIL: addr 1234 returned %d\n", ret);
    return 0;
}

This worked in gcc 4.4.5, but I haven't tried 4.5 or 4.6. Of course other
changes in the optimizer would probably perturb things enough that this code
wouldn't trigger it any more with different gcc versions (including 4.8 or
4.9), even if the problem in the compiler still remains.

Reply via email to