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

Mikhail Maltsev <miyuki at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |miyuki at gcc dot gnu.org
          Component|middle-end                  |ipa

--- Comment #3 from Mikhail Maltsev <miyuki at gcc dot gnu.org> ---
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;

}

Reply via email to