Bug 29446

Summary: [4.2 Regression] VRP ICE in compare_names
Product: gcc Reporter: kargls
Component: tree-optimizationAssignee: Richard Biener <rguenth>
Status: RESOLVED FIXED    
Severity: critical CC: dnovillo, fang, gcc-bugs, pinskia, rguenth
Priority: P3 Keywords: ice-on-valid-code
Version: 4.2.0   
Target Milestone: 4.2.0   
Host: Target:
Build: Known to work: 4.1.2
Known to fail: 4.2.0 Last reconfirmed: 2006-10-13 10:38:52
Bug Depends on:    
Bug Blocks: 31698    

Description kargls 2006-10-12 22:37:04 UTC
troutmask:kargl[206] gfc -m32 -O3 -fbounds-check -c vrp.f90
vrp.f90: In function 'abc':
vrp.f90:1: internal compiler error: in compare_names, at tree-vrp.c:3645

The Fortran code is

function abc(n)
integer :: xsd(n), abc(size(xsd),n), i, j, n
do i=1,2
   do j=1,3
      if (i /= j) then
         abc(1,1) = 0
      else
         abc(1,j) = xsd(1)
      end if
   end do
end do
end function abc
Comment 1 Andrew Pinski 2006-10-13 03:19:26 UTC
C testcase:
void f(int *n, int *m)
{
  int i;
  int ubound0;
  int ubound1;
  int stride2;
  int offset3;
  int size4;
  int j;
  int ubound5;
  int size6;
  int D919;
  __SIZE_TYPE__ D920;
  int D921;
  unsigned int D922;
  __SIZE_TYPE__ D923;
  unsigned int D924;

  ubound0 = *m;
  stride2 = ubound0;
  ubound1 = *n;
  size4 = stride2 * ubound1;
  D922 = size4 - 1;
  int (*abc)[D922];
  abc = _gfortran_internal_malloc (size4 * 4);
  offset3 = ~stride2;
  ubound5 = *n;
  size6 = ubound5;
  D919 = size6 - 1;
  int (*xsd)[D919];
  xsd = _gfortran_internal_malloc (size6 * 4);
  i = 1;

  if (i <= 2)
    {
      while (1)
        {
          {
            _Bool D918;

            j = 1;
            if (j <= 3)
              {
                while (1)
                  {
                    {
                      _Bool D917;

                      if (i != j)
                        {
                          if (__builtin_expect (ubound0 <= 0, 0))
                            {
                              __builtin_abort ();
                            }
                          else
                            {
                              (void) 0;
                            }
                          if (__builtin_expect (ubound1 <= 0, 0))
                            {
                              __builtin_abort ();
                            }
                          else
                            {
                              (void) 0;
                            }
                          (*abc)[stride2 + offset3 + 1] = 0;
                        }
                      else
                        {
                          {
                            int D916;

                            if (__builtin_expect (ubound0 <= 0, 0))
                              {
                                __builtin_abort ();
                              }
                            else
                              {
                                (void) 0;
                              }
                            D916 = j;
                            if (__builtin_expect (D916 <= 0, 0))
                              {
                                __builtin_abort ();
                              }
                            else
                              {
                                (void) 0;
                              }
                            if (__builtin_expect (D916 > ubound1, 0))
                              {
                                __builtin_abort ();
                              }
                            else
                              {
                                (void) 0;
                              }
                            if (__builtin_expect (ubound5 <= 0, 0))
                              {
                                __builtin_abort ();
                              }
                            else
                              {
                                (void) 0;
                              }
                            (*abc)[D916 * stride2 + offset3 + 1] = (*xsd)[0];
                          }
                        }
                      D917 = j == 3;
                      j = j + 1;
                      if (D917) break; else (void) 0;
                    }
                  }
              }
            else
              {
                (void) 0;
              }
          //  L4:;
            D918 = i == 2;
            i = i + 1;
            if (D918) break; else (void) 0;
          }
        }
    }
  else
    {
      (void) 0;
    }
//L2:;
  _gfortran_internal_free ((void *) xsd);
  _gfortran_internal_free ((void *) abc);

}
Comment 2 Andrew Pinski 2006-10-13 03:34:43 UTC
here is a shorter testcase:
void f(void)
{
  int i, ubound1, j, ubound5;
  int (*abc)[3];
  i = 1;
  while (1)
    {
       if (j <= 3)
         while (1)
           {
              _Bool D917;
              if (i != j)
                {
                  if (__builtin_expect (ubound1 <= 0, 0))
                    __builtin_abort ();
                  (*abc)[1] = 0;
                }
               else
                 {
                    int D916;
                    D916 = j;
                    if (__builtin_expect (D916 > ubound1, 0))
                      __builtin_abort ();
                    if (__builtin_expect (ubound5 <= 0, 0))
                      __builtin_abort ();
                  }
               j = j + 1;
               if (D917)
		 break;
           }
    i = i + 1;
  }
}
Comment 3 Richard Biener 2006-10-13 08:22:42 UTC
Slightly less undefined, ICEs with -O -ftree-vrp -funswitch-loops:

