http://gcc.gnu.org/bugzilla/show_bug.cgi?id=49504

           Summary: Invalid optimization for Pmode != ptr_mode
           Product: gcc
           Version: 4.7.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: middle-end
        AssignedTo: unassig...@gcc.gnu.org
        ReportedBy: hjl.to...@gmail.com


On x32 branch, I got

[hjl@gnu-33 tmp]$ cat x32.c
unsigned long long t(const void* p, unsigned long long q) {
  unsigned long long a = (((unsigned long long) ((unsigned long) p)) + q) >>
32;
  return a;
}
[hjl@gnu-33 tmp]$ /usr/gcc-4.7.0-x32/bin/gcc -O2 -mx32 -S x32.c
[hjl@gnu-33 tmp]$ cat x32.s
    .file    "x32.c"
    .text
    .p2align 4,,15
    .globl    t
    .type    t, @function
t:
.LFB0:
    .cfi_startproc
    xorl    %eax, %eax
    ret
    .cfi_endproc
.LFE0:
    .size    t, .-t
    .ident    "GCC: (GNU) 4.7.0 20110616 (experimental)"
    .section    .note.GNU-stack,"",@progbits
[hjl@gnu-33 tmp]$ 

From

http://code.google.com/p/nativeclient/issues/detail?id=1601

What it does is that when pointers from memory (ptr_mode) are zero extended
when getting into registers (Pmode)(POINTERS_EXTEND_UNSIGNED > 0), and there is
a Pmode PLUS or MINUS of a register that holds a pointer value with some other
register, all bits above ptr_mode are considered zero.

Here is the test that demonstrates the bug clearly (compile with -O2):

  unsigned long long t(const void* p, unsigned long long q) {
    unsigned long long a = (((unsigned long long)p) + q) >> 32;
    return a;
  }

In our z86_64 compiler, p is 32-bit. It gets zero-extended to 64-bit long long
for addition with q, but the fact that it was originally a pointer is
preserved. Thus, nonzero_bits1 thinks the result of addition always has high
32-bits equal to zero, so the result of the right shift is always zero.

The test gets optimized to "return 0;".

Reply via email to