Bug 33572 - [4.3 Regression] wrong code with -O
Summary: [4.3 Regression] wrong code with -O
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: tree-optimization (show other bugs)
Version: 4.3.0
: P3 normal
Target Milestone: 4.3.0
Assignee: Alexandre Oliva
URL:
Keywords: wrong-code
Depends on:
Blocks:
 
Reported: 2007-09-27 16:03 UTC by Wouter Vermaelen
Modified: 2007-10-09 04:48 UTC (History)
10 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2007-09-27 21:03:18


Attachments
preprocessed source (reduced) (349 bytes, text/plain)
2007-09-27 20:30 UTC, Wouter Vermaelen
Details
assembly output (for reduced bug.ii) (1.02 KB, text/plain)
2007-09-27 20:31 UTC, Wouter Vermaelen
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Wouter Vermaelen 2007-09-27 16:03:03 UTC
> cat bug.cc
#include <vector>
#include <memory>

struct Foo { virtual void f() {} };

int main(int argc, char**)
{
        std::auto_ptr<Foo> foo;
        if (argc) {
                foo.reset(new Foo());
        } else {
                std::vector<int> v;
        }
        Foo* p = foo.release();
        p->f();
}

> g++ -O bug.cc
> a.out
Segmentation fault (core dumped)

I'm using SVN revision 128838 on linux-x86_64.
Without -O or with g++ version 4.2.1 this program works correctly.
Comment 1 Paolo Carlini 2007-09-27 16:36:53 UTC
I can't reproduce...
Comment 2 Serge Belyshev 2007-09-27 20:20:53 UTC
Could you please attach preprocessed source (.ii file ) and assembly output (.s) (use -save-temps option to generate them)
Comment 3 Wouter Vermaelen 2007-09-27 20:30:48 UTC
Created attachment 14257 [details]
preprocessed source (reduced)
Comment 4 Wouter Vermaelen 2007-09-27 20:31:40 UTC
Created attachment 14258 [details]
assembly output (for reduced bug.ii)
Comment 5 Richard Biener 2007-09-27 21:03:18 UTC
Confirmed.  The reduced testcase gets optimized to

<bb 3>:
  D.2145 = operator new (8);

<bb 4>:
  ((struct Foo *) D.2145)->_vptr.Foo = &_ZTV3Foo[2];

<bb 5>:
  D.2147 ={v} 0B->_vptr.Foo;
  OBJ_TYPE_REF(*D.2147;0B->0) (0B);

where dereferencing NULL obviously is bogus.  After 038t.sdse2 everything
looks ok:

<bb 4>:
  D.2124_3 = (struct Foo *) D.2145_2;
  D.2124_3->_vptr.Foo ={v} &_ZTV3Foo[2];
  goto <bb 6>;

<bb 5>:
  deallocate (&v, 0B);

<bb 6>:
  # foo$ptr_16 = PHI <foo$ptr_18(ab)(5), D.2124_3(4)>
  foo$ptr_19(ab) = 0B;
  D.2147_6 = foo$ptr_16->_vptr.Foo;
  D.2148_7 = *D.2147_6;

but after apply inline it's wrong!?

<bb 3>:
  D.2145_2 = operator new (8);

<bb 4>:
  D.2124_3 = (struct Foo *) D.2145_2;
  D.2124_3->_vptr.Foo ={v} &_ZTV3Foo[2];

<bb 5>:
  # foo$ptr_16 = PHI <foo$ptr_18(ab)(2), D.2124_3(4)>
  foo$ptr_19(ab) = 0B;
  D.2147_6 = foo$ptr_19(ab)->_vptr.Foo;
  D.2148_7 = *D.2147_6;
  OBJ_TYPE_REF(D.2148_7;foo$ptr_19(ab)->0) (foo$ptr_19(ab));
  goto <bb 7>;
