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
 ;******************************************************************************

Reply via email to