Bug 9065

Summary: FAIL with gcc.c-torture/execute/loop-2e.c test with gcc-3.2.1 (wrong instruction generation)
Product: gcc Reporter: bsg
Component: cAssignee: Paolo Carlini <paolo.carlini>
Status: RESOLVED DUPLICATE    
Severity: normal CC: gcc-bugs, paolo.carlini
Priority: P3 Keywords: wrong-code
Version: 3.1   
Target Milestone: ---   
Host: Target:
Build: Known to work:
Known to fail: Last reconfirmed:

Description bsg 2002-12-27 05:56:01 UTC
I have found a bug when compiling test file gcc.c-torture/execute/loop-2e.c

This is a minimalized version of test file
gcc/testsuite/gcc.c-torture/execute/loop-2e.c:
--- begin
  void f (int *p, int **q)
  {
/*  Correct behaviour with: */
      unsigned int i;

/*  Incorrect behaviour with: */
/*    int i; */

      for (i = 0; i < 40; i++)
          *q++ = &p[i];
  }
--- end

GCC command line: /root/tmp/compile/gcc/gcc/cc1 exp.c -Os -Wall -W -o exp.s

If you set type of variable `i' to signed int (instead of unsigned)
in function `f()' and use optimization for size (`-Os' option)
then the compiler will produce wrong assembly output as shown below:
--- begin
        .file   "exp.c"
        .text
.globl f
        .type   f,@function
f:
        pushl   %ebp
        movl    %esp, %ebp
        movl    8(%ebp), %eax   #  p,  p
        movl    12(%ebp), %ecx  #  q,  q
        movl    %eax, %edx      #  p,  p
        addl    $156, %eax
.L6:
        movl    %edx, (%ecx)    #  p, * q
        addl    $4, %ecx        #  q
        addl    $4, %edx        #  p
        cmpl    %eax, %edx      #  p

# Here is a bug.
#  Correct instruction:
        jbe     .L6
#  Incorrect instruction:
#       jle     .L6

        popl    %ebp
        ret
.Lfe1:
        .size   f,.Lfe1-f
--- end

This bug happens when gcc decided to eliminate                             
induction variable `i' and replace it with pointers comparison.

The bug consts in unexpected loop termination when one of
the pointers `*p' or `*q' (function arguments) is above 0x80000000
while another pointer is below 0x80000000.

The problem is that the type of jump instruction (`jbe' or `jle')
depends on the type of variable `i' (unsigned or signed). That is wrong
because in the example above we use instruction `cmpl %eax, %edx'
to compare pointers, not integers. And the pointers should always be compared
as unsigned numbers (i.e. `jbe' instruction should be used).

This example fails when one of the pointers `*p' or `*q' is above 0x8000000
while another pointer is below 0x80000000. Such a values can not be compared
correctly as signed integers.

Release:
2.3.1

Environment:
GCC version is: gcc-3.2.1 (GNU CPP version 3.2.1 (cpplib) (i386 Linux/ELF))
My system is Linux-2.2.19 on i586 (i586-pc-linux-gnu) with glibc-2.2.3.
Options to comile gcc:
../gcc-3.2.1/configure --enable-shared --prefix=/usr --enable-threads

How-To-Repeat:
  void f (int *p, int **q)
  {
/*  Incorrect behaviour with: */
    int i;

      for (i = 0; i < 40; i++)
          *q++ = &p[i];
  }

GCC command line: /root/tmp/compile/gcc/gcc/cc1 exp.c -Os -Wall -W -o exp.s
Comment 1 Paolo Carlini 2002-12-27 08:33:39 UTC
*** This bug has been marked as a duplicate of 9064 ***