https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54089
--- Comment #89 from Alexander Klepikov <klepikov.alex+bugs at gmail dot com> --- Here's what I did sh.md: (define_expand "ashrsi3" [(parallel [(set (match_operand:SI 0 "arith_reg_dest" "") (ashiftrt:SI (match_operand:SI 1 "arith_reg_operand" "") (match_operand:SI 2 "nonmemory_operand" ""))) (clobber (reg:SI T_REG))])] "" { if (expand_ashiftrt (operands)) DONE; if (!CONST_INT_P (operands[2])) FAIL; int value = INTVAL (operands[2]) & 31; emit_insn (gen_ashrsi3_n_call (operands[0], operands[1], GEN_INT(value))); DONE; }) (define_insn_and_split "ashrsi3_n_call" [(set (match_operand:SI 0 "arith_reg_dest" "=r") (ashiftrt:SI (match_operand:SI 1 "arith_reg_operand" "0") (match_operand:SI 2 "const_int_operand"))) (clobber (reg:SI T_REG))] "TARGET_SH1" "#" "&& can_create_pseudo_p ()" [(const_int 0)] { char func[18]; int value; rtx wrk; cfun->machine->ashrsi3_libcall_expanded++; if (expand_ashiftrt (operands)) DONE; if (!CONST_INT_P (operands[2])) FAIL; value = INTVAL (operands[2]) & 31; if (dump_file) fprintf(dump_file, "ashrsi3_n_call: Expanding ashrsi3 libcall\n"); wrk = gen_reg_rtx (Pmode); /* Load the value into an arg reg and call a helper. */ emit_move_insn (gen_rtx_REG (SImode, 4), operands[1]); sprintf (func, "__ashiftrt_r4_%d", value); rtx lab = function_symbol (wrk, func, SFUNC_STATIC).lab; emit_insn (gen_ashrsi3_n (GEN_INT (value), wrk, lab)); emit_move_insn (operands[0], gen_rtx_REG (SImode, 4)); DONE; }) sh.cc: bool expand_ashiftrt (rtx *operands) { rtx wrk; int value; if (TARGET_DYNSHIFT) { if (!CONST_INT_P (operands[2])) { rtx count = copy_to_mode_reg (SImode, operands[2]); emit_insn (gen_negsi2 (count, count)); emit_insn (gen_ashrsi3_d (operands[0], operands[1], count)); return true; } else if (ashiftrt_insns[INTVAL (operands[2]) & 31] > 1 + SH_DYNAMIC_SHIFT_COST) { rtx count = force_reg (SImode, GEN_INT (- (INTVAL (operands[2]) & 31))); emit_insn (gen_ashrsi3_d (operands[0], operands[1], count)); return true; } } if (!CONST_INT_P (operands[2])) return false; value = INTVAL (operands[2]) & 31; if (value == 31) { /* If we are called from abs expansion, arrange things so that we we can use a single MT instruction that doesn't clobber the source, if LICM can hoist out the load of the constant zero. */ if (currently_expanding_to_rtl) { emit_insn (gen_cmpgtsi_t (force_reg (SImode, CONST0_RTX (SImode)), operands[1])); emit_insn (gen_mov_neg_si_t (operands[0], get_t_reg_rtx ())); return true; } emit_insn (gen_ashrsi2_31 (operands[0], operands[1])); return true; } else if (value >= 16 && value <= 19) { wrk = gen_reg_rtx (SImode); emit_insn (gen_ashrsi2_16 (wrk, operands[1])); value -= 16; while (value--) gen_ashift (ASHIFTRT, 1, wrk); emit_move_insn (operands[0], wrk); return true; } /* Expand a short sequence inline, longer call a magic routine. */ else if (value <= 5) { wrk = gen_reg_rtx (SImode); emit_move_insn (wrk, operands[1]); while (value--) gen_ashift (ASHIFTRT, 1, wrk); emit_move_insn (operands[0], wrk); return true; } return false; } Now GCC falls into infinite loop when compiling this: int f_short_rshift_signed(char v){ return v >> 5; } It looks like it splits and then combines again.