Bug 20991 - [4.0 Regression] ICE in cgraph_mark_reachable_node
Summary: [4.0 Regression] ICE in cgraph_mark_reachable_node
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: middle-end (show other bugs)
Version: 4.0.0
: P2 normal
Target Milestone: 4.0.1
Assignee: Not yet assigned to anyone
URL:
Keywords: ice-on-valid-code
Depends on:
Blocks:
 
Reported: 2005-04-13 13:25 UTC by Jakub Jelinek
Modified: 2005-04-24 22:11 UTC (History)
7 users (show)

See Also:
Host:
Target: i386-redhat-linux
Build:
Known to work: 4.1.0
Known to fail:
Last reconfirmed: 2005-04-17 21:34:28


Attachments
Testcase (130.31 KB, application/octet-stream)
2005-04-13 13:28 UTC, Jakub Jelinek
Details
Fix that disables the optimization if cgraph would abort (782 bytes, patch)
2005-04-18 04:51 UTC, Jakub Jelinek
Details | Diff
Patch that fixes this by relying the method will be emitted together with its vtable (1.49 KB, patch)
2005-04-18 04:53 UTC, Jakub Jelinek
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Jakub Jelinek 2005-04-13 13:25:05 UTC
Current gcc-4_0-branch (i.e. with PR20635 fix in) ICEs on the attached testcase
at -O3 -m32.  It is a recent regression (the assert was added 2005-03-18)
and prevents building Octave.
virtual std::string octave_value::class_name() const (this)
{
...
}
seen in *.generic dump seems to be unused until *.dom1 time (till then
Fissparse uses
  arg_106 = &D.101031;
  D.141412_107 = arg_106->_vptr.octave_value;
  D.141413_108 = D.141412_107 + 468B;
  D.141414_109 = *D.141413_108;
  OBJ_TYPE_REF(D.141414_109;arg_106->117) (&D.141411, arg_106) [return slot
addr];
and only in the first dominator pass this gets changed into:
  arg_175 = &arg;
  D.131589_176 = arg._vptr.octave_value;
  D.131590_177 = D.131589_176 + 468B;
  D.131591_178 = *D.131590_177;
  class_name (&D.131588, &arg) [return slot addr];
but cgraph does not know about this call until Fissparse's assembly is emitted.
But at that point cgraph_global_info_ready is already true, therefore the ICE.
Comment 1 Jakub Jelinek 2005-04-13 13:28:28 UTC
Created attachment 8617 [details]
Testcase
Comment 2 Jakub Jelinek 2005-04-13 14:26:55 UTC
Somewhat simplified testcase:

#include <vector>
#include <string>

struct A { int i; };
struct B { int i; };
struct C { int i; };
struct D { int i; };

struct E
{
  E (void);
  E (bool b);
  E (const A & m);
  virtual ~ E (void);
  virtual A m1 (bool x = false) const { return rep->m1 (x); }
  virtual B m2 (bool x = false) const { return rep->m2 (x); }
  virtual C m3 (bool x = false) const { return rep->m3 (x); }
  virtual D m4 (bool x = false) const { return rep->m4 (x); }
  virtual std::string m5 (void) const { return rep->m5 (); }
  virtual std::string m6 (void) const { return rep->m6 (); }
  union { E *rep; int count; };
};

struct F
{
  F (void) : data () {}
  F (const E & tc) : data (1, tc) {}
  F (const F & obj):data (obj.data) {}
  ~F (void) {}
  E operator  () (int n) const { return n2 (n); }
  int n1 (void) const { return data.size (); }
  std::vector < E > data;
  E n2 (int n) const { return data[n]; }
};

static bool foo (const E & arg) { return (arg.m6 () == "foo"); }
F bar (const F & args) { return E (foo (args (0))); }
F fn1 (const F & args)
{
  E retval;

  if (args (0).m6 () == "foo")
    retval = args (0).m1 ();

  return retval;
}

static F f2 (const B & v) { F retval; return retval; }
static F f2 (const C & v) { F retval; return retval; }
static F f2 (const D & v) { F retval; return retval; }

F
f3 (const F & x)
{
  F retval;
  int n = x.n1 ();

  if (n != 1)
    return retval;

  E arg = x (0);
  if (arg.m6 () == "foo")
    {
      if (arg.m5 () == "bar")
        retval = f2 (x (0).m2 ());
      else if (arg.m5 () == "baz")
        retval = f2 (x (0).m3 ());
      else
        retval = f2 (x (0).m4 ());
    }

  return retval;
}
Comment 3 Ferdinand 2005-04-14 12:35:26 UTC
Your simplified testcase only causes an ICE when I use the C++ headers from gcc
3.4.3 with gcc 4.0.0, otherwise it works fine.

ICE: /opt/gcc40/bin/g++ -O -finline-functions test.cc -c -o test.o -isystem
/usr/include/c++/3.4.3

No ICE: /opt/gcc40/bin/g++ -O -finline-functions test.cc -c -o test.o

So you should be able to build Octave without problems...
Comment 4 Michael Matz 2005-04-15 02:40:27 UTC
We see this error in blender.  I was able to reduce it quite a bit to this: 
 
struct IMG_Rect { 
 virtual inline int getWidth() const; 
 virtual inline bool isEmpty() const; 
 virtual int getVisibility(int) const; 
}; 
 
inline int IMG_Rect::getWidth() const 
{ 
 return 1; 
} 
 
inline bool IMG_Rect::isEmpty() const 
{ 
 return (getWidth() == 0); 
} 
 
void A() 
{ 
 IMG_Rect i_bnds; 
 if (i_bnds.isEmpty()) 
  i_bnds.getWidth(); 
} 
 
void B() 
{ 
 IMG_Rect i_bnds; 
 if (i_bnds.isEmpty()) 
  i_bnds.getWidth(); 
} 
 
Comment 5 Michael Matz 2005-04-15 03:16:07 UTC
One strange thing is, that the call to getWidth() in B is already in .generic: 
    if (retval.1) 
      { 
        getWidth (&i_bnds); 
      } 
 
while the call to getWidth() in isEmpty() (which is inlined later into B()) is 
  D.1595 = this->_vptr.IMG_Rect; 
  D.1596 = *D.1595; 
  D.1597 = OBJ_TYPE_REF(D.1596;this->0) (this); 
  D.1594 = D.1597 == 0; 
 
Both are actually virtual calls of course, so I wonder why they are represented 
differently.  Note that this doesn't change if I make B() a method of IMG_Rect. 
I thought initially that might be a difference, as isEmpty is one. 
 
Another fact is, that if I comment out the totally unrelated useless decl for 
getVisibility(), it works.  The .i01.cgraph dump in that case shows these 
  Initial entry points: void B() void A() 
  Unit entry points: void B() void A() virtual bool IMG_Rect::isEmpty() const 
    virtual int IMG_Rect::getWidth() const 
 
while when it breaks (i.e. when getVisibility is there) it looks like: 
  Initial entry points: void B() void A() 
  Unit entry points: void B() void A() 
 
See how the two methods in question are now missing.  As they are declared inline this 
actually should be okay, and that getVisibility makes a difference might be another bug, 
which hides this one sometimes. 
Comment 6 Andrew Pinski 2005-04-15 05:36:35 UTC
Hmm, all of the testcases listed here work on the mainline.
Comment 7 Michael Matz 2005-04-15 06:51:52 UTC
Perhaps due to the IPA infrastructure? 
Comment 8 Jakub Jelinek 2005-04-17 16:08:12 UTC
Just got another bugreport for this bug, this time in gnomesword,
https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=155152

The new references are created in tree-ssa-ccp.c's fold_stmt when it
constant propagates the vptr access, but that is already when
cgraph does not allow new references to be created.

The problem only happens in compilation units that don't output
the virtual table.  But for methods in virtual tables we know that the method
will be emitted in some other compilation unit (where the virtual table
gets emitted), so having the method finalized as unreferenced in
the current compilation unit is not a problem.

So, I think at least as a short time solution we can add a flag to cgraph
node that will signalize that the function is guaranteed to be emitted
in some other CU.  This flag would be set in cp_fold_obj_type_ref
and cgraph_mark_reachable_node would only do something about such nodes
if they have needed set or !cgraph_global_info_ready.
Comment 9 Mark Mitchell 2005-04-17 17:04:04 UTC
Subject: Re:  [4.0 Regression] ICE in cgraph_mark_reachable_node

jakub at gcc dot gnu dot org wrote:
> ------- Additional Comments From jakub at gcc dot gnu dot org  2005-04-17 16:08 -------
> Just got another bugreport for this bug, this time in gnomesword,
> https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=155152
> 
> The new references are created in tree-ssa-ccp.c's fold_stmt when it
> constant propagates the vptr access, but that is already when
> cgraph does not allow new references to be created.

The easiest solution, then, might be not to do the constant propagation 
in that case.  That seems like it would attack the problem directly and 
locally.  It would of course result in inferior code, but this is a case 
that C++ compilers have traditionally been lame about, so it's not 
really a step backwards.

It also sounds like you might be able to come up with a C test case. 
The basic flaw is that cgraph is not expecting an apparently 
unreferenced function to become referenced as a result of the optimizers 
figuring out to what function a pointer pointers.  That's a bug in 
cgraph; it should conservatively assume that all functions whose address 
has been taken are referenced.  It doesn't have to emit them, or even 
process them until it knows they are referenced, but it shouldn't assume 
that they're not needed until all points-to analysis is complete. 
Perhaps it needs a tri-state (referenced, not referenced, don't know).

Comment 10 Jakub Jelinek 2005-04-17 21:28:24 UTC
On HEAD this doesn't fail any longer because of the:
* final.c (output_addr_const): Do not call mark_referenced.
change (part of tree profiling branch merge).

I don't think you can construct a C testcase for this, as soon as you save
some function's address into some reachable variable or take it in
some reachable function, cgraph will know about it.  The OBJ_TYPE_REF is special
in that there is no such variable in the current translation unit
and cp_fold_obj_type_ref just knows what is in the variable (vtable) in
some other translation unit and optimizes that access.

Of course we can
I'm ATM testing 2 different patches, will attach them here once the testing
finishes.
Comment 11 Andrew Pinski 2005-04-17 21:34:28 UTC
Confirmed, just a note the patch which "fixes" this on the mainline is wrong as shown by PR 20965.
Comment 12 Mark Mitchell 2005-04-17 21:52:18 UTC
Subject: Re:  [4.0 Regression] ICE in cgraph_mark_reachable_node

jakub at gcc dot gnu dot org wrote:

> some reachable function, cgraph will know about it.  The OBJ_TYPE_REF is special
> in that there is no such variable in the current translation unit
> and cp_fold_obj_type_ref just knows what is in the variable (vtable) in
> some other translation unit and optimizes that access.

So, perhaps one approach would be to have cgraph recognize the 
OBJ_TYPE_REF, and mark as reachable all things reachable from the 
vtable.  Not that this would necessarily be trivial to implement.

Comment 13 Jakub Jelinek 2005-04-18 04:51:59 UTC
Created attachment 8674 [details]
Fix that disables the optimization if cgraph would abort

This patch was bootstrapped/regtested on x86_64-linux.
Comment 14 Jakub Jelinek 2005-04-18 04:53:29 UTC
Created attachment 8675 [details]
Patch that fixes this by relying the method will be emitted together with its vtable
Comment 15 Jan Hubicka 2005-04-18 11:06:37 UTC
Subject: Re:  [4.0 Regression] ICE in cgraph_mark_reachable_node

> 
> ------- Additional Comments From jakub at gcc dot gnu dot org  2005-04-18 04:53 -------
> Created an attachment (id=8675)
>  --> (http://gcc.gnu.org/bugzilla/attachment.cgi?id=8675&action=view)
> Patch that fixes this by relying the method will be emitted together with its
> vtable

The cgraph bits looks OK for me for 4.0 branch.  I guess Mark will have
to comment on the C++ part.
Even in mainline we are not safe wrt this issue especially if we
introduce pre-inline optimizations that again might cprop the references
in.  I would like to see a variant of this patch for mainline that adds
varpool node pointer into cgraph node (such as *output_only_if) that
would prevent cgraphunit from marking it as needed unless the node
pointed too is needed too.   I can implement this next week, but I won't
mind being beaten ;)  It probably should be done by the post-inlining
dead function removal pass as we still want to see the function body for
inlining.

Honza
> 
> 
> -- 
> 
> 
> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=20991
> 
> ------- You are receiving this mail because: -------
> You are on the CC list for the bug, or are watching someone who is.
Comment 16 Mark Mitchell 2005-04-18 17:59:53 UTC
The patch in Comment #13 is OK for 4.0.0.  It's a pessimization, but it's rather
more obviously correct.  Please apply forthwith.  Thanks.
Comment 17 GCC Commits 2005-04-19 05:52:57 UTC
Subject: Bug 20991

CVSROOT:	/cvs/gcc
Module name:	gcc
Branch: 	gcc-4_0-branch
Changes by:	jakub@gcc.gnu.org	2005-04-19 05:52:46

Modified files:
	gcc            : ChangeLog tree-ssa-ccp.c 
	gcc/testsuite  : ChangeLog 
Added files:
	gcc/testsuite/g++.dg/opt: pr20991.C 

Log message:
	PR middle-end/20991
	* tree-ssa-ccp.c (fold_stmt): Don't optimize OBJ_TYPE_REFs if that
	would result in an already finalized unreachable node becoming
	reachable while cgraph_global_info_ready.
	
	* g++.dg/opt/pr20991.C: New test.

Patches:
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/ChangeLog.diff?cvsroot=gcc&only_with_tag=gcc-4_0-branch&r1=2.7592.2.170&r2=2.7592.2.171
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/tree-ssa-ccp.c.diff?cvsroot=gcc&only_with_tag=gcc-4_0-branch&r1=2.58&r2=2.58.2.1
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/ChangeLog.diff?cvsroot=gcc&only_with_tag=gcc-4_0-branch&r1=1.5084.2.128&r2=1.5084.2.129
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.dg/opt/pr20991.C.diff?cvsroot=gcc&only_with_tag=gcc-4_0-branch&r1=NONE&r2=1.1.2.1

Comment 18 GCC Commits 2005-04-24 12:46:46 UTC
Subject: Bug 20991

CVSROOT:	/cvs/gcc
Module name:	gcc
Branch: 	gcc-4_0-branch
Changes by:	jakub@gcc.gnu.org	2005-04-24 12:46:25

Modified files:
	gcc            : ChangeLog varasm.c cgraph.h tree-ssa-ccp.c 
	gcc/cp         : ChangeLog 

Log message:
	PR middle-end/20991
	* cgraph.h (cgraph_local_info): Add vtable_method field.
	* varasm.c (mark_decl_referenced): If cgraph_global_info_ready
	and node is vtable_method, finalized and not reachable, don't do
	anything.
	
	Revert:
	2005-04-18  Jakub Jelinek  <jakub@redhat.com>
	* tree-ssa-ccp.c (fold_stmt): Don't optimize OBJ_TYPE_REFs if that
	would result in an already finalized unreachable node becoming
	reachable while cgraph_global_info_ready.
	
	* class.c: Include cgraph.h.
	(cp_fold_obj_type_ref): Set node->local.vtable_method.
	* Make-lang.in (cgraph.o): Depend on $(CGRAPH_H).

Patches:
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/ChangeLog.diff?cvsroot=gcc&only_with_tag=gcc-4_0-branch&r1=2.7592.2.186&r2=2.7592.2.187
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/varasm.c.diff?cvsroot=gcc&only_with_tag=gcc-4_0-branch&r1=1.477.6.8&r2=1.477.6.9
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cgraph.h.diff?cvsroot=gcc&only_with_tag=gcc-4_0-branch&r1=1.44.8.3&r2=1.44.8.4
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/tree-ssa-ccp.c.diff?cvsroot=gcc&only_with_tag=gcc-4_0-branch&r1=2.58.2.1&r2=2.58.2.2
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cp/ChangeLog.diff?cvsroot=gcc&only_with_tag=gcc-4_0-branch&r1=1.4648.2.34&r2=1.4648.2.35

Comment 19 GCC Commits 2005-04-24 22:06:47 UTC
Subject: Bug 20991

CVSROOT:	/cvs/gcc
Module name:	gcc
Changes by:	jakub@gcc.gnu.org	2005-04-24 22:06:37

Modified files:
	gcc            : ChangeLog varasm.c cgraph.h 
	gcc/cp         : ChangeLog 
	gcc/testsuite  : ChangeLog 
	gcc/cp         : class.c Make-lang.in 
Added files:
	gcc/testsuite/g++.dg/opt: pr20991.C 

Log message:
	PR middle-end/20991
	* cgraph.h (cgraph_local_info): Add vtable_method field.
	* varasm.c (mark_decl_referenced): If cgraph_global_info_ready
	and node is vtable_method, finalized and not reachable, don't do
	anything.
	
	* class.c: Include cgraph.h.
	(cp_fold_obj_type_ref): Set node->local.vtable_method.
	* Make-lang.in (cgraph.o): Depend on $(CGRAPH_H).
	
	* g++.dg/opt/pr20991.C: New test.

Patches:
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/ChangeLog.diff?cvsroot=gcc&r1=2.8440&r2=2.8441
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/varasm.c.diff?cvsroot=gcc&r1=1.504&r2=1.505
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cgraph.h.diff?cvsroot=gcc&r1=1.50&r2=1.51
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cp/ChangeLog.diff?cvsroot=gcc&r1=1.4721&r2=1.4722
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/ChangeLog.diff?cvsroot=gcc&r1=1.5392&r2=1.5393
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cp/class.c.diff?cvsroot=gcc&r1=1.713&r2=1.714
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cp/Make-lang.in.diff?cvsroot=gcc&r1=1.200&r2=1.201
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.dg/opt/pr20991.C.diff?cvsroot=gcc&r1=1.1&r2=1.2

Comment 20 Jakub Jelinek 2005-04-24 22:11:53 UTC
Actually it failed on HEAD today (at least on ppc-linux).
Should be fixed on both 4.0 and HEAD CVS now though.