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.