Comment 6 Paolo Carlini 2007-09-27 21:19:32 UTC
I can see now from the reduced testcase that the library uses mt_alloc, not the default allocator. Next time, just say it... ;)
Comment 7 Richard Biener 2007-09-28 12:28:09 UTC
After inlining deallocate into main we end up with:

int main(int, char**) (argc, D.2111)
{
  static struct __pool pool;
  static struct __pool pool;
  int * p;
  struct Foo * foo$ptr;
  struct Foo * D.2185;
  struct Foo * D.2182;
  int save_filt.2;
  void * save_eptr.1;
  struct vector v;
  int (*__vtbl_ptr_type) (void) D.2148;
  int (*__vtbl_ptr_type) (void) * D.2147;
  void * D.2145;
  struct Foo * D.2124;

<bb 2>:
  foo$ptr_18(ab) = 0B;
  if (argc_1(D) != 0)
    goto <bb 3>;
  else
    goto <bb 5>;

<bb 3>:
  D.2145_2 = operator new (8);

<bb 4>:
  D.2124_3 = (struct Foo *) D.2145_2;
  D.2124_3->_vptr.Foo ={v} &_ZTV3Foo[2];
  goto <bb 10>;

<bb 5>:

<bb 6>:
  if (0)
    goto <bb 7>;
  else
    goto <bb 8>;

<bb 7>:
  _M_reclaim_block (&pool, 0B, 0);

<bb 8>:

<bb 9>:

<bb 10>:
  # foo$ptr_16 = PHI <foo$ptr_18(ab)(9), D.2124_3(4)>
  foo$ptr_19(ab) = 0B;
  D.2147_6 = foo$ptr_16->_vptr.Foo;
  D.2148_7 = *D.2147_6;
  OBJ_TYPE_REF(D.2148_7;foo$ptr_16->0) (foo$ptr_16);
  goto <bb 12>;

  # foo$ptr_17(ab) = PHI <foo$ptr_18(ab)(3), (7), foo$ptr_19(ab)(10)>
<L3>:;
  save_filt.2_10 = <<<filter object>>>;
  save_eptr.1_11 = <<<exception object>>>;
  D.2182_13 = foo$ptr_17(ab);
  operator delete (D.2182_13);
  <<<exception object>>> = save_eptr.1_11;
  <<<filter object>>> = save_filt.2_10;
  resx 1;

<bb 12>:
  D.2185_14 = foo$ptr_19(ab);
  operator delete (D.2185_14);
  return 0;

}

after cleanup_cfg it still looks sane:

int main(int, char**) (argc, D.2111)
{
  static struct __pool pool;
  static struct __pool pool;
  int * p;
  struct Foo * foo$ptr;
  struct Foo * D.2185;
  struct Foo * D.2182;
  int save_filt.2;
  void * save_eptr.1;
  struct vector v;
  int (*__vtbl_ptr_type) (void) D.2148;
  int (*__vtbl_ptr_type) (void) * D.2147;
  void * D.2145;
  struct Foo * D.2124;

<bb 2>:
  foo$ptr_18(ab) = 0B;
  if (argc_1(D) != 0)
    goto <bb 3>;
  else
    goto <bb 5>;

<bb 3>:
  D.2145_2 = operator new (8);

<bb 4>:
  D.2124_3 = (struct Foo *) D.2145_2;
  D.2124_3->_vptr.Foo ={v} &_ZTV3Foo[2];

<bb 5>:
  # foo$ptr_16 = PHI <foo$ptr_18(ab)(2), D.2124_3(4)>
  foo$ptr_19(ab) = 0B;
  D.2147_6 = foo$ptr_16->_vptr.Foo;
  D.2148_7 = *D.2147_6;
  OBJ_TYPE_REF(D.2148_7;foo$ptr_16->0) (foo$ptr_16);
  goto <bb 7>;

  # foo$ptr_17(ab) = PHI <foo$ptr_18(ab)(3), foo$ptr_19(ab)(5)>
<L3>:;
  save_filt.2_10 = <<<filter object>>>;
  save_eptr.1_11 = <<<exception object>>>;
  D.2182_13 = foo$ptr_17(ab);
  operator delete (D.2182_13);
  <<<exception object>>> = save_eptr.1_11;
  <<<filter object>>> = save_filt.2_10;
  resx 1;

<bb 7>:
  D.2185_14 = foo$ptr_19(ab);
  operator delete (D.2185_14);
  return 0;

}

