Bug 24172 - [4.1 Regression] error: incorrect sharing of tree nodes
Summary: [4.1 Regression] error: incorrect sharing of tree nodes
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: tree-optimization (show other bugs)
Version: 4.1.0
: P2 critical
Target Milestone: 4.1.0
Assignee: Jan Hubicka
URL: http://gcc.gnu.org/ml/gcc-patches/200...
Keywords: ice-on-valid-code, patch
Depends on:
Blocks:
 
Reported: 2005-10-03 01:06 UTC by Kevin Gilbert
Modified: 2005-10-30 21:59 UTC (History)
5 users (show)

See Also:
Host:
Target:
Build:
Known to work: 4.0.0
Known to fail: 4.1.0
Last reconfirmed: 2005-10-21 11:07:48


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Kevin Gilbert 2005-10-03 01:06:00 UTC
Compile of KOffice with gcc4.1 failed.  Source condensed to a test case which produces the following error:

---------------
test-case-1.cpp: In function ‘void prepare_inpaint()’:
test-case-1.cpp:55: error: incorrect sharing of tree nodes
D.1986_15 = "rb"[0];

"rb"[0];

test-case-1.cpp:55: internal compiler error: verify_stmts failed
---------------

gcc version info:

---------------
Using built-in specs.
Target: i686-pc-linux-gnu
Configured with: ./configure
Thread model: posix
gcc version 4.1.0 20050927 (experimental)
---------------

Compile command:

---------------
g++ -O2 -c test-case-1.cpp
---------------

The compile fails with O1, O2 and O3 but works with O0. Source code of test case (note: I could not reduce it any further) :

---------------
namespace cimg_library
{       template<typename T = float> struct CImg;
        template<typename T = float> struct CImgl;

        struct Exception
        {
        };

        struct IOException : Exception
        {       IOException( const char * )
                {
                }
        };

        namespace cimg
        {       inline int* dummy( const char* const path, const char* const mode )
                {       throw IOException( mode[ 0 ] == 'r' ? "a" : (mode[ 0 ] == 'w' ? "b" : "" ));
                        return 0;
                }

        }

        template<typename T> struct CImg
        {       T *data;

                explicit CImg( const unsigned int dx = 0 )
                {
                }

                CImg( const char *filename )
                {       CImgl<T>( filename ).get_append( 'v', 'p' );
                }
        };

        template<typename T> struct CImgl
        {       CImgl( const unsigned int )
                {
                }

                CImgl(const char* filename)
                {       cimg::dummy( filename, "rb" );
                        unsigned int n;
                        CImgl<T> res( n );
                }

                CImg<T> get_append( const char, const char ) const
                {       CImg<T> res;
                        return res;
                }
        };
}

using namespace cimg_library;

void prepare_inpaint( )
{       cimg_library::CImg<unsigned char> mask = CImg<unsigned char>( "" );
}
---------------
Comment 1 Andrew Pinski 2005-10-03 01:12:59 UTC
This is caused by the inliner.
Comment 2 Andrew Pinski 2005-10-03 01:26:49 UTC
Here is a slightly shorter testcase:


template<typename T = float> struct CImg;
        template<typename T = float> struct CImgl;
        struct IOException
        {       IOException( const char * ){}
        };
  inline int* dummy( const char* const path, const char* const
mode )
                {       throw IOException( mode[ 0 ] == 'r' ? "a" : (mode[ 0 ]
== 'w' ? "b" : "" ));
                }
        template<typename T> struct CImg
        {       T *data;
                explicit CImg( const unsigned int dx = 0 )
                {
                }
                CImg( const char *filename )
                {       CImgl<T>( filename ).get_append( 'v', 'p' );
                }
        };
        template<typename T> struct CImgl
        {       CImgl( const unsigned int )
                {
                }
                CImgl(const char* filename)
                {       dummy( filename, "rb" );
                        unsigned int n;
                       CImgl<T> res( n );
                }
                CImg<T> get_append( const char, const char ) const
                {       CImg<T> res;
                }
        };
void prepare_inpaint( )
{       CImg<unsigned char> mask = CImg<unsigned char>( "" );
}

---

I have not tried to reduce it further.
Comment 3 Andrew Pinski 2005-10-03 16:54:18 UTC
Confirmed, reduced testcase:
void IOException( char);
inline int* dummy( const char* const mode )
{
  IOException(*mode+*mode);
}

void prepare_inpaint( )
{
  dummy ("rb");
}


The problem is that we have &"rb"[0] and we get *(&"rb"[0]) but we only fold that to "rb"[0] instead of all the way to 'r'.
Comment 4 janis187 2005-10-03 21:59:57 UTC
A regression hunt using the testcase from comment #3 identified this patch from
hubicka@gcc.gnu.org:

  http://gcc.gnu.org/ml/gcc-cvs/2005-05/msg00624.html
Comment 5 Richard Biener 2005-10-04 10:44:04 UTC
The problem is, that with this part of the blamed patch

