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