the update_ssa (2048) call makes a mess out of it:

int main(int, char**) (argc, D.2111)
{
  static struct __pool pool;
  static struct __pool pool;
  int * p;
  struct Foo * foo$ptr;
  struct Foo * D.2185;
  struct Foo * D.2182;
  int save_filt.2;
  void * save_eptr.1;
  struct vector v;
  int (*__vtbl_ptr_type) (void) D.2148;
  int (*__vtbl_ptr_type) (void) * D.2147;
  void * D.2145;
  struct Foo * D.2124;

<bb 2>:
  foo$ptr_18(ab) = 0B;
  if (argc_1(D) != 0)
    goto <bb 3>;
  else
    goto <bb 5>;

<bb 3>:
  D.2145_2 = operator new (8);

<bb 4>:
  D.2124_3 = (struct Foo *) D.2145_2;
  D.2124_3->_vptr.Foo ={v} &_ZTV3Foo[2];

<bb 5>:
  # foo$ptr_16 = PHI <foo$ptr_18(ab)(2), D.2124_3(4)>
  foo$ptr_19(ab) = 0B;
  D.2147_6 = foo$ptr_19(ab)->_vptr.Foo;
  D.2148_7 = *D.2147_6;
  OBJ_TYPE_REF(D.2148_7;foo$ptr_19(ab)->0) (foo$ptr_19(ab));
  goto <bb 7>;

  # foo$ptr_17(ab) = PHI <foo$ptr_18(ab)(3), foo$ptr_19(ab)(5)>
<L3>:;
  save_filt.2_10 = <<<filter object>>>;
  save_eptr.1_11 = <<<exception object>>>;
  D.2182_13 = foo$ptr_17(ab);
  operator delete (D.2182_13);
  <<<exception object>>> = save_eptr.1_11;
  <<<filter object>>> = save_filt.2_10;
  resx 1;

<bb 7>:
  D.2185_14 = foo$ptr_19(ab);
  operator delete (D.2185_14);
  return 0;

}
Comment 8 Richard Biener 2007-09-28 12:59:24 UTC
Honza, as only foo$ptr is marked for renaming and that from update_ssa_across_eh_edges (), maybe this is a latent problem with inlining
and EH info?  Can you have a look?
Comment 9 Richard Biener 2007-09-30 12:41:02 UTC
Diego, we seem to have a general problem with the incremental SSA updater.
If we rename foo$ptr in

<bb 6>:
  # foo$ptr_16 = PHI <foo$ptr_18(ab)(5), D.1758_3(4)>
  p_12 = foo$ptr_16;
  foo$ptr_19(ab) = 0B;
  p_15 = foo$ptr_16;
  p_4 = foo$ptr_16;
  p_5 = foo$ptr_16;
  D.1781_6 = foo$ptr_16->_vptr.Foo;
  D.1782_7 = *D.1781_6;
  OBJ_TYPE_REF(D.1782_7;foo$ptr_16->0) (foo$ptr_16);
  goto <bb 8>;

it apperantly does not deal correctly with the lifetimes of foo$ptr_16 and
foo$ptr_19(ab) overlapping.  Note that the SSA_NAME_OCCURS_IN_ABNORMAL_PHI
flags are correct, foo$ptr_16 does not live across an EH edge (but just
local in BB 6).  Still, for this flag to prevent creating overlapping life
ranges it would have need to be set on foo$ptr_16 as well.