===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-inline.c,v
retrieving revision 1.182
retrieving revision 1.183
diff -u -r1.182 -r1.183
--- gcc/gcc/tree-inline.c	2005/04/23 21:27:58	1.182
+++ gcc/gcc/tree-inline.c	2005/05/13 13:56:54	1.183
@@ -566,21 +566,15 @@
 	{
 	  /* Get rid of *& from inline substitutions that can happen when a
 	     pointer argument is an ADDR_EXPR.  */
-	  tree decl = TREE_OPERAND (*tp, 0), value;
+	  tree decl = TREE_OPERAND (*tp, 0);
 	  splay_tree_node n;
 
 	  n = splay_tree_lookup (id->decl_map, (splay_tree_key) decl);
 	  if (n)
 	    {
-	      value = (tree) n->value;
-	      STRIP_NOPS (value);
-	      if (TREE_CODE (value) == ADDR_EXPR
-		  && (lang_hooks.types_compatible_p
-		      (TREE_TYPE (*tp), TREE_TYPE (TREE_OPERAND (value, 0)))))
-		{
-		  *tp = TREE_OPERAND (value, 0);
-		  return copy_body_r (tp, walk_subtrees, data);
-		}
+	      *tp = build_fold_indirect_ref ((tree)n->value);
+	      *walk_subtrees = 0;
+	      return NULL;
 	    }
 	}
 
we do not have *tp unshared anymore.  Is build_fold_indirect_ref supposed
to do that?

Anyway, I'll test the following:

Index: tree-inline.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-inline.c,v
retrieving revision 1.210
diff -c -3 -p -r1.210 tree-inline.c
*** tree-inline.c       1 Aug 2005 15:25:28 -0000       1.210
--- tree-inline.c       4 Oct 2005 10:43:23 -0000
*************** copy_body_r (tree *tp, int *walk_subtree
*** 636,643 ****
                  else
                    *tp = build1 (INDIRECT_REF, type, (tree)n->value);
                }
!             *walk_subtrees = 0;
!             return NULL;
            }
        }

--- 636,642 ----
                  else
                    *tp = build1 (INDIRECT_REF, type, (tree)n->value);
                }
!             /* Fall through to copying the folded tree.  */
            }
        }

Comment 6 Richard Biener 2005-10-04 11:00:11 UTC
Other approach, make sure we fold it.  We don't have fold_build4, neither does fold handle it.  But there's fold_read_from_constant_string.

