I believe what is happening is that a loop like

for (int i = 1; i; ++i) { int64_t m = i * CONST_LL ...}

is being optimized to roughly:

int64_t m = 0;
for (...) { m += CONST_LL ...}

My code was intentionally allowing i to become negative (it was testing the
equivalence of two expressions for all int i except 0).  If the multiply really
happens, when i wraps around 'm' becomes negative.  In the optimized version it
keeps growing as if it were 'unsigned int i'.

The simplified repro case included can be "fixed" by changing the initial 'int
i = 1' to 'int i = -10'.  Also for some reason the 'm2' test (greatly
simplified from the original code) cannot be removed without "fixing" the
problem.  And it does not occur without optimization:

$ cc  -O2 -o gccbug gccbug.c --save-temps -v
Using built-in specs.
Target: amd64-undermydesk-freebsd
Configured with: FreeBSD/amd64 system compiler
Thread model: posix
gcc version 4.2.1 20070719  [FreeBSD]
 /usr/libexec/cc1 -E -quiet -v -D_LONGLONG gccbug.c -O2 -fpch-preprocess -o
gccbug.i
ignoring duplicate directory "/usr/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/include
End of search list.
 /usr/libexec/cc1 -fpreprocessed gccbug.i -quiet -dumpbase gccbug.c -auxbase
gccbug -O2 -version -o gccbug.s
GNU C version 4.2.1 20070719  [FreeBSD] (amd64-undermydesk-freebsd)
        compiled by GNU C version 4.2.1 20070719  [FreeBSD].
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=102400
Compiler executable checksum: 2117630c4ec5f0cc97737a66d6c5822c
gccbug.c: In function 'main':
gccbug.c:24: warning: incompatible implicit declaration of built-in function
'printf'
 /usr/bin/as -V -Qy -o gccbug.o gccbug.s
GNU assembler version 2.15 [FreeBSD] 2004-05-23 (x86_64-obrien-freebsd) using
BFD version 2.15 [FreeBSD] 2004-05-23
 /usr/bin/ld --eh-frame-hdr -V -dynamic-linker /libexec/ld-elf.so.1 -o gccbug
/usr/lib/crt1.o /usr/lib/crti.o /usr/lib/crtbegin.o -L/usr/lib -L/usr/lib
gccbug.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s
--no-as-needed /usr/lib/crtend.o /usr/lib/crtn.o
GNU ld version 2.15 [FreeBSD] 2004-05-23
  Supported emulations:
   elf_i386_fbsd
   elf_x86_64_fbsd

# 1 "gccbug.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "gccbug.c"
typedef long long int int64_t;
typedef unsigned long int uint32_t;
# 12 "gccbug.c"
int
main()
{
 int i = 0;
 for (i = 1; i; ++i) {
  int64_t m = i * 16807LL;



  uint32_t m2 = 8;
  if (i == -2 && m2 != 7)

   printf("%d (%lld)\n", i, m);
 }
}

When it fails:
$ ./gccbug
-2 (72185515310258)

Correct output would be
-2 (-33614)


-- 
           Summary: reduction of in-loop 64-bit multiply to repeated add
                    wrong when loop var wraps neg
           Product: gcc
           Version: 4.2.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: rtl-optimization
        AssignedTo: unassigned at gcc dot gnu dot org
        ReportedBy: ben at ben dot com
 GCC build triplet: amd64-undermydesk-freebsd
  GCC host triplet: amd64-undermydesk-freebsd
GCC target triplet: amd64-undermydesk-freebsd


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

Reply via email to