void f(_Bool D917, int j0, int ubound1, int ubound5)
{
  int i, j = j0;
  int (*abc)[3];
  i = 1;
  while (1)
    {
       if (j <= 3)
         while (1)
           {
              if (i != j)
                {
                  if (ubound1 <= 0)
                    return;
                  (*abc)[1] = 0;
                }
               else
                 {
                    if (j > ubound1)
                      return;
                    if (ubound5 <= 0)
                      return;
                  }
               j = j + 1;
               if (D917)
                 break;
           }
    i = i + 1;
  }
}
Comment 4 Richard Biener 2006-10-13 09:18:54 UTC
We end up comparing (GT_EXPR) i_92 with ubound1_111 which have the following value ranges and equivalences:

i_92: [1, 3]  EQUIVALENCES: { i_1 j_2 i_67 j_70 } (4 elements)

i_1: ~[0, 0]  EQUIVALENCES: { } (0 elements)
j_2: VARYING
i_67: [1, ubound1_8]  EQUIVALENCES: { i_1 } (1 elements)
j_70: [-INF, 3]  EQUIVALENCES: { j_2 } (1 elements)


ubound1_111: [-INF, 0]  EQUIVALENCES: { ubound1_8 ubound1_112 } (2 elements)

ubound1_8: VARYING
ubound1_112: [i_67, +INF]  EQUIVALENCES: { ubound1_8 } (1 elements)


i_67 > ubound1_8   ([1, ubound1_8] > [ubound1_8, ubound1_8])  is false
i_67 > ubound1_111 ([1, ubound1_8] > [-INF, 0])               is true
i_92 > ubound1_111 ([1, 3] > [-INF, 0])                       is true


So we have a cross-equivalency set inconsistency.
Comment 5 Richard Biener 2006-10-13 10:07:46 UTC
It looks like we would need to recurse down into symbolic ranges in fix_equivalence_set, which would be far too costly.  So a conservative
fix for 4.2 is to just not record symbolic equivalencies at all.

I wonder if there is a better way to deal with these issues than fix_equivalence_set though.
Comment 6 Richard Biener 2006-10-13 10:38:52 UTC
I have a patch to get rid of that beast completely.
Comment 7 patchapp@dberlin.org 2006-10-13 12:45:26 UTC
Subject: Bug number PR29446

A patch for this bug has been added to the patch tracker.
The mailing list url for the patch is http://gcc.gnu.org/ml/gcc-patches/2006-10/msg00698.html
Comment 8 Richard Biener 2006-10-13 20:09:23 UTC
Subject: Bug 29446

Author: rguenth
Date: Fri Oct 13 20:09:10 2006
New Revision: 117705

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=117705
Log:
2006-10-13  Richard Guenther  <rguenther@suse.de>

	PR tree-optimization/29446
	* tree-vrp.c (fix_equivalence_set): Remove.
	(extract_range_from_assert): Do not call fix_equivalence_set.
	(debug_value_range): Print a newline.
	(compare_name_with_value): For equivalence sets with
	inconsistent value ranges conservatively bail out.
	(compare_names): Likewise.

	* gcc.dg/torture/pr29446.c: New testcase.

Added:
    trunk/gcc/testsuite/gcc.dg/torture/pr29446.c
Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/testsuite/ChangeLog
    trunk/gcc/tree-vrp.c

Comment 9 Richard Biener 2006-10-13 20:09:36 UTC
Fixed.
Comment 10 Richard Biener 2007-04-25 17:10:43 UTC
Subject: Bug 29446

Author: rguenth
Date: Wed Apr 25 17:10:31 2007
New Revision: 124158

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=124158
Log:
2007-04-25  Richard Guenther  <rguenther@suse.de>
 
 	PR tree-optimization/31698
 	* g++.dg/other/pr31698.C: New testcase.

 	Backport from mainline:
 	2006-10-13  Richard Guenther  <rguenther@suse.de>
 
 	PR tree-optimization/29446
 	* tree-vrp.c (fix_equivalence_set): Remove.
 	(extract_range_from_assert): Do not call fix_equivalence_set.
 	(debug_value_range): Print a newline.
 	(compare_name_with_value): For equivalence sets with
 	inconsistent value ranges conservatively bail out.
 	(compare_names): Likewise.

 	* gcc.dg/torture/pr29446.c: New testcase.

Added:
    branches/gcc-4_1-branch/gcc/testsuite/g++.dg/other/pr31698.C
    branches/gcc-4_1-branch/gcc/testsuite/gcc.dg/torture/pr29446.c
      - copied unchanged from r117705, trunk/gcc/testsuite/gcc.dg/torture/pr29446.c
Modified:
    branches/gcc-4_1-branch/gcc/ChangeLog
    branches/gcc-4_1-branch/gcc/testsuite/ChangeLog
    branches/gcc-4_1-branch/gcc/tree-vrp.c