Index: fold-const.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fold-const.c,v
retrieving revision 1.626
diff -c -3 -p -r1.626 fold-const.c
*** fold-const.c        26 Sep 2005 01:28:38 -0000      1.626
--- fold-const.c        4 Oct 2005 10:59:06 -0000
*************** fold_indirect_ref_1 (tree type, tree op0
*** 11511,11519 ****
      {
        tree op = TREE_OPERAND (sub, 0);
        tree optype = TREE_TYPE (op);
!       /* *&p => p */
        if (type == optype)
!       return op;
        /* *(foo *)&fooarray => fooarray[0] */
        else if (TREE_CODE (optype) == ARRAY_TYPE
               && type == TREE_TYPE (optype))
--- 11511,11525 ----
      {
        tree op = TREE_OPERAND (sub, 0);
        tree optype = TREE_TYPE (op);
!       /* *&p => p;  make sure to handle *&"str"[cst] here.  */
        if (type == optype)
!       {
!         tree fop = fold_read_from_constant_string (op);
!         if (fop)
!           return fop;
!         else
!           return op;
!       }
        /* *(foo *)&fooarray => fooarray[0] */
        else if (TREE_CODE (optype) == ARRAY_TYPE
               && type == TREE_TYPE (optype))
Comment 7 Andrew Pinski 2005-10-04 12:53:04 UTC
(In reply to comment #6)
> Other approach, make sure we fold it.  We don't have fold_build4, neither does
> fold handle it.  But there's fold_read_from_constant_string.

I rather see this patch here than the first one for 4.1.  I also like to see a lot of the code from tree-ccp.c for folding moved to the proper spot for 4.2.
Comment 8 Jan Hubicka 2005-10-04 12:56:11 UTC
Subject: Re:  [4.1 Regression] error: incorrect sharing of tree nodes

> 
> 
> ------- Comment #5 from rguenth at gcc dot gnu dot org  2005-10-04 10:44 -------
> The problem is, that with this part of the blamed patch
> 
> ===================================================================
> RCS file: /cvs/gcc/gcc/gcc/tree-inline.c,v
> retrieving revision 1.182
> retrieving revision 1.183
> diff -u -r1.182 -r1.183
> --- gcc/gcc/tree-inline.c       2005/04/23 21:27:58     1.182
> +++ gcc/gcc/tree-inline.c       2005/05/13 13:56:54     1.183
> @@ -566,21 +566,15 @@
>         {
>           /* Get rid of *& from inline substitutions that can happen when a
>              pointer argument is an ADDR_EXPR.  */
> -         tree decl = TREE_OPERAND (*tp, 0), value;
> +         tree decl = TREE_OPERAND (*tp, 0);
>           splay_tree_node n;
> 
>           n = splay_tree_lookup (id->decl_map, (splay_tree_key) decl);
>           if (n)
>             {
> -             value = (tree) n->value;
> -             STRIP_NOPS (value);
> -             if (TREE_CODE (value) == ADDR_EXPR
> -                 && (lang_hooks.types_compatible_p
> -                     (TREE_TYPE (*tp), TREE_TYPE (TREE_OPERAND (value, 0)))))
> -               {
> -                 *tp = TREE_OPERAND (value, 0);
> -                 return copy_body_r (tp, walk_subtrees, data);
> -               }
> +             *tp = build_fold_indirect_ref ((tree)n->value);
> +             *walk_subtrees = 0;
> +             return NULL;
>             }
>         }
> 
> we do not have *tp unshared anymore.  Is build_fold_indirect_ref supposed
> to do that?

It is not, but the entries of decl_map are expected to be shareable.
There are couple of other places where n->value is substituted in
without further copying.  I see there can be NOP_EXPRs and ADDR_EXPRs
that are supposed to be unshared.

We don't want to recurse on substituted value as we would mess up
recursive functions and friends, but probably somehing like unshare_expr
call on all places we dosubstitution would work?
I can look into that tomorrow unless someone beats me ;)

Honza
Comment 9 Richard Biener 2005-10-04 13:42:23 UTC
Patch posted.
Comment 10 Richard Biener 2005-10-07 09:05:29 UTC
Honza, I'm stuck with rth's comment that there may be still sharing bugs even
after making fold_indirect_ref_1 fold the offending statement.  And as you noted,
calling copy_body_r on the folded or unfolded tree causes either nice recursion
or the assert at tree-inline.c:665 to trigger.

So can you try either convince rth that just doing better folding is safe or
try your unshare_expr idea?

Thx,
Richard.
Comment 11 Steven Bosscher 2005-10-21 11:07:48 UTC
Honza, Richi... well?  Is anyone going to do anything with this bug? :-)
Comment 12 Richard Biener 2005-10-21 12:19:22 UTC
My fix to fold works and is in out beta compiler.
Comment 13 Jan Hubicka 2005-10-27 21:18:34 UTC
This is patch I am testing to prevent the sharing.  I think it is good idea in addition to Richard's patch to make fold do it's job too:

void IOException( char);
inline int* dummy( const char* const mode )
{
  IOException(*mode+*mode);
}

void prepare_inpaint( )
{
  dummy ("rb");
}


Index: tree-inline.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-inline.c,v
retrieving revision 1.212
diff -c -3 -p -r1.212 tree-inline.c
*** tree-inline.c	12 Oct 2005 23:34:09 -0000	1.212
--- tree-inline.c	27 Oct 2005 21:16:34 -0000
*************** copy_body_r (tree *tp, int *walk_subtree
*** 639,644 ****
--- 639,645 ----
  	  n = splay_tree_lookup (id->decl_map, (splay_tree_key) decl);
  	  if (n)
  	    {
+ 	      tree new;
  	      /* If we happen to get an ADDR_EXPR in n->value, strip
  	         it manually here as we'll eventually get ADDR_EXPRs
  		 which lie about their types pointed to.  In this case
*************** copy_body_r (tree *tp, int *walk_subtree
*** 646,658 ****
  		 but we absolutely rely on that.  As fold_indirect_ref
  	         does other useful transformations, try that first, though.  */
  	      tree type = TREE_TYPE (TREE_TYPE ((tree)n->value));
! 	      *tp = fold_indirect_ref_1 (type, (tree)n->value);
  	      if (! *tp)
  	        {
! 		  if (TREE_CODE ((tree)n->value) == ADDR_EXPR)
! 		    *tp = TREE_OPERAND ((tree)n->value, 0);
  	          else
! 	            *tp = build1 (INDIRECT_REF, type, (tree)n->value);
  		}
  	      *walk_subtrees = 0;
  	      return NULL;
--- 647,660 ----
  		 but we absolutely rely on that.  As fold_indirect_ref
  	         does other useful transformations, try that first, though.  */
  	      tree type = TREE_TYPE (TREE_TYPE ((tree)n->value));
! 	      new = unshare_expr ((tree)n->value);
! 	      *tp = fold_indirect_ref_1 (type, new);
  	      if (! *tp)
  	        {
! 		  if (TREE_CODE (new) == ADDR_EXPR)
! 		    *tp = TREE_OPERAND (new, 0);
  	          else
! 	            *tp = build1 (INDIRECT_REF, type, new);
  		}
  	      *walk_subtrees = 0;
  	      return NULL;
Comment 14 Jan Hubicka 2005-10-30 18:18:12 UTC
Subject: Bug 24172

Author: hubicka
Date: Sun Oct 30 18:14:15 2005
New Revision: 106247

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=106247
Log:
	PR tree-optimization/24172
	* tree-inline.c (copy_body_r): Unshare the substituted value first.
	* g++.dg/tree-ssa/pr24172.C: New testcase.

Added:
    trunk/gcc/testsuite/g++.dg/tree-ssa/pr24172.C
Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/testsuite/ChangeLog
    trunk/gcc/tree-inline.c

Comment 15 Jan Hubicka 2005-10-30 21:59:52 UTC
Fixed by my patch