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.
  • [Bug tree-optimization/127874] N... kyuwoncho18 at gmail dot com via Gcc-bugs

Reply via email to