Bug 64006 - __builtin_mul_overflow fails to signal overflow
Summary: __builtin_mul_overflow fails to signal overflow
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: tree-optimization (show other bugs)
Version: 5.0
: P3 normal
Target Milestone: 5.0
Assignee: Jakub Jelinek
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2014-11-20 23:56 UTC by Julian Taylor
Modified: 2014-11-21 20:44 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2014-11-21 00:00:00


Attachments
gcc5-pr64006.patch (1.68 KB, patch)
2014-11-21 13:08 UTC, Jakub Jelinek
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Julian Taylor 2014-11-20 23:56:14 UTC
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)
Comment 1 Jakub Jelinek 2014-11-21 10:40:26 UTC
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.
Comment 2 Jakub Jelinek 2014-11-21 13:08:28 UTC
Created attachment 34068 [details]
gcc5-pr64006.patch

Untested fix.
Comment 3 Jakub Jelinek 2014-11-21 20:42:09 UTC
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
Comment 4 Jakub Jelinek 2014-11-21 20:44:24 UTC
Fixed.