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

            Bug ID: 126531
           Summary: Wrong code with ranger and exception handling
           Product: gcc
           Version: 17.0
            Status: UNCONFIRMED
          Keywords: wrong-code
          Severity: normal
          Priority: P3
         Component: tree-optimization
          Assignee: unassigned at gcc dot gnu.org
          Reporter: ktkachov at gcc dot gnu.org
  Target Milestone: ---

/* ranger_cache::range_from_dom (gcc/gimple-range-cache.cc:1784) applies an
   inferred range taken from a dominator block to a query block that is reached
   from that dominator through an EH edge.  The inference is accumulated at
line
   1820 and applied at line 1908 under
        if (!has_abnormal_call_or_eh_pred_edge_p (start_bb))
   which only inspects the predecessors of the query block.  The siblings guard
   the edge itself:
        ranger_cache::edge_range                gimple-range-cache.cc:1314
        gimple_ranger::range_on_edge            gimple-range.cc:281
            if ((e->flags & (EDGE_EH | EDGE_ABNORMAL)) == 0)

   g++, aborts at -O1 -O2 -O3 -Os.  Correct at -O0 and with
   -fno-tree-vrp -fno-thread-jumps -fno-tree-dominator-opts.  */

/* More than 16 bytes, so S is returned in memory.  *p becomes the return slot
   of the call and GIMPLE keeps a single statement "*p_7(D) = h (k_8(D));",
   a call that can throw whose store operand infers p != 0.  */

struct S { int a[8]; };

__attribute__((noipa)) S
h (int k)
{
  if (k)
    throw 1;                    /* Thrown before anything is stored.  */
  S s = {};
  s.a[0] = 5;
  return s;
}

__attribute__((noipa)) int
f (S *p, int k)
{
  int r = 0;
  try
    {
      *p = h (k);               /* Infers p != 0, but only if it completes.  */
      r = 1;
    }
  catch (...)
    {
      if (p == 0)               /* Must not fold: the store never ran.  */
        r = 12;
      else
        r = 2;
    }
  return r;
}

S obj;

int
main (void)
{
  if (f (&obj, 0) != 1)         /* Normal path, p is &obj.  */
    __builtin_abort ();
  if (f (0, 1) != 12)           /* h throws, no store, p is null.  */
    __builtin_abort ();
  return 0;
}

aborts on aarch64 as described in the comment and passes at -O0

Reply via email to