[In the testcase the final inliner is the first one to cause renaming of
foo$ptr, the early SRA pass introduces the life-range overlap (but hidden
by a copy chain) and the first copyprop makes it obviously visible (that's
the dump from above)]
Comment 10 Richard Biener 2007-09-30 12:51:04 UTC
Zdenek may also have an idea?
Comment 11 dnovillo@google.com 2007-09-30 13:41:36 UTC
Subject: Re:  [4.3 Regression] wrong code with -O

On 30 Sep 2007 12:41:03 -0000, rguenth at gcc dot gnu dot org
<gcc-bugzilla@gcc.gnu.org> wrote:
>
>
> ------- Comment #9 from rguenth at gcc dot gnu dot org  2007-09-30 12:41 -------
> Diego, we seem to have a general problem with the incremental SSA updater.
> If we rename foo$ptr in
>
> <bb 6>:
>   # foo$ptr_16 = PHI <foo$ptr_18(ab)(5), D.1758_3(4)>
>   p_12 = foo$ptr_16;
>   foo$ptr_19(ab) = 0B;
>   p_15 = foo$ptr_16;
>   p_4 = foo$ptr_16;
>   p_5 = foo$ptr_16;
>   D.1781_6 = foo$ptr_16->_vptr.Foo;
>   D.1782_7 = *D.1781_6;
>   OBJ_TYPE_REF(D.1782_7;foo$ptr_16->0) (foo$ptr_16);
>   goto <bb 8>;

Is the symbol foo$ptr being marked for renaming?  If so, that's wrong.
 A gimple register symbol cannot be marked for renaming if there are
overlapping live ranges in its SSA names.  We don't have a general
mechanism to prevent that.  Mostly because we do not keep track when
OLRs are created.  The generic SSA updating mechanism has no cheap way
of checking that.
Comment 12 rguenther@suse.de 2007-09-30 14:01:08 UTC
Subject: Re:  [4.3 Regression] wrong code with
 -O

On Sun, 30 Sep 2007, dnovillo at google dot com wrote:

> > ------- Comment #9 from rguenth at gcc dot gnu dot org  2007-09-30 12:41 -------
> > Diego, we seem to have a general problem with the incremental SSA updater.
> > If we rename foo$ptr in
> >
> > <bb 6>:
> >   # foo$ptr_16 = PHI <foo$ptr_18(ab)(5), D.1758_3(4)>
> >   p_12 = foo$ptr_16;
> >   foo$ptr_19(ab) = 0B;
> >   p_15 = foo$ptr_16;
> >   p_4 = foo$ptr_16;
> >   p_5 = foo$ptr_16;
> >   D.1781_6 = foo$ptr_16->_vptr.Foo;
> >   D.1782_7 = *D.1781_6;
> >   OBJ_TYPE_REF(D.1782_7;foo$ptr_16->0) (foo$ptr_16);
> >   goto <bb 8>;
> 
> Is the symbol foo$ptr being marked for renaming?  If so, that's wrong.
>  A gimple register symbol cannot be marked for renaming if there are
> overlapping live ranges in its SSA names.  We don't have a general
> mechanism to prevent that.  Mostly because we do not keep track when
> OLRs are created.  The generic SSA updating mechanism has no cheap way
> of checking that.

Yes, it is marked for renaming by the inliner.  Somehow the inliner
assumes there are no OLRs:

...
   The function mark PHI_RESULT of such PHI nodes for renaming; it is
   safe the EH edges are abnormal and SSA_NAME_OCCURS_IN_ABNORMAL_PHI
   must be set.  This means, that there will be no overlapping live ranges
   for the underlying symbol.

   This might change in future if we allow redirecting of EH edges and
   we might want to change way build CFG pre-inlining to include
   all the possible edges then.  */

