https://gcc.gnu.org/g:c80ac3cb559f6ea2be6be3d0458c1615ff27c9a0

commit r17-3009-gc80ac3cb559f6ea2be6be3d0458c1615ff27c9a0
Author: Kito Cheng <[email protected]>
Date:   Tue Aug 4 10:43:37 2026 +0800

    RISC-V: Don't let popretz combine across a call [PR target/126454]
    
    The popretz pass scans backwards from cm.popret for the "li a0, 0" that
    feeds the (use a0), but nothing stopped the scan at a call: the argument
    registers of a call live in CALL_INSN_FUNCTION_USAGE, which
    reg_referenced_p does not look at, and the a0 set by a call_value hides
    in a PARALLEL, which the bare SET test did not match.  A "li a0, 0" that
    sets up the first argument of a call was therefore deleted and cm.popret
    became cm.popretz, so the callee got garbage in a0 and the caller
    returned 0 instead of the result of the callee.
    
    Use insn level helpers instead, find_reg_fusage for the uses and
    reg_set_p for the definitions, and ask them about the word_mode a0
    rather than about the a0 of the (use a0), whose mode covers a0 and a1
    for a DImode return value on rv32.
    
    gcc/ChangeLog:
    
            PR target/126454
            * config/riscv/riscv-opt-popretz.cc (pass_combine_popretz::execute):
            Stop the backward scan at any use or definition of a0, including
            those hidden in CALL_INSN_FUNCTION_USAGE or in a PARALLEL.
    
    gcc/testsuite/ChangeLog:
    
            PR target/126454
            * gcc.target/riscv/pr126454.c: New test.

Diff:
---
 gcc/config/riscv/riscv-opt-popretz.cc     | 44 ++++++++++++++++++-------------
 gcc/testsuite/gcc.target/riscv/pr126454.c | 36 +++++++++++++++++++++++++
 2 files changed, 61 insertions(+), 19 deletions(-)

diff --git a/gcc/config/riscv/riscv-opt-popretz.cc 
b/gcc/config/riscv/riscv-opt-popretz.cc
index a109780417b1..3c501d3df239 100644
--- a/gcc/config/riscv/riscv-opt-popretz.cc
+++ b/gcc/config/riscv/riscv-opt-popretz.cc
@@ -205,7 +205,7 @@ pass_combine_popretz::execute (function *fn)
 
       rtx_insn *def_a0_insn = NULL;
       rtx_insn *use_a0_insn = NULL;
-      rtx a0_reg = NULL;
+      rtx a0_reg = regno_reg_rtx[A0_REGNUM];
       /* Scan backwards from popret to find the pattern:
          1. First, find the (use a0) pseudo-instruction
          2. Continue scanning to find "li a0, 0" (set a0 to const0_rtx)
@@ -223,29 +223,35 @@ pass_combine_popretz::execute (function *fn)
              && REG_P (XEXP (def_pat, 0))
              && REGNO (XEXP (def_pat, 0)) == A0_REGNUM)
            {
-             a0_reg = XEXP (def_pat, 0);
              use_a0_insn = def_insn;
              continue;
            }
 
-         if (use_a0_insn && reg_referenced_p (a0_reg, def_pat))
+         if (use_a0_insn)
            {
-             /* a0 is used by other instruction before its use in popret.  */
-             use_a0_insn = NULL;
-             break;
-           }
-
-         if (use_a0_insn
-             && GET_CODE (def_pat) == SET
-             && REG_P (SET_DEST (def_pat))
-             && REGNO (SET_DEST (def_pat)) == A0_REGNUM)
-           {
-             if (SET_SRC (def_pat) == CONST0_RTX (GET_MODE (SET_SRC 
(def_pat))))
-               def_a0_insn = def_insn;
-             /* Stop the search regardless of the value assigned to a0,
-                because we only want to match the last (most recent)
-                definition of a0 before the (use a0).  */
-             break;
+             if (reg_referenced_p (a0_reg, def_pat)
+                 || (CALL_P (def_insn)
+                     && find_reg_fusage (def_insn, USE, a0_reg)))
+               {
+                 /* a0 is used by other instruction before its use in
+                    popret.  */
+                 use_a0_insn = NULL;
+                 break;
+               }
+
+             if (reg_set_p (a0_reg, def_insn))
+               {
+                 rtx set = single_set (def_insn);
+                 if (set
+                     && REG_P (SET_DEST (set))
+                     && REGNO (SET_DEST (set)) == A0_REGNUM
+                     && SET_SRC (set) == CONST0_RTX (GET_MODE (SET_SRC (set))))
+                   def_a0_insn = def_insn;
+                 /* Stop the search regardless of the value assigned to a0,
+                    because we only want to match the last (most recent)
+                    definition of a0 before the (use a0).  */
+                 break;
+               }
            }
          }
 
diff --git a/gcc/testsuite/gcc.target/riscv/pr126454.c 
b/gcc/testsuite/gcc.target/riscv/pr126454.c
new file mode 100644
index 000000000000..ac30c1756dff
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/pr126454.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options " -Os -march=rv32ima_zca_zcmp -mabi=ilp32 -mcmodel=medlow" }*/
+/* { dg-skip-if "" { *-*-* } {"-O0" "-O1" "-O2" "-Og" "-O3" "-Oz" "-flto"} } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+int callee (int a, int *p);
+
+/*
+**test_arg_setup:
+**     ...
+**     li      a0,0
+**     call    callee(?:@plt)?
+**     cm.popret       {ra}, 32
+**     ...
+*/
+int
+test_arg_setup (int mode)
+{
+  int local = mode;
+  return callee (0, &local);
+}
+
+/*
+**test_ret_zero:
+**     ...
+**     call    callee(?:@plt)?
+**     cm.popretz      {ra}, 32
+**     ...
+*/
+int
+test_ret_zero (int mode)
+{
+  int local = mode;
+  callee (0, &local);
+  return 0;
+}

Reply via email to