https://gcc.gnu.org/g:59236d56eec6854e261dbf16963d5ee9e03bf7d5
commit r16-3014-g59236d56eec6854e261dbf16963d5ee9e03bf7d5 Author: Georg-Johann Lay <a...@gjlay.de> Date: Tue Aug 5 17:48:43 2025 +0200 AVR: Allow combination of sign_extend with ashift. gcc/ * config/avr/avr.cc (avr_rtx_costs_1) [SIGN_EXTEND]: Adjust cost. * config/avr/avr.md (*sext.ashift<QIPSI:mode><HISI:mode>2): New insn and a cc split. Diff: --- gcc/config/avr/avr.cc | 10 ++++++++++ gcc/config/avr/avr.md | 37 ++++++++++++++++++++++++++++++++++++- 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc index 1bfa3f5a00d7..ae49d4dc8bc1 100644 --- a/gcc/config/avr/avr.cc +++ b/gcc/config/avr/avr.cc @@ -12758,6 +12758,16 @@ avr_rtx_costs_1 (rtx x, machine_mode mode, int outer_code, return true; case SIGN_EXTEND: + if (GET_CODE (XEXP (x, 0)) == ASHIFT + && CONST_INT_P (XEXP (XEXP (x, 0), 1))) + { + // "*sext.ashift<QIPSI:mode><HISI:mode>2_split" + int m0 = GET_MODE_SIZE (GET_MODE (XEXP (x, 0))); + int m1 = GET_MODE_SIZE (mode); + *total = COSTS_N_INSNS (m0 * INTVAL (XEXP (XEXP (x, 0), 1)) + + m1 - m0); + return true; + } *total = COSTS_N_INSNS (n_bytes + 2 - GET_MODE_SIZE (GET_MODE (XEXP (x, 0)))); *total += avr_operand_rtx_cost (XEXP (x, 0), GET_MODE (XEXP (x, 0)), diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md index d4bf4dad76db..60b1f604f7be 100644 --- a/gcc/config/avr/avr.md +++ b/gcc/config/avr/avr.md @@ -2943,7 +2943,7 @@ [(set (match_operand:HI 0 "register_operand" "=r,*r") (ashift:HI (sign_extend:HI (match_operand:QI 1 "register_operand" "0,r")) (const_int 1))) - (clobber (reg:CC REG_CC)) ] + (clobber (reg:CC REG_CC))] "reload_completed" "@ lsl %A0\;sbc %B0,%B0 @@ -3004,6 +3004,41 @@ operands[2] = gen_int_mode (1 << INTVAL (operands[2]), QImode); }) +(define_insn_and_split "*sext.ashift<QIPSI:mode><HISI:mode>2_split" + [(set (match_operand:HISI 0 "register_operand" "=r") + (sign_extend:HISI (ashift:QIPSI (match_operand:QIPSI 1 "register_operand" "0") + (match_operand:QI 2 "const_int_operand" "PKC03"))))] + "<HISI:SIZE> > <QIPSI:SIZE> + && IN_RANGE (INTVAL (operands[2]), 1, 2 + (<QIPSI:SIZE> <= 2))" + "#" + "&& reload_completed" + [(scratch)] + { DONE_ADD_CCC }) + +(define_insn "*sext.ashift<QIPSI:mode><HISI:mode>2" + [(set (match_operand:HISI 0 "register_operand" "=r") + (sign_extend:HISI (ashift:QIPSI (match_operand:QIPSI 1 "register_operand" "0") + (match_operand:QI 2 "const_int_operand" "PKC03")))) + (clobber (reg:CC REG_CC))] + "reload_completed + && <HISI:SIZE> > <QIPSI:SIZE> + && IN_RANGE (INTVAL (operands[2]), 1, 2 + (<QIPSI:SIZE> <= 2))" + { + const int regno = REGNO (operands[0]); + // The shift. + for (int s = 0; s < (int) INTVAL (operands[2]); ++s) + for (int b = 0; b < <QIPSI:SIZE>; ++b) + output_asm_insn (b == 0 ? "lsl %0" : "rol %0", + &all_regs_rtx[regno + b]); + // Sign-extend can use carry. + for (int b = <QIPSI:SIZE>; b < <HISI:SIZE>; ++b) + output_asm_insn ("sbc %0,%0", &all_regs_rtx[regno + b]); + return ""; + } + [(set (attr "length") + (plus (symbol_ref "<QIPSI:SIZE> * INTVAL (operands[2])") + (symbol_ref "<HISI:SIZE> - <QIPSI:SIZE>")))]) + ;****************************************************************************** ; mul HI: $1 = sign-/zero-/one-extend, $2 = reg ;******************************************************************************