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