https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127795
Bug ID: 127795
Summary: [SPARC] DEBUG_INSN makes -g retain a dead computation
in delay-slot reorganization
Product: gcc
Version: 17.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: rtl-optimization
Assignee: unassigned at gcc dot gnu.org
Reporter: yqtian668 at gmail dot com
Target Milestone: ---
Host: x86_64-pc-linux-gnu
Target: sparc-elf
Build: x86_64-pc-linux-gnu
Created attachment 65790
--> https://gcc.gnu.org/bugzilla/attachment.cgi?id=65790&action=edit
patch
A debug instruction can stop `delete_prior_computation` from finding and
deleting a dead register definition during SPARC delay-slot reorganization.
As a result, `-g` retains an extra dead instruction that is deleted with
`-g0`. This reproduces on GCC trunk at revision
`54e232d0d4752b419ed775bdad50d83798fa899d`.
SPARC provides the reproducing delay-slot shape, but the affected walk is in
the target-independent `gcc/reorg.cc` implementation used by delay-slot
targets.
Reproducer:
```c
int
foo (int a, int b)
{
int e = a + b;
if (e >= 97)
return a;
}
```
Using a `sparc-elf` compiler built from that revision:
```
$ sparc-elf-gcc -O2 -fno-tree-ter -fno-var-tracking \
-fcompare-debug -S source.c
cc1: error: source.c: '-fcompare-debug' failure (length)
```
Actual behavior:
The relevant executable instructions are:
```
-g0: jmp %o7+8
nop
-g: add %o0, %o1, %o1
jmp %o7+8
nop
```
The extra `add` is dead, so no runtime miscompilation is currently known.
The problem is that debug information changes generated code and causes
`-fcompare-debug` to fail.
The first differing pass is `dbr`. When a jump is removed,
`delete_computation` calls `delete_prior_computation` for its `REG_DEAD`
notes. With `-g0`, the backward walk reaches and deletes the `add`. With
`-g`, a debug marker between the definition and its use ends the walk early.
Cause:
`delete_prior_computation` in `gcc/reorg.cc` walks backward using
`prev_nonnote_insn`:
```c
for (our_prev = prev_nonnote_insn (insn);
our_prev && (NONJUMP_INSN_P (our_prev) || CALL_P (our_prev));
our_prev = prev_nonnote_insn (our_prev))
```
`prev_nonnote_insn` can return a `DEBUG_INSN`, which does not satisfy the
loop condition and therefore terminates the search.
This is related to PR rtl-optimization/127725, but it is a separate site and a
different transformation path.
Proposed fix:
Using `prev_nonnote_nondebug_insn` for both steps of the walk makes the `-g`
and `-g0` builds agree. A patch and a focused `gcc.target/sparc` test are
prepared. The test checks both `-fcompare-debug` and that the dead `add` is
absent; it fails before the change and passes after it.
The patch passes `contrib/check_GNU_style.sh` and `git diff --check`. On
x86_64 Linux, the exact patch completed bootstrap and the full testsuite.
After normalizing the build-directory path embedded in one module test name,
the baseline and patched builds each produced 541,492 test-result records;
the records were identical.