https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127874
Bug ID: 127874
Summary: [15/16/17 Regression] ICE: in single_succ_edge, at
basic-block.h:327 with noreturn memset removed by DSE
as redundant store since r15-5336
Product: gcc
Version: 17.0
Status: UNCONFIRMED
Keywords: ice-on-valid-code
Severity: normal
Priority: P3
Component: tree-optimization
Assignee: unassigned at gcc dot gnu.org
Reporter: kyuwoncho18 at gmail dot com
Target Milestone: ---
godbolt: https://godbolt.org/z/YKnW8drj5
```c
extern void *memset (void *, int, __SIZE_TYPE__) __attribute__((noreturn));
int g;
void
f (char *p)
{
*p = 0;
if (g)
memset (p, 0, 1);
}
```
```console
$ gcc -O1 -c t.c
during GIMPLE pass: local-fnsummary
t.c: In function 'f':
t.c:10:1: internal compiler error: in single_succ_edge, at basic-block.h:327
10 | }
| ^
0x28b796b internal_error(char const*, ...)
???:0
0xa97878 fancy_abort(char const*, int, char const*)
???:0
0xf886e1 compute_fn_summary(cgraph_node*, bool)
???:0
```
This is trunk 17.0.0 20261012 on godbolt; a local 17.0.0 20260915 build with
--enable-checking=yes,extra,rtl gives the same ICE. GCC 15.1, 15.2, 15.3 (which
contains the r15-10943 backport), 16.1 and 16.2 crash with a segfault in the
same pass, and GCC 14.4 compiles it. `-O0` and `-O1 -fno-tree-dse` compile it
as well.
`-fdump-tree-dse1-details` shows that dse1 removes the call:
```
Deleted redundant call: memset (p_3(D), 0, 1);
...
<bb 2> :
*p_3(D) = 0;
g.0_1 = g;
if (g.0_1 != 0)
goto <bb 3>; [INV]
else
goto <bb 4>; [INV]
<bb 3> :
<bb 4> :
return;
```
This is the same problem as PR121103 (noreturn `memmove`), reached through a
path that its fix does not cover. r15-7269-g3d07e7bf13d (PR117892) added the
check to `dse_optimize_call`, and r16-7598-g36a5d12cca2 (PR121103, backported
as r15-10943) made `dse_optimize_stmt` skip a builtin call when
`gimple_call_ctrl_altering_p` is set, so a noreturn `memset` is no longer
removed as a dead store itself. Here, however, DSE is processing the earlier
`*p = 0`: `dse_optimize_redundant_stores` (tree-ssa-dse.cc) then finds the
later `memset (p, 0, 1)` among the uses, classifies it as a redundant zero
store and deletes it with `delete_dead_or_redundant_call`, without checking
`gimple_call_ctrl_altering_p`. After the noreturn call is gone, bb 3 has no
successor, and `compute_fn_summary` later hits the assertion in
`single_succ_edge`. Skipping control-altering calls in that loop should fix it.
The ICE starts with r15-5336-gcee7d080d5c ("Ignore conditions guarding
__builtin_unreachable in inliner metrics"), whose new walk in ipa-fnsummary
reaches that block. GCC 14.4 deletes the call too (its dse1 dump has the same
"Deleted redundant call" line), but nothing before fixup_cfg trips over the
empty block there; the redundant-store path dates from 3fe0ddc8833 (PR90883,
2019).
Disclaimer: This test case was generated by a fuzzer, and the report was
written with LLM assistance.