https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68470

Martin Liška <marxin at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |marxin at gcc dot gnu.org

--- Comment #4 from Martin Liška <marxin at gcc dot gnu.org> ---
(In reply to Mikhail Maltsev from comment #3)
> A bit simplified testcase:
> 
> void deallocate(void *);
> void *a;
> 
> struct C {
>   virtual void m_fn1();
> };
> 
> struct D {
>   C *m_fn2() {
>     if (a)
>       __builtin_abort();
>   }
> };
> D getd();
> 
> struct vec_int {
>   int _M_start;
>   ~vec_int() {
>     if (_M_start)
>       deallocate(&_M_start);
>   }
> };
> vec_int *b;
> 
> struct I {
>   virtual void m_fn3();
> };
> 
> void I::m_fn3() {
>   if (a)
>     getd().m_fn2()->m_fn1();
>   b->~vec_int();
> }
> 
> $ cc1plus -O2 test.cc - ICE after fnsplit
> $ cc1plus -O2 test.cc -fno-checking - ICE in IPA-ICF (like in the original
> bug report)
> $ cc1plus -O2 test.cc -fno-devirtualize - OK
> $ cc1plus -O2 test.cc --param partial-inlining-entry-probability=0 - OK
> 
> ISTM, this is some IPA-related issue:
> D::m_fn2 and vec_int::~vec_int are inlined into I::m_fn3.
> D::m_fn2 (D::operator-> in previous comments) does not return any value
> (undefined behavior), so gimple_fold_call devirtualizes
> getd().m_fn2()->m_fn1() into __builtin_unreachable during fwprop1.
> fnsplit then tries to split I::m_fn3. This is how the function looks before
> fnsplit:
> 
> ;; Function virtual void I::m_fn3() (_ZN1I5m_fn3Ev, funcdef_no=4,
> decl_uid=2299, cgraph_uid=4, symbol_order=6)
> 
> virtual void I::m_fn3() (struct I * const this)
> {
>   struct C * D.2356;
>   void * a.0_3;
>   void * a.2_5;
>   struct vec_int * b.1_12;
>   int _14;
>   int * _15;
> 
>   <bb 2>:
>   a.0_3 = a;
>   if (a.0_3 != 0B)
>     goto <bb 3>;
>   else
>     goto <bb 6>;
> 
>   <bb 3>:
>   getd ();
>   a.2_5 = a;
>   if (a.2_5 != 0B)
>     goto <bb 4>;
>   else
>     goto <bb 5>;
> 
>   <bb 4>:
>   __builtin_abort ();
> 
>   <bb 5>:
>   __builtin_unreachable ();
> 
>   <bb 6>:
>   b.1_12 = b;
>   _14 = b.1_12->_M_start;
>   if (_14 != 0)
>     goto <bb 7>;
>   else
>     goto <bb 8>;
> 
>   <bb 7>:
>   _15 = &b.1_12->_M_start;
>   deallocate (_15);
> 
>   <bb 8>:
>   MEM[(struct  &)b.1_12] ={v} {CLOBBER};
>   return;
> 
> }
> 
> The splitting pass tries to do this:
> 
> Splitting function at:
> Split point at BB 6
>   header time: 19646 header size: 10
>   split time: 2491 split size: 6
>   bbs: 6, 7
>   SSA names to pass: 
> Introduced new external node (void __builtin_unreachable()/18).
> 
> ICE probably happens in this part:
> 
> virtual void I::m_fn3() (struct I * const this)
> {
>   struct C * D.2356;
>   void * a.0_3;
>   void * a.2_5;
> 
>   <bb 2>:
>   a.0_3 = a;
>   if (a.0_3 != 0B)
>     goto <bb 3>;
>   else
>     goto <bb 6>;
> 
>   <bb 3>:
>   getd ();
>   a.2_5 = a;
>   if (a.2_5 != 0B)
>     goto <bb 4>;
>   else
>     goto <bb 5>;
> 
>   <bb 4>:
>   __builtin_abort ();
> 
>   <bb 5>:
>   __builtin_unreachable ();
> 
>   <bb 6>:
>   I::_ZN1I5m_fn3Ev.part.1 ();
>   MEM[(struct  &)_12] ={v} {CLOBBER};
>   return;
> 
> }

Hi.

The problem is really in <bb 6>, which contains definition of 'b.1_12' that is
used in return_bb (<bb 8>). The return_bb is eventually merged with <bb 6>.

I'm not sure about proper fix, I would expect that return_bb must be pruned of
all unused stmts (that would be moved to newly created function). Any ideas?

Martin

Reply via email to