static void
update_ssa_across_eh_edges (basic_block bb)
{
  edge e;
  edge_iterator ei;

  FOR_EACH_EDGE (e, ei, bb->succs)
    if (!e->dest->aux
        || ((basic_block)e->dest->aux)->index == ENTRY_BLOCK)
      {
        tree phi;

        gcc_assert (e->flags & EDGE_EH);
        for (phi = phi_nodes (e->dest); phi; phi = PHI_CHAIN (phi))
          {
            gcc_assert (SSA_NAME_OCCURS_IN_ABNORMAL_PHI
                        (PHI_RESULT (phi)));
            mark_sym_for_renaming
              (SSA_NAME_VAR (PHI_RESULT (phi)));
          }
      }
}

Comment 13 Alexandre Oliva 2007-10-01 19:55:17 UTC
Patch at http://gcc.gnu.org/ml/gcc-patches/2007-10/msg00061.html is quite likely to fix this.
Comment 14 Alexandre Oliva 2007-10-02 01:38:11 UTC
Subject: Bug 33572

Author: aoliva
Date: Tue Oct  2 01:37:59 2007
New Revision: 128939

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=128939
Log:
PR tree-optimization/33572
* tree-cfg.c (verify_stmts): Check for missing PHI defs.
* tree-inline.c (update_ssa_across_eh_edges): Renamed to...
(update_ssa_across_abnormal_edges): ... this.  Set slots in the
return PHI node.
(copy_edges_for_bb): Handle nonlocal label edges.
(make_nonlocal_label_edges): Deleted.
(optimize_inline_calls): Don't call it.

Modified:
    branches/var-tracking-assignments-branch/gcc/ChangeLog.vta
    branches/var-tracking-assignments-branch/gcc/tree-cfg.c
    branches/var-tracking-assignments-branch/gcc/tree-inline.c

Comment 15 Alexandre Oliva 2007-10-03 01:04:15 UTC
Confirmed, the patch fixes it.
Comment 16 Alexandre Oliva 2007-10-06 11:44:14 UTC
Subject: Bug 33572

Author: aoliva
Date: Sat Oct  6 11:43:56 2007
New Revision: 129051

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=129051
Log:
gcc/ChangeLog:
PR tree-optimization/33572
* tree-cfg.c (verify_stmts): Check for missing PHI defs.
* tree-inline.c (update_ssa_across_eh_edges): Renamed to...
(update_ssa_across_abnormal_edges): ... this.  Set slots in the
return PHI node.
(copy_edges_for_bb): Handle nonlocal label edges.
(make_nonlocal_label_edges): Deleted.
(optimize_inline_calls): Don't call it.
gcc/testsuite/ChangeLog:
PR tree-optimization/33572
* g++.dg/torture/pr33572.C: New.

Added:
    trunk/gcc/testsuite/g++.dg/torture/pr33572.C
Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/testsuite/ChangeLog
    trunk/gcc/tree-cfg.c
    trunk/gcc/tree-inline.c

