]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
AVR: Allow combination of sign_extend with ashift.
authorGeorg-Johann Lay <avr@gjlay.de>
Tue, 5 Aug 2025 15:48:43 +0000 (17:48 +0200)
committerGeorg-Johann Lay <avr@gjlay.de>
Tue, 5 Aug 2025 15:53:58 +0000 (17:53 +0200)
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.

gcc/config/avr/avr.cc
gcc/config/avr/avr.md

index 1bfa3f5a00d7bfe0629c7d6715493dc9a9c59e6c..ae49d4dc8bc1ef998999fb6581370538958e6a77 100644 (file)
@@ -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)),
index d4bf4dad76db858ed4440948bac0482f17f00e41..60b1f604f7be83b3451c99b788e0a836a2703dd0 100644 (file)
   [(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
     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
 ;******************************************************************************