https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127933

            Bug ID: 127933
           Summary: RISC-V: Debug use keeps an unused vsetvli destination
                    and causes -fcompare-debug failure
           Product: gcc
           Version: 17.0
            Status: UNCONFIRMED
          Keywords: compare-debug-failure
          Severity: normal
          Priority: P3
         Component: target
          Assignee: unassigned at gcc dot gnu.org
          Reporter: yqtian668 at gmail dot com
  Target Milestone: ---
            Target: riscv64-unknown-linux-gnu

Created attachment 65866
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=65866&action=edit
Proposed patch and regression tests

GCC trunk generates a different `vsetvli` instruction when debug information
is enabled.  A debug-only use of the VL result is treated as an ordinary use,
so `-g` keeps a destination register that `-g0` correctly discards.

Tested revision:

```text
40b414ce63a5448495df9161aea0bfb495b47c11
```

Reproducer:

```c
#include <stddef.h>
#include <riscv_vector.h>

void
vadd (int32_t *a, const int32_t *b, const int32_t *c, size_t n)
{
  size_t vl = __riscv_vsetvl_e32m1 (n);
  vint32m1_t vb = __riscv_vle32_v_i32m1 (b, vl);
  vint32m1_t vc = __riscv_vle32_v_i32m1 (c, vl);
  vint32m1_t result = __riscv_vadd_vv_i32m1 (vb, vc, vl);
  __riscv_vse32_v_i32m1 (a, result, vl);
}
```

Command:

```sh
riscv64-unknown-linux-gnu-gcc -O2 -march=rv64gcv -mabi=lp64d \
  -fcompare-debug -S source.c
```

Actual result:

```text
cc1: error: source.c: '-fcompare-debug' failure (length)
```

The relevant instruction is:

```text
-g0: vsetvli zero,a3,e32,m1,ta,ma
-g:  vsetvli a3,a3,e32,m1,ta,ma
```

The VL destination is dead in ordinary code.  With `-g`, however, GCC emits a
debug bind for the source variable `vl`.  `has_no_uses` in
`gcc/config/riscv/riscv-vsetvl.cc` examines every later instruction with
`df_find_use`, including debug instructions, and therefore decides that the
destination is still used.

Ignoring the debug use is not sufficient by itself: once the destination is
replaced with `zero`, a debug bind reached by the old definition must no
longer describe the variable as living in that register.  The candidate patch
uses exact DF def-use chains to find those debug binds, including binds in
successor blocks, and marks their locations unavailable before completing the
transformation.

Two focused tests were run.  The natural reproducer checks both the generated
`vsetvli` and the debug location for `vl`.  A second CFG test checks debug uses
reached in a successor block.  The unmodified compiler reports 10 failures
and 5 unresolved checks for the first test, and 15 failures and 5 unresolved
checks for the second.  With the patch, the tests report 15 and 20 expected
passes respectively.  The checking-enabled compiler's C and C++ selftests
also pass.  `git diff --check` and `contrib/check_GNU_style.sh` are clean.

Expected result: debug-only uses should not keep an otherwise unused
`vsetvli` destination, and debug locations that depended on the removed
definition should be made unavailable.

I searched GCC Bugzilla for `vsetvl debug`, `vsetvli -g`,
`has_no_uses`, and `remove_unused_dest_operand` and did not find an exact
match.  PR target/126244 also concerns a dead `vsetvli` destination, but it is
a wrong-code issue unrelated to debug information.

Reply via email to