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

            Bug ID: 128571
           Summary: RISC-V: -msave-restore places -fzero-call-used-regs
                    zeroing after tail __riscv_restore_0
           Product: gcc
           Version: 16.2.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: target
          Assignee: unassigned at gcc dot gnu.org
          Reporter: 220245569 at seu dot edu.cn
                CC: 220255623 at seu dot edu.cn, jianhao.xu at seu dot edu.cn
  Target Milestone: ---
            Target: riscv64-*-*

Summary
-------
With -msave-restore, the register-zeroing instructions for foo are emitted
after the unconditional tail transfer to __riscv_restore_0. They cannot execute
on the return path. This occurs with GCC 16.2.0 targeting riscv64-linux-gnu.

Reproducer
----------
$ cat trigger.c
int ext(int);
int foo(int x) {
    return ext(x + 1) + 2;
}

Compile flag:
$ riscv64-linux-gnu-gcc -O2 -msave-restore -fzero-call-used-regs=all -S
trigger.c -o trigger.s

$ cat trigger.s
# Relevant instructions; CFI and most zeroing instructions omitted.
foo:
    call    t0,__riscv_save_0
    addiw   a0,a0,1
    call    ext
    addiw   a0,a0,2
    tail    __riscv_restore_0
    li      t0,0             # unreachable
    li      t1,0
    li      t2,0
    li      a1,0
    # ... remaining GPR and floating-point zeroing ...
    fmv.d.x ft11,zero

Expected behavior
-----------------
The requested register clearing should execute before foo returns.
__riscv_restore_0 is an epilogue helper; this is not a source-level sibling
call to ext.

Possible cause / Suggested Fix
-----------------------------
In riscv_expand_epilogue, gen_gpr_restore emits a non-jump instruction whose
assembly is "tail __riscv_restore_%0", followed by gen_gpr_restore_return, a
return instruction with an empty assembly template. pass_zero_call_used_regs
inserts its sequence before the latter RETURN_P instruction, so the sequence
appears after the actual tail transfer.

Please make the RTL return boundary match the emitted control transfer, or
otherwise insert clearing before that transfer. Any change also needs to
account for scratch registers used by the restore helper; simply moving the
sequence without reviewing the helper's register contract may be insufficient.

Reply via email to