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

--- Comment #2 from Oleg Endo <olegendo at gcc dot gnu.org> ---
The *cbranch_t splitter is done like 4 times, because there are 4 split passes.
 The last split pass is split5, which is done right after the delayed-branch
pass.  Before delayed-branch handling the call insn looks like:

(call_insn 13 79 14 2 (parallel [
            (call (mem:SI (reg/f:SI 1 r1 [167]) [0 bar S4 A32])
                (const_int 0 [0]))
            (use (reg:PSI 151 ))
            (clobber (reg:SI 146 pr))
        ]) sh_tmp.cpp:453 304 {calli}
     (expr_list:REG_DEAD (reg:PSI 151 )
        (expr_list:REG_DEAD (reg:SI 4 r4)
            (expr_list:REG_DEAD (reg/f:SI 1 r1 [167])
                (nil))))
    (expr_list:REG_UNUSED (use (reg:SI 4 r4))
        (nil)))

And modified_between_p returns true.

After delayed-branch pass the call insn looks like:

(insn 122 60 14 (sequence [
            (call_insn 13 60 12 (parallel [
                        (call (mem:SI (reg/f:SI 1 r1 [167]) [0 bar S4 A32])
                            (const_int 0 [0]))
                        (use (reg:PSI 151 ))
                        (clobber (reg:SI 146 pr))
                    ]) sh_tmp.cpp:453 304 {calli}
                 (expr_list:REG_DEAD (reg:PSI 151 )
                    (expr_list:REG_DEAD (reg:SI 4 r4)
                        (expr_list:REG_DEAD (reg/f:SI 1 r1 [167])
                            (nil))))
                (expr_list:REG_UNUSED (use (reg:SI 4 r4))
                    (nil)))
            (insn 12 13 14 (set (reg:SI 4 r4)
                    (reg/f:SI 15 r15)) 247 {movsi_ie}
                 (nil))
        ]) sh_tmp.cpp:453 -1
     (nil))

And modified_between_p returns false, because the function reg_set_p doesn't
handle sequence rtx codes.

This could be a fix:

Index: gcc/rtlanal.c
===================================================================
--- gcc/rtlanal.c    (revision 218544)
+++ gcc/rtlanal.c    (working copy)
@@ -875,17 +875,24 @@
 {
   /* We can be passed an insn or part of one.  If we are passed an insn,
      check if a side-effect of the insn clobbers REG.  */
-  if (INSN_P (insn)
-      && (FIND_REG_INC_NOTE (insn, reg)
-      || (CALL_P (insn)
-          && ((REG_P (reg)
-           && REGNO (reg) < FIRST_PSEUDO_REGISTER
-           && overlaps_hard_reg_set_p (regs_invalidated_by_call,
-                           GET_MODE (reg), REGNO (reg)))
-          || MEM_P (reg)
-          || find_reg_fusage (insn, CLOBBER, reg)))))
-    return 1;
+  if (INSN_P (insn) && FIND_REG_INC_NOTE (insn, reg))
+    return true;

+  /* After delay slot handling, call and branch insns might be in a
+     sequence.  Check all the elements there.  */
+  if (INSN_P (insn) && GET_CODE (PATTERN (insn)) == SEQUENCE)
+    for (int i = 0; i < XVECLEN (PATTERN (insn), 0); ++i)
+      if (reg_set_p (reg, XVECEXP (PATTERN (insn), 0, i)))
+    return true;
+
+  if (CALL_P (insn)
+      && ((REG_P (reg) && REGNO (reg) < FIRST_PSEUDO_REGISTER
+       && overlaps_hard_reg_set_p (regs_invalidated_by_call,
+                       GET_MODE (reg), REGNO (reg)))
+      || MEM_P (reg)
+      || find_reg_fusage (insn, CLOBBER, reg)))
+    return true;
+
   return set_of (reg, insn) != NULL_RTX;
 }


I haven't checked it, but maybe this also helps PR 56451 in some way.


Alternatively, we can just disable the *cbranch_t splitter after the
delay-branch pass:

Index: gcc/config/sh/sh.md
===================================================================
--- gcc/config/sh/sh.md    (revision 218544)
+++ gcc/config/sh/sh.md    (working copy)
@@ -8361,7 +8361,7 @@
 {
   return output_branch (sh_eval_treg_value (operands[1]), insn, operands);
 }
-  "&& 1"
+  "&& !crtl->dbr_scheduled_p"
   [(set (pc) (if_then_else (eq (reg:SI T_REG) (match_dup 2))
                (label_ref (match_dup 0))
                (pc)))]


Both patches fix the problem here, but I haven't tested them further.  My
feeling is that the function reg_set_p should be fixed.

Reply via email to