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.

Reply via email to