following code does not print overflow while the result does clearly overflow: $ cat test.c #include <stdio.h> int __attribute__((noinline)) wrapper(long a, long b, long * r) { return __builtin_mul_overflow(a, b, r); } long __attribute__((noinline)) test(long *dims, int nd) { int i; long size = 1; for (i = 0; i < nd; i++) { long dim = dims[i]; if (__builtin_mul_overflow(size, dim, &size)) { //if (wrapper(size, dim, &size)) { puts("overflow"); } } return size; } int main(int argc, char * argv[]) { long r; long dim[7] = {975,975,975,975,975,975,975}; r = test(dim, 7); printf("%ld\n",r); } $ gcc-5.0 -O2 test.c $ ./a.out 7488110182826036655 if one uses the commented wrapper function version it correctly prints overflow. $ gcc-5.0 --version gcc (GCC) 5.0.0 20141119 (experimental) Copyright (C) 2014 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. $ gcc-5.0 -v Using built-in specs. COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=/media/jtaylor/45d3164a-104c-4489-9021-091002eb6730/data/local-5.0/bin/../libexec/gcc/x86_64-unknown-linux-gnu/5.0.0/lto-wrapper Target: x86_64-unknown-linux-gnu Configured with: /media/jtaylor/45d3164a-104c-4489-9021-091002eb6730/data/gcc/configure --disable-werror --enable-languages=c,c++,fortran --enable-tls --prefix=/media/jtaylor/45d3164a-104c-4489-9021-091002eb6730/data//gcc/local-5.0 --with-gmp=/usr --with-mpfr=/usr --with-mpc=/usr --with-cloog=/usr --with-ppl=/usr --with-isl=/usr --disable-bootstrap Thread model: posix gcc version 5.0.0 20141119 (experimental) (GCC)
Reduced testcase: int v; long __attribute__ ((noinline)) test (long *x, int y) { int i; long s = 1; for (i = 0; i < y; i++) if (__builtin_mul_overflow (s, x[i], &s)) v++; return s; } int main () { long d[7] = { 975, 975, 975, 975, 975, 975, 975 }; long r = test (d, 7); if (sizeof (long) * __CHAR_BIT__ == 64 && v != 1) __builtin_abort (); else if (sizeof (long) * __CHAR_BIT__ == 32 && v != 4) __builtin_abort (); return 0; } The problem is in VRP, the IMAGPART_EXPR of the MUL_OVERFLOW result is processed with only some edges executable and others not, so the value ranges of the values are only temporary, not final. In that case, one of the arguments of MUL_OVERFLOW is assumed to be [1, 1] and the other argument is VARYING. A final [1, 1] * VARYING in the same types is never overflowing though, the result always fits into the type, so we set [0, 0] as the value range for the IMAGPART_EXPR. And for some reason we are not called again when the MUL_OVERFLOW arguments are VARYING * VARYING. So, is there some way how to tell VRP to simulate the IMAGPART_EXPR again? Or is there a way to see if the value ranges of the *_OVERFLOW arguments are just temporary simulation or final? Is the fact that IMAGPART_EXPR range might be narrower initially and change to larger one later on compatible with VRP at all? Though, how is that generally different from say simulating s = s + 4 inside a loop? There we initially assume (if s is 1 before the loop) range [5, 5] and later turn it into a wider range. Though, for the IMAGPART_EXPR in this case, the arguments of the MUL_OVERFLOW don't depend on the IMAGPART_EXPR value.
Created attachment 34068 [details] gcc5-pr64006.patch Untested fix.
Author: jakub Date: Fri Nov 21 20:41:37 2014 New Revision: 217945 URL: https://gcc.gnu.org/viewcvs?rev=217945&root=gcc&view=rev Log: PR tree-optimization/64006 * tree-vrp.c (stmt_interesting_for_vrp): Return true for {ADD,SUB,MUL}_OVERFLOW internal calls. (vrp_visit_assignment_or_call): For {ADD,SUB,MUL}_OVERFLOW internal calls, check if any REALPART_EXPR/IMAGPART_EXPR immediate uses would change their value ranges and return SSA_PROP_INTERESTING if so, or SSA_PROP_NOT_INTERESTING if there are some REALPART_EXPR/IMAGPART_EXPR immediate uses interesting for vrp. * gcc.c-torture/execute/pr64006.c: New test. Added: trunk/gcc/testsuite/gcc.c-torture/execute/pr64006.c Modified: trunk/gcc/ChangeLog trunk/gcc/testsuite/ChangeLog trunk/gcc/tree-vrp.c
Fixed.