Comment 17 H.J. Lu 2007-10-07 14:39:51 UTC
(In reply to comment #16)
> Subject: Bug 33572
> 
> Author: aoliva
> Date: Sat Oct  6 11:43:56 2007
> New Revision: 129051
> 
> URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=129051
> Log:
> gcc/ChangeLog:
> PR tree-optimization/33572
> * tree-cfg.c (verify_stmts): Check for missing PHI defs.
> * tree-inline.c (update_ssa_across_eh_edges): Renamed to...
> (update_ssa_across_abnormal_edges): ... this.  Set slots in the
> return PHI node.
> (copy_edges_for_bb): Handle nonlocal label edges.
> (make_nonlocal_label_edges): Deleted.
> (optimize_inline_calls): Don't call it.
> gcc/testsuite/ChangeLog:
> PR tree-optimization/33572
> * g++.dg/torture/pr33572.C: New.
> 
> Added:
>     trunk/gcc/testsuite/g++.dg/torture/pr33572.C
> Modified:
>     trunk/gcc/ChangeLog
>     trunk/gcc/testsuite/ChangeLog
>     trunk/gcc/tree-cfg.c
>     trunk/gcc/tree-inline.c
> 

g++.dg/torture/pr33572.C failed on Linux/ia32:

Executing on host: /export/build/gnu/gcc/build-i686-linux/gcc/testsuite/g++/../../g++ -B/export/build/gnu/gcc/build-i686-linux/gcc/testsuite/g++/../../ /net/gnu-13/export/gnu/src/gcc/gcc/gcc/testsuite/g++.dg/torture/pr33572.C  -nostdinc++ -I/export/build/gnu/gcc/build-i686-linux/i686-pc-linux-gnu/libstdc++-v3/include/i686-pc-linux-gnu -I/export/build/gnu/gcc/build-i686-linux/i686-pc-linux-gnu/libstdc++-v3/include -I/net/gnu-13/export/gnu/src/gcc/gcc/libstdc++-v3/libsupc++ -I/net/gnu-13/export/gnu/src/gcc/gcc/libstdc++-v3/include/backward -I/net/gnu-13/export/gnu/src/gcc/gcc/libstdc++-v3/testsuite/util -fmessage-length=0  -O0    -fno-show-column   -L/export/build/gnu/gcc/build-i686-linux/i686-pc-linux-gnu/./libstdc++-v3/src/.libs  -L/export/build/gnu/gcc/build-i686-linux/i686-pc-linux-gnu/./libstdc++-v3/src/.libs -L/export/build/gnu/gcc/build-i686-linux/i686-pc-linux-gnu/./libiberty  -lm   -o ./pr33572.exe    (timeout = 300)
/tmp/ccSsvTAh.o: In function `vector::deallocate(int*)':^M
pr33572.C:(.text._ZN6vector10deallocateEPi[_ZN6vector10deallocateEPi]+0x24): undefined reference to `__gnu_cxx::__pool<true>::_M_reclaim_block(char*, unsigned long)'^M
collect2: ld returned 1 exit status^M
Comment 18 John David Anglin 2007-10-08 16:41:46 UTC
I see the same failure as HJL on hppa-unknown-linux-gnu.
Comment 19 Alexandre Oliva 2007-10-08 23:57:30 UTC
Subject: Bug 33572

Author: aoliva
Date: Mon Oct  8 23:57:20 2007
New Revision: 129144

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=129144
Log:
PR tree-optimization/33572
* g++.dg/torture/pr33572.C: Replace with complete test.

Modified:
    trunk/gcc/testsuite/ChangeLog
    trunk/gcc/testsuite/g++.dg/torture/pr33572.C

Comment 20 Alexandre Oliva 2007-10-09 04:47:01 UTC
Subject: Bug 33572

Author: aoliva
Date: Tue Oct  9 04:46:49 2007
New Revision: 129151

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=129151
Log:
PR tree-optimization/33572
* tree-inline.c (update_ssa_across_abnormal_edges): Tolerate
the absence of a corresponding edge from the exit block.

Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/tree-inline.c

Comment 21 Alexandre Oliva 2007-10-09 04:48:08 UTC
Fixed.
Comment 22 Alexandre Oliva 2007-10-15 17:07:46 UTC
Subject: Bug 33572

Author: aoliva
Date: Mon Oct 15 17:07:20 2007
New Revision: 129356

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=129356
Log:
gcc/ChangeLog:
PR tree-optimization/33735
PR tree-optimization/33572
* tree-inline.c (update_ssa_across_abnormal_edges): Revert
2007-10-09's change.
* except.c (duplicate_eh_regions): Don't look for prev_try
beyond ERT_ALLOWED_EXCEPTIONS with an empty list.
gcc/testsuite/ChangeLog:
PR tree-optimization/33735
* g++.dg/torture/pr33735.C: New.

Added:
    trunk/gcc/testsuite/g++.dg/torture/pr33735.C
Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/except.c
    trunk/gcc/testsuite/ChangeLog
    trunk/gcc/tree-inline.c