https://gcc.gnu.org/g:939362411d0903542647dae0eff82db10a3ad78a

commit r15-5599-g939362411d0903542647dae0eff82db10a3ad78a
Author: Georg-Johann Lay <a...@gjlay.de>
Date:   Thu Nov 21 22:59:14 2024 +0100

    AVR: target/117726 - Tweak ashiftrt:SI and lshiftrt:SI insns.
    
    This patch is similar to r15-5569 (tweak ashift:SI) but for
    ashiftrt and lshiftrt codes.  It splits constant shift offsets > 16
    into a 3-operand byte shift and a 2-operand residual bit shift.
       Moreover, some of the constraint alternatives have been promoted
    to 3-operand alternatives regardless of options.  For example,
    ashift:HI and lshiftrt:HI can support 3 operands for offsets 9...12
    without any overhead.
       Apart from that, it's a bit of code clean up for 2-byte and 4-byte
    shift insns:  Use one RTL peephole with any_shift code iterator
    instead of 3 individual peepholes.  It also removes some useless
    split insns; presumably introduced during the cc0 -> CCmode work.
    
            PR target/117726
    gcc/
            * config/avr/avr-passes.cc (avr_split_shift): Also handle
            ASHIFTRT and LSHIFTRT codes for 4-byte shifts.
            (constr_split_shift4): New code_attr.
            (avr_emit_shift): Adjust to new shift capabilities.
            * config/avr/predicates.md (scratch_or_d_register_operand):
            rename to scratch_or_dreg_operand.
            * config/avr/avr.md: Same.
            (define_peephole2): Write the RTL scratch peephole for 2-byte and
            4-byte shifts that generates *sh*<mode>3_const insns using code
            iterator any_shift.
            (*ashlhi3_const_split, *ashrhi3_const_split, *ashrhi3_const_split)
            (*lshrsi3_const_split, *lshrhi3_const_split): Remove useless
            split insns.
            (define_split) [avropt_split_bit_shift]: Add splitters
            for 4-byte ASHIFTRT and LSHIFTRT insns using avr_split_shift().
            (ashrsi3, *ashrsi3, *ashrsi3_const): Add "r,0,C4a" and "r,r,C4a"
            constraint alternatives depending on 2op, 3op.
            (lshrsi3, *lshrsi3, *lshrsi3_const): Add "r,0,C4r" and "r,r,C4r"
            constraint alternatives depending on 2op, 3op. Add "r,r,C15".
            (lshrhi3, *lshrhi3, *lshrhi3_const, ashlhi3, *ashlhi3)
            (*ashlhi3_const): Add "r,r,C7c" alternative.
            (ashrpsi, *ashrpsi3): Add "r,r,C22" alternative.
            (ashlqi, *ashlqi): Turn C06 alternative into "r,r,C06".
            * config/avr/constraints.md (C14, C22, C30, C7c): New constraints.
            * config/avr/avr.cc (ashlhi3_out, lshrhi3_out)
            [case 7, 9, 10, 11, 12]: Support as 3-operand insn.
            (lshrsi3_out) [case 15]: Same.
            (ashrsi3_out) [case 30]: Same.
            (ashrhi3_out) [case 14]: Same.
            (ashrqi3_out) [case 6]: Same.
            (avr_out_ashrpsi3) [case 22]: Same.
            * config/avr/avr.h: Fix comment typo.
            * doc/invoke.texi (AVR Options) <-msplit-bit-shift>: Document.

Diff:
---
 gcc/config/avr/avr-passes.cc  |  95 +++++++++--
 gcc/config/avr/avr.cc         | 174 ++++++++++++++++----
 gcc/config/avr/avr.h          |   7 +-
 gcc/config/avr/avr.md         | 371 ++++++++++++++++--------------------------
 gcc/config/avr/constraints.md |  20 +++
 gcc/config/avr/predicates.md  |   2 +-
 gcc/doc/invoke.texi           |  11 +-
 7 files changed, 395 insertions(+), 285 deletions(-)

diff --git a/gcc/config/avr/avr-passes.cc b/gcc/config/avr/avr-passes.cc
index 57c3fed1e410..bd249b70e8d6 100644
--- a/gcc/config/avr/avr-passes.cc
+++ b/gcc/config/avr/avr-passes.cc
@@ -43,6 +43,7 @@
 #include "context.h"
 #include "tree-pass.h"
 #include "insn-attr.h"
+#include "tm-constrs.h"
 
 
 #define CONST_INT_OR_FIXED_P(X) (CONST_INT_P (X) || CONST_FIXED_P (X))
@@ -2412,6 +2413,7 @@ bbinfo_t::find_plies (int len, const insninfo_t &ii, 
const memento_t &memo0)
 
       bool profitable = (cost < SCALE * fpd->max_ply_cost
                         || (bbinfo_t::try_split_any_p
+                            && fpd->solution.n_plies == 0
                             && cost / SCALE <= fpd->max_ply_cost
                             && cost / SCALE == fpd->movmode_cost));
       if (! profitable)
@@ -4840,37 +4842,54 @@ avr_shift_is_3op ()
    LSHIFTRT, ASHIFT } into a byte shift and a residual bit shift.  */
 
 bool
-avr_split_shift_p (int n_bytes, int offset, rtx_code)
+avr_split_shift_p (int n_bytes, int offset, rtx_code code)
 {
   gcc_assert (n_bytes == 4);
 
-  return (avr_shift_is_3op ()
-         && offset % 8 != 0 && IN_RANGE (offset, 17, 30));
+  if (avr_shift_is_3op ()
+      && offset % 8 != 0)
+    return select<bool>()
+      : code == ASHIFT ? IN_RANGE (offset, 17, 30)
+      : code == ASHIFTRT ? IN_RANGE (offset, 9, 29)
+      : code == LSHIFTRT ? IN_RANGE (offset, 9, 30) && offset != 15
+      : bad_case<bool> ();
+
+  return false;
 }
 
 
+/* Emit a DEST = SRC <code> OFF shift of QImode, HImode or PSImode.
+   SCRATCH is a QImode d-register, scratch:QI, or NULL_RTX.  */
+
 static void
 avr_emit_shift (rtx_code code, rtx dest, rtx src, int off, rtx scratch)
 {
-  machine_mode mode = GET_MODE (dest);
+  const machine_mode mode = GET_MODE (dest);
+  rtx xoff = GEN_INT (off);
+  bool is_3op = (off % 8 == 0
+                || off == GET_MODE_BITSIZE (mode) - 1
+                || (code == ASHIFTRT && off == GET_MODE_BITSIZE (mode) - 2)
+                || (mode == HImode
+                    && (code == ASHIFT || code == LSHIFTRT)
+                    && satisfies_constraint_C7c (xoff) /* 7...12 */));
   rtx shift;
 
-  if (off == GET_MODE_BITSIZE (mode) - 1)
+  if (is_3op)
     {
-      shift = gen_rtx_fmt_ee (code, mode, src, GEN_INT (off));
+      shift = gen_rtx_fmt_ee (code, mode, src, xoff);
     }
   else
     {
       if (REGNO (dest) != REGNO (src))
        emit_valid_move_clobbercc (dest, src);
-      shift = gen_rtx_fmt_ee (code, mode, dest, GEN_INT (off));
+      shift = gen_rtx_fmt_ee (code, mode, dest, xoff);
     }
 
   emit_valid_move_clobbercc (dest, shift, scratch);
 }
 
 
-/* Worker for define_split that run when -msplit-bit-shift is on.
+/* Worker for define_split that runs when -msplit-bit-shift is on.
    Split a shift of code CODE into a 3op byte shift and a residual bit shift.
    Return 'true' when a split has been performed and insns have been emitted.
    Otherwise, return 'false'.  */
@@ -4887,25 +4906,73 @@ avr_split_shift (rtx xop[], rtx scratch, rtx_code code)
 
   if (code == ASHIFT)
     {
-      if (ioff >= 25)
+      if (IN_RANGE (ioff, 25, 30))
        {
          rtx dst8 = avr_byte (dest, 3);
          rtx src8 = avr_byte (src, 0);
-         avr_emit_shift (code, dst8, src8, ioff % 8, NULL_RTX);
+         avr_emit_shift (code, dst8, src8, ioff - 24, NULL_RTX);
          emit_valid_move_clobbercc (avr_byte (dest, 2), const0_rtx);
          emit_valid_move_clobbercc (avr_word (dest, 0), const0_rtx);
          return true;
        }
-      else if (ioff >= 17)
+      else if (IN_RANGE (ioff, 17, 23))
        {
          rtx dst16 = avr_word (dest, 2);
          rtx src16 = avr_word (src, 0);
-         avr_emit_shift (code, dst16, src16, ioff % 16, scratch);
+         avr_emit_shift (code, dst16, src16, ioff - 16, scratch);
          emit_valid_move_clobbercc (avr_word (dest, 0), const0_rtx);
          return true;
        }
-      else
-       gcc_unreachable ();
+    }
+  else if (code == ASHIFTRT
+          || code == LSHIFTRT)
+    {
+      if (IN_RANGE (ioff, 25, 30))
+       {
+         rtx dst8 = avr_byte (dest, 0);
+         rtx src8 = avr_byte (src, 3);
+         avr_emit_shift (code, dst8, src8, ioff - 24, NULL_RTX);
+         if (code == ASHIFTRT)
+           {
+             rtx signs = avr_byte (dest, 1);
+             avr_emit_shift (code, signs, src8, 7, NULL_RTX);
+             emit_valid_move_clobbercc (avr_byte (dest, 2), signs);
+             emit_valid_move_clobbercc (avr_byte (dest, 3), signs);
+           }
+         else
+           {
+             emit_valid_move_clobbercc (avr_byte (dest, 1), const0_rtx);
+             emit_valid_move_clobbercc (avr_word (dest, 2), const0_rtx);
+           }
+         return true;
+       }
+      else if (IN_RANGE (ioff, 17, 23))
+       {
+         rtx dst16 = avr_word (dest, 0);
+         rtx src16 = avr_word (src, 2);
+         avr_emit_shift (code, dst16, src16, ioff - 16, scratch);
+         if (code == ASHIFTRT)
+           {
+             rtx msb = avr_byte (src, 3);
+             rtx signs = avr_byte (dest, 2);
+             avr_emit_shift (code, signs, msb, 7, NULL_RTX);
+             emit_valid_move_clobbercc (avr_byte (dest, 3), signs);
+           }
+         else
+           emit_valid_move_clobbercc (avr_word (dest, 2), const0_rtx);
+
+         return true;
+       }
+      else if (IN_RANGE (ioff, 9, 15))
+       {
+         avr_emit_shift (code, dest, src, 8, NULL_RTX);
+         rtx dst24 = avr_chunk (PSImode, dest, 0);
+         rtx src24 = avr_chunk (PSImode, dest, 0);
+         if (! scratch)
+           scratch = gen_rtx_SCRATCH (QImode);
+         avr_emit_shift (code, dst24, src24, ioff - 8, scratch);
+         return true;
+       }
     }
   else
     gcc_unreachable ();
diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc
index cc13dae9bfea..64d7795f37cc 100644
--- a/gcc/config/avr/avr.cc
+++ b/gcc/config/avr/avr.cc
@@ -6809,6 +6809,7 @@ ashlhi3_out (rtx_insn *insn, rtx operands[], int *plen)
                      && XVECLEN (PATTERN (insn), 0) == 3
                      && REG_P (operands[3]));
       bool ldi_ok = test_hard_reg_class (LD_REGS, operands[0]);
+      bool reg1_unused_after = reg_unused_after (insn, operands[1]);
 
       if (plen)
        *plen = 0;
@@ -6878,43 +6879,50 @@ ashlhi3_out (rtx_insn *insn, rtx operands[], int *plen)
                              "mov %B0,%A0"     CR_TAB
                              "mov %A0,__tmp_reg__", operands, plen, 9);
        case 7:
-         return avr_asm_len ("lsr %B0"     CR_TAB
-                             "mov %B0,%A0" CR_TAB
-                             "clr %A0"     CR_TAB
-                             "ror %B0"     CR_TAB
-                             "ror %A0", operands, plen, 5);
+         return reg1_unused_after
+           ? avr_asm_len ("lsr %B1"     CR_TAB
+                          "mov %B0,%A1" CR_TAB
+                          "clr %A0"     CR_TAB
+                          "ror %B0"     CR_TAB
+                          "ror %A0", operands, plen, 5)
+           : avr_asm_len ("bst %B1,0"   CR_TAB
+                          "mov %B0,%A1" CR_TAB
+                          "clr %A0"     CR_TAB
+                          "ror %B0"     CR_TAB
+                          "ror %A0"     CR_TAB
+                          "bld %B0,7", operands, plen, 6);
        case 8:
          return avr_asm_len ("mov %B0,%A1" CR_TAB
                              "clr %A0", operands, plen, 2);
        case 9:
-         return avr_asm_len ("mov %B0,%A0" CR_TAB
+         return avr_asm_len ("mov %B0,%A1" CR_TAB
                              "clr %A0"     CR_TAB
                              "lsl %B0", operands, plen, 3);
        case 10:
-         return avr_asm_len ("mov %B0,%A0" CR_TAB
+         return avr_asm_len ("mov %B0,%A1" CR_TAB
                              "clr %A0"     CR_TAB
                              "lsl %B0"     CR_TAB
                              "lsl %B0", operands, plen, 4);
        case 11:
-         return avr_asm_len ("mov %B0,%A0" CR_TAB
+         return avr_asm_len ("mov %B0,%A1" CR_TAB
                              "clr %A0"     CR_TAB
                              "lsl %B0"     CR_TAB
                              "lsl %B0"     CR_TAB
                              "lsl %B0", operands, plen, 5);
        case 12:
          if (ldi_ok)
-           return avr_asm_len ("mov %B0,%A0" CR_TAB
+           return avr_asm_len ("mov %B0,%A1" CR_TAB
                                "clr %A0"     CR_TAB
                                "swap %B0"    CR_TAB
                                "andi %B0,0xf0", operands, plen, 4);
          if (scratch)
-           return avr_asm_len ("mov %B0,%A0" CR_TAB
+           return avr_asm_len ("mov %B0,%A1" CR_TAB
                                "clr %A0"     CR_TAB
                                "swap %B0"    CR_TAB
                                "ldi %3,0xf0" CR_TAB
                                "and %B0,%3", operands, plen, 5);
 
-         return avr_asm_len ("mov %B0,%A0" CR_TAB
+         return avr_asm_len ("mov %B0,%A1" CR_TAB
                              "clr %A0"     CR_TAB
                              "lsl %B0"     CR_TAB
                              "lsl %B0"     CR_TAB
@@ -7164,6 +7172,7 @@ ashrqi3_out (rtx_insn *insn, rtx operands[], int *plen)
        *plen = 0;
 
       const int offs = INTVAL (operands[2]);
+      bool reg1_unused_after = reg_unused_after (insn, operands[1]);
 
       if (IN_RANGE (offs, 0, 5))
        {
@@ -7173,10 +7182,16 @@ ashrqi3_out (rtx_insn *insn, rtx operands[], int *plen)
        }
       else if (offs == 6)
        {
-         return avr_asm_len ("bst %0,6"  CR_TAB
-                             "lsl %0"    CR_TAB
-                             "sbc %0,%0" CR_TAB
-                             "bld %0,0", operands, plen, 4);
+         return reg1_unused_after
+           ? avr_asm_len ("bst %1,6"  CR_TAB
+                          "lsl %1"    CR_TAB
+                          "sbc %0,%0" CR_TAB
+                          "bld %0,0", operands, plen, 4)
+           : avr_asm_len ("mov %0,%1" CR_TAB
+                          "bst %0,6"  CR_TAB
+                          "lsl %0"    CR_TAB
+                          "sbc %0,%0" CR_TAB
+                          "bld %0,0", operands, plen, 5);
        }
       else if (offs >= 7)
        {
@@ -7210,6 +7225,7 @@ ashrhi3_out (rtx_insn *insn, rtx operands[], int *plen)
                      && XVECLEN (PATTERN (insn), 0) == 3
                      && REG_P (operands[3]));
       bool ldi_ok = test_hard_reg_class (LD_REGS, operands[0]);
+      bool reg1_unused_after = reg_unused_after (insn, operands[1]);
 
       if (plen)
        *plen = 0;
@@ -7312,11 +7328,18 @@ ashrhi3_out (rtx_insn *insn, rtx operands[], int *plen)
                              "asr %A0"     CR_TAB
                              "asr %A0", operands, plen, 8);
        case 14:
-         return avr_asm_len ("lsl %B0"     CR_TAB
-                             "sbc %A0,%A0" CR_TAB
-                             "lsl %B0"     CR_TAB
-                             "mov %B0,%A0" CR_TAB
-                             "rol %A0", operands, plen, 5);
+         return reg1_unused_after
+           ? avr_asm_len ("bst %B1,6"   CR_TAB
+                          "lsl %B1"     CR_TAB
+                          "sbc %B0,%B0" CR_TAB
+                          "sbc %A0,%A0" CR_TAB
+                          "bld %A0,0", operands, plen, 5)
+           : avr_asm_len ("mov %B0,%B1"   CR_TAB
+                          "bst %B0,6"   CR_TAB
+                          "lsl %B0"     CR_TAB
+                          "sbc %B0,%B0" CR_TAB
+                          "sbc %A0,%A0" CR_TAB
+                          "bld %A0,0", operands, plen, 6);
        default:
          if (INTVAL (operands[2]) < 16)
            break;
@@ -7357,6 +7380,8 @@ avr_out_ashrpsi3 (rtx_insn *insn, rtx *op, int *plen)
       if (plen)
        *plen = 0;
 
+      bool reg1_unused_after = reg_unused_after (insn, op[1]);
+
       switch (INTVAL (op[2]))
        {
        case 8:
@@ -7378,6 +7403,22 @@ avr_out_ashrpsi3 (rtx_insn *insn, rtx *op, int *plen)
                              "sbrc %A0,7"  CR_TAB
                              "com %B0"     CR_TAB
                              "mov %C0,%B0", op, plen, 4);
+       case 22:
+         {
+           rtx xop[2] = { op[0], op[1] };
+           if (! reg1_unused_after)
+             {
+               avr_asm_len ("mov %C0,%C1", xop, plen, 1);
+               xop[1] = xop[0];
+             }
+           return avr_asm_len ("bst %C1,6"   CR_TAB
+                               "lsl %C1"     CR_TAB
+                               "sbc %C0,%C0" CR_TAB
+                               "sbc %B0,%B0" CR_TAB
+                               "sbc %A0,%A0" CR_TAB
+                               "bld %A0,0", xop, plen, 6);
+         }
+
        default:
          if (INTVAL (op[2]) < 24)
            break;
@@ -7387,7 +7428,7 @@ avr_out_ashrpsi3 (rtx_insn *insn, rtx *op, int *plen)
        case 23:
          {
            rtx xop[2] = { op[0], op[1] };
-           if (! reg_unused_after (insn, xop[1]))
+           if (! reg1_unused_after)
              {
                avr_asm_len ("mov %C0,%C1", xop, plen, 1);
                xop[1] = xop[0];
@@ -7419,6 +7460,7 @@ ashrsi3_out (rtx_insn *insn, rtx operands[], int *plen)
 
       int reg0 = true_regnum (operands[0]);
       int reg1 = true_regnum (operands[1]);
+      bool reg1_unused_after = reg_unused_after (insn, operands[1]);
 
       switch (INTVAL (operands[2]))
        {
@@ -7461,6 +7503,26 @@ ashrsi3_out (rtx_insn *insn, rtx operands[], int *plen)
                              "com %D0"     CR_TAB
                              "mov %B0,%D0" CR_TAB
                              "mov %C0,%D0", operands, plen, 6);
+       case 30:
+         {
+           rtx xop[2] = { operands[0], operands[1] };
+           if (! reg1_unused_after)
+             {
+               avr_asm_len ("mov %D0,%D1", xop, plen, 1);
+               xop[1] = xop[0];
+             }
+           avr_asm_len ("bst %D1,6" CR_TAB
+                        "lsl %D1" CR_TAB
+                        "sbc %A0,%A0" CR_TAB
+                        "sbc %B0,%B0", xop, plen, 4);
+           return AVR_HAVE_MOVW
+             ? avr_asm_len ("movw %C0,%A0" CR_TAB
+                            "bld %A0,0", xop, plen, 2)
+             : avr_asm_len ("mov %C0,%A0" CR_TAB
+                            "mov %D0,%A0" CR_TAB
+                            "bld %A0,0", xop, plen, 3);
+         }
+
        default:
          if (INTVAL (operands[2]) < 32)
            break;
@@ -7470,7 +7532,7 @@ ashrsi3_out (rtx_insn *insn, rtx operands[], int *plen)
        case 31:
          {
            rtx xop[2] = { operands[0], operands[1] };
-           if (! reg_unused_after (insn, xop[1]))
+           if (! reg1_unused_after)
              {
                avr_asm_len ("mov %D0,%D1", xop, plen, 1);
                xop[1] = xop[0];
@@ -7566,6 +7628,7 @@ lshrhi3_out (rtx_insn *insn, rtx operands[], int *plen)
                      && XVECLEN (PATTERN (insn), 0) == 3
                      && REG_P (operands[3]));
       bool ldi_ok = test_hard_reg_class (LD_REGS, operands[0]);
+      bool reg1_unused_after = reg_unused_after (insn, operands[1]);
 
       if (plen)
        *plen = 0;
@@ -7635,42 +7698,49 @@ lshrhi3_out (rtx_insn *insn, rtx operands[], int *plen)
                              "mov %A0,%B0"     CR_TAB
                              "mov %B0,__tmp_reg__", operands, plen, 9);
        case 7:
-         return avr_asm_len ("lsl %A0"     CR_TAB
-                             "mov %A0,%B0" CR_TAB
-                             "rol %A0"     CR_TAB
-                             "sbc %B0,%B0" CR_TAB
-                             "neg %B0", operands, plen, 5);
+         return reg1_unused_after
+           ? avr_asm_len ("lsl %A1"     CR_TAB
+                          "mov %A0,%B1" CR_TAB
+                          "rol %A0"     CR_TAB
+                          "sbc %B0,%B0" CR_TAB
+                          "neg %B0", operands, plen, 5)
+           : avr_asm_len ("bst %A1,7"   CR_TAB
+                          "mov %A0,%B1" CR_TAB
+                          "rol %A0"     CR_TAB
+                          "sbc %B0,%B0" CR_TAB
+                          "neg %B0"     CR_TAB
+                          "bld %A0,0", operands, plen, 6);
        case 8:
          return avr_asm_len ("mov %A0,%B1" CR_TAB
                              "clr %B0", operands, plen, 2);
        case 9:
-         return avr_asm_len ("mov %A0,%B0" CR_TAB
+         return avr_asm_len ("mov %A0,%B1" CR_TAB
                              "clr %B0"     CR_TAB
                              "lsr %A0", operands, plen, 3);
        case 10:
-         return avr_asm_len ("mov %A0,%B0" CR_TAB
+         return avr_asm_len ("mov %A0,%B1" CR_TAB
                              "clr %B0"     CR_TAB
                              "lsr %A0"     CR_TAB
                              "lsr %A0", operands, plen, 4);
        case 11:
-         return avr_asm_len ("mov %A0,%B0" CR_TAB
+         return avr_asm_len ("mov %A0,%B1" CR_TAB
                              "clr %B0"     CR_TAB
                              "lsr %A0"     CR_TAB
                              "lsr %A0"     CR_TAB
                              "lsr %A0", operands, plen, 5);
        case 12:
          if (ldi_ok)
-           return avr_asm_len ("mov %A0,%B0" CR_TAB
+           return avr_asm_len ("mov %A0,%B1" CR_TAB
                                "clr %B0"     CR_TAB
                                "swap %A0"    CR_TAB
                                "andi %A0,0x0f", operands, plen, 4);
          return scratch
-           ? avr_asm_len ("mov %A0,%B0" CR_TAB
+           ? avr_asm_len ("mov %A0,%B1" CR_TAB
                           "clr %B0"     CR_TAB
                           "swap %A0"    CR_TAB
                           "ldi %3,0x0f" CR_TAB
                           "and %A0,%3", operands, plen, 5)
-           : avr_asm_len ("mov %A0,%B0" CR_TAB
+           : avr_asm_len ("mov %A0,%B1" CR_TAB
                           "clr %B0"     CR_TAB
                           "lsr %A0"     CR_TAB
                           "lsr %A0"     CR_TAB
@@ -7816,6 +7886,7 @@ lshrsi3_out (rtx_insn *insn, rtx operands[], int *plen)
     {
       int reg0 = true_regnum (operands[0]);
       int reg1 = true_regnum (operands[1]);
+      bool reg1_unused_after_p = reg_unused_after (insn, operands[1]);
 
       if (plen)
        *plen = 0;
@@ -7844,6 +7915,30 @@ lshrsi3_out (rtx_insn *insn, rtx operands[], int *plen)
                           "mov %C0,%D1" CR_TAB
                           "mov %B0,%C1" CR_TAB
                           "mov %A0,%B1", operands, plen, 4);
+       case 15:
+         avr_asm_len (reg1_unused_after_p
+                      ? "lsl %B1"
+                      : "bst %B1,7", operands, plen, 1);
+         if (reg0 != reg1 + 2)
+           {
+             if (AVR_HAVE_MOVW)
+               avr_asm_len ("movw %A0,%C1", operands, plen, 1);
+             else
+               avr_asm_len ("mov %A0,%C1"  CR_TAB
+                            "mov %B0,%D1", operands, plen, 2);
+           }
+         return reg1_unused_after_p
+           ? avr_asm_len ("clr %D0"  CR_TAB
+                          "clr %C0"  CR_TAB
+                          "rol %A0"  CR_TAB
+                          "rol %B0"  CR_TAB
+                          "rol %C0", operands, plen, 5)
+           : avr_asm_len ("clr %D0"  CR_TAB
+                          "clr %C0"  CR_TAB
+                          "lsl %A0"  CR_TAB
+                          "rol %B0"  CR_TAB
+                          "rol %C0"  CR_TAB
+                          "bld %A0,0", operands, plen, 6);
        case 16:
          if (reg0 == reg1 + 2)
            return avr_asm_len ("clr %C0"  CR_TAB
@@ -12556,6 +12651,9 @@ avr_rtx_costs_1 (rtx x, machine_mode mode, int 
outer_code,
              case 8:
                *total = COSTS_N_INSNS (5);
                break;
+             case 22:
+               *total = COSTS_N_INSNS (6);
+               break;
              case 23:
                *total = COSTS_N_INSNS (4);
                break;
@@ -12589,6 +12687,9 @@ avr_rtx_costs_1 (rtx x, machine_mode mode, int 
outer_code,
              case 2:
                *total = COSTS_N_INSNS (!speed ? 7 : 8);
                break;
+             case 30:
+               *total = COSTS_N_INSNS (7 - AVR_HAVE_MOVW);
+               break;
              case 31:
                *total = COSTS_N_INSNS (AVR_HAVE_MOVW ? 4 : 5);
                break;
@@ -12723,8 +12824,13 @@ avr_rtx_costs_1 (rtx x, machine_mode mode, int 
outer_code,
              case 2:
                *total = COSTS_N_INSNS (!speed ? 7 : 8);
                break;
-             case 8:
+             case 15:
+               *total = COSTS_N_INSNS (8 - AVR_HAVE_MOVW);
+               break;
              case 16:
+               *total = COSTS_N_INSNS (4 - AVR_HAVE_MOVW);
+               break;
+             case 8:
              case 24:
                *total = COSTS_N_INSNS (4);
                break;
diff --git a/gcc/config/avr/avr.h b/gcc/config/avr/avr.h
index 2432cd615378..ac12af689380 100644
--- a/gcc/config/avr/avr.h
+++ b/gcc/config/avr/avr.h
@@ -611,10 +611,11 @@ struct GTY(()) machine_function
      __builtin_return_address.  */
   bool use_L__stack_usage;
 
-  /* Counts how many times the execute() method of the avr-fuse-add
+  /* Counts how many times the execute() method of the avr-fuse-add pass
      has been invoked.  The count is even increased when the optimization
-     itself is not run.  This purpose of this variable is to provide
-     information about where in the pass sequence we are.  */
+     itself is not run.  The purpose of this variable is to provide
+     information about where in the pass sequence we are.
+     It is used in insn / split conditons.  */
   int n_avr_fuse_add_executed;
 };
 
diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md
index 59e327fe7272..346847fa7d6e 100644
--- a/gcc/config/avr/avr.md
+++ b/gcc/config/avr/avr.md
@@ -5148,10 +5148,13 @@
   [(set_attr "length" "5,0,1,2,3,4,6,9")
    (set_attr "adjust_len" "ashlqi")])
 
+;; "ashlhi3"
+;; "ashlhq3"  "ashluhq3"
+;; "ashlha3"  "ashluha3"
 (define_insn_and_split "ashl<mode>3"
-  [(set (match_operand:ALL2 0 "register_operand"              "=r,r,r,r    
,r,r,r")
-        (ashift:ALL2 (match_operand:ALL2 1 "register_operand"  "0,0,0,r    
,0,0,0")
-                     (match_operand:QI 2 "nop_general_operand" "r,L,P,O 
C15,K,n,Qm")))]
+  [(set (match_operand:ALL2 0 "register_operand"              "=r,r  ,r        
,r,r")
+        (ashift:ALL2 (match_operand:ALL2 1 "register_operand"  "0,0  ,r        
,0,0")
+                     (match_operand:QI 2 "nop_general_operand" "r,LPK,O C7c 
C15,n,Qm")))]
   ""
   "#"
   "&& reload_completed"
@@ -5160,16 +5163,19 @@
                                 (match_dup 2)))
               (clobber (reg:CC REG_CC))])])
 
+;; "*ashlhi3"
+;; "*ashlhq3"  "*ashluhq3"
+;; "*ashlha3"  "*ashluha3"
 (define_insn "*ashl<mode>3"
-  [(set (match_operand:ALL2 0 "register_operand"              "=r,r,r,r    
,r,r,r")
-        (ashift:ALL2 (match_operand:ALL2 1 "register_operand"  "0,0,0,r    
,0,0,0")
-                     (match_operand:QI 2 "nop_general_operand" "r,L,P,O 
C15,K,n,Qm")))
+  [(set (match_operand:ALL2 0 "register_operand"              "=r,r  ,r        
,r,r")
+        (ashift:ALL2 (match_operand:ALL2 1 "register_operand"  "0,0  ,r        
,0,0")
+                     (match_operand:QI 2 "nop_general_operand" "r,LPK,O C7c 
C15,n,Qm")))
    (clobber (reg:CC REG_CC))]
   "reload_completed"
   {
     return ashlhi3_out (insn, operands, NULL);
   }
-  [(set_attr "length" "6,0,2,3,4,10,10")
+  [(set_attr "length" "10")
    (set_attr "adjust_len" "ashlhi")])
 
 
@@ -5342,69 +5348,61 @@
     operands[2] = avr_to_int_mode (operands[0]);
   })
 
-(define_peephole2
+(define_peephole2 ; *ashlhi3_const  *ashrhi3_const  *lshrhi3_const
   [(match_scratch:QI 3 "d")
-   (parallel [(set (match_operand:ALL2 0 "register_operand" "")
-                   (ashift:ALL2 (match_operand:ALL2 1 "register_operand" "")
-                                (match_operand:QI 2 "const_int_operand" "")))
-              (clobber (reg:CC REG_CC))])]
+   (parallel [(set (match_operand:ALL2 0 "register_operand")
+                   (any_shift:ALL2 (match_operand:ALL2 1 "register_operand")
+                                   (match_operand:QI 2 "const_int_operand")))
+              (clobber (reg:CC REG_CC))])
+   ;; Don't allow $3 to overlap with $0.
+   (match_dup 3)]
   ""
   [(parallel [(set (match_dup 0)
-                   (ashift:ALL2 (match_dup 1)
-                                (match_dup 2)))
+                   (any_shift:ALL2 (match_dup 1)
+                                   (match_dup 2)))
               (clobber (match_dup 3))
               (clobber (reg:CC REG_CC))])])
 
 ;; "*ashlhi3_const"
 ;; "*ashlhq3_const"  "*ashluhq3_const"
 ;; "*ashlha3_const"  "*ashluha3_const"
-(define_insn_and_split "*ashl<mode>3_const_split"
-  [(set (match_operand:ALL2 0 "register_operand"              "=r,r,r    ,r,r")
-        (ashift:ALL2 (match_operand:ALL2 1 "register_operand"  "0,0,r    ,0,0")
-                     (match_operand:QI 2 "const_int_operand"   "L,P,O 
C15,K,n")))
-   (clobber (match_scratch:QI 3                               "=X,X,X    
,X,&d"))]
-  "reload_completed"
-  "#"
-  "&& reload_completed"
-  [(parallel [(set (match_dup 0)
-                   (ashift:ALL2 (match_dup 1)
-                                (match_dup 2)))
-              (clobber (match_dup 3))
-              (clobber (reg:CC REG_CC))])])
-
 (define_insn "*ashl<mode>3_const"
-  [(set (match_operand:ALL2 0 "register_operand"              "=r,r,r    ,r,r")
-        (ashift:ALL2 (match_operand:ALL2 1 "register_operand"  "0,0,r    ,0,0")
-                     (match_operand:QI 2 "const_int_operand"   "L,P,O 
C15,K,n")))
-   (clobber (match_scratch:QI 3                               "=X,X,X    
,X,&d"))
+  [(set (match_operand:ALL2 0 "register_operand"              "=r  ,r        
,r")
+        (ashift:ALL2 (match_operand:ALL2 1 "register_operand"  "0  ,r        
,0")
+                     (match_operand:QI 2 "const_int_operand"   "LPK,O C7c 
C15,n")))
+   (clobber (match_scratch:QI 3                               "=X  ,X        
,&d"))
    (clobber (reg:CC REG_CC))]
   "reload_completed"
   {
     return ashlhi3_out (insn, operands, NULL);
   }
-  [(set_attr "length" "0,2,2,4,10")
+  [(set_attr "length" "10")
    (set_attr "adjust_len" "ashlhi")])
 
+(define_code_attr constr_split_shift4
+  [(ashift "C4l")
+   (ashiftrt "C4a")
+   (lshiftrt "C4r")])
 
 ;; Split shift into a byte shift and a residual bit shift (without scratch)
 (define_split
   [(parallel [(set (match_operand:ALL4 0 "register_operand")
-                   (ashift:ALL4 (match_operand:ALL4 1 "register_operand")
-                                (match_operand:QI 2 "const_int_operand")))
+                   (any_shift:ALL4 (match_operand:ALL4 1 "register_operand")
+                                   (match_operand:QI 2 "const_int_operand")))
               (clobber (reg:CC REG_CC))])]
   "avropt_split_bit_shift
    && n_avr_fuse_add_executed >= 1
-   && satisfies_constraint_C4l (operands[2])"
+   && satisfies_constraint_<constr_split_shift4> (operands[2])"
   [(parallel [(set (match_dup 0)
-                   (ashift:ALL4 (match_dup 1)
-                                (match_dup 3)))
+                   (any_shift:ALL4 (match_dup 1)
+                                   (match_dup 3)))
               (clobber (reg:CC REG_CC))])
    (parallel [(set (match_dup 0)
-                   (ashift:ALL4 (match_dup 0)
-                                (match_dup 4)))
+                   (any_shift:ALL4 (match_dup 0)
+                                   (match_dup 4)))
               (clobber (reg:CC REG_CC))])]
   {
-    if (avr_split_shift (operands, NULL_RTX, ASHIFT))
+    if (avr_split_shift (operands, NULL_RTX, <CODE>))
       DONE;
     else if (REGNO (operands[0]) == REGNO (operands[1]))
       FAIL;
@@ -5416,24 +5414,24 @@
 ;; Split shift into a byte shift and a residual bit shift (with scratch)
 (define_split
   [(parallel [(set (match_operand:ALL4 0 "register_operand")
-                   (ashift:ALL4 (match_operand:ALL4 1 "register_operand")
-                                (match_operand:QI 2 "const_int_operand")))
-              (clobber (match_operand:QI 3 "scratch_or_d_register_operand"))
+                   (any_shift:ALL4 (match_operand:ALL4 1 "register_operand")
+                                   (match_operand:QI 2 "const_int_operand")))
+              (clobber (match_operand:QI 3 "scratch_or_dreg_operand"))
               (clobber (reg:CC REG_CC))])]
   "avropt_split_bit_shift
    && n_avr_fuse_add_executed >= 1
-   && satisfies_constraint_C4l (operands[2])"
+   && satisfies_constraint_<constr_split_shift4> (operands[2])"
   [(parallel [(set (match_dup 0)
-                   (ashift:ALL4 (match_dup 1)
-                                (match_dup 4)))
+                   (any_shift:ALL4 (match_dup 1)
+                                   (match_dup 4)))
               (clobber (reg:CC REG_CC))])
    (parallel [(set (match_dup 0)
-                   (ashift:ALL4 (match_dup 0)
-                                (match_dup 5)))
+                   (any_shift:ALL4 (match_dup 0)
+                                   (match_dup 5)))
               (clobber (match_dup 3))
               (clobber (reg:CC REG_CC))])]
   {
-    if (avr_split_shift (operands, operands[3], ASHIFT))
+    if (avr_split_shift (operands, operands[3], <CODE>))
       DONE;
     else if (REGNO (operands[0]) == REGNO (operands[1]))
       FAIL;
@@ -5443,27 +5441,31 @@
   })
 
 
-(define_peephole2
+;; Endow 4-byte shift with a scratch if available.
+(define_peephole2 ; *ashrsi3_const  *lshrsi3_const  *ashlsi3_const
   [(match_scratch:QI 3 "d")
-   (parallel [(set (match_operand:ALL4 0 "register_operand" "")
-                   (ashift:ALL4 (match_operand:ALL4 1 "register_operand" "")
-                                (match_operand:QI 2 "const_int_operand" "")))
+   (parallel [(set (match_operand:ALL4 0 "register_operand")
+                   (any_shift:ALL4 (match_operand:ALL4 1 "register_operand")
+                                   (match_operand:QI 2 "const_int_operand")))
               (clobber (reg:CC REG_CC))])
    ;; $3 must not overlap with the output of the insn above.
    (match_dup 3)]
   ""
   [(parallel [(set (match_dup 0)
-                   (ashift:ALL4 (match_dup 1)
-                                (match_dup 2)))
+                   (any_shift:ALL4 (match_dup 1)
+                                   (match_dup 2)))
               (clobber (match_dup 3))
               (clobber (reg:CC REG_CC))])])
 
 
+;; "*ashlsi3_const"
+;; "*ashlsq3_const"  "*ashlusq3_const"
+;; "*ashlsa3_const"  "*ashlusa3_const"
 (define_insn "*ashl<mode>3_const"
-  [(set (match_operand:ALL4 0 "register_operand"                "=r ,r        
,r  ,r  ,r")
-        (ashift:ALL4 (match_operand:ALL4 1 "register_operand"    "0 ,r        
,0  ,r  ,0")
-                     (match_operand:QI 2 "const_int_operand"     "LP,O C15 
C31,C4l,C4l,n")))
-   (clobber (match_operand:QI 3 "scratch_or_d_register_operand" "=X ,X        
,&d ,&d ,&d"))
+  [(set (match_operand:ALL4 0 "register_operand"             "=r ,r        ,r  
,r  ,r")
+        (ashift:ALL4 (match_operand:ALL4 1 "register_operand" "0 ,r        ,0  
,r  ,0")
+                     (match_operand:QI 2 "const_int_operand"  "LP,O C15 
C31,C4l,C4l,n")))
+   (clobber (match_operand:QI 3 "scratch_or_dreg_operand"    "=X ,X        ,&d 
,&d ,&d"))
    (clobber (reg:CC REG_CC))]
   "reload_completed"
   {
@@ -5532,9 +5534,9 @@
 ;; "ashrqi3"
 ;; "ashrqq3"  "ashruqq3"
 (define_insn_and_split "ashr<mode>3"
-  [(set (match_operand:ALL1 0 "register_operand"                  "=r,r,r,r,r  
        ,r  ,r  ,r")
-        (ashiftrt:ALL1 (match_operand:ALL1 1 "register_operand"    "0,0,0,0,0  
        ,0  ,r  ,0")
-                       (match_operand:QI 2 "nop_general_operand"   
"r,L,P,K,C03 C04 C05,C06,C07,Qm")))]
+  [(set (match_operand:ALL1 0 "register_operand"                  "=r,r        
      ,r      ,r")
+        (ashiftrt:ALL1 (match_operand:ALL1 1 "register_operand"    "0,0        
      ,r      ,0")
+                       (match_operand:QI 2 "nop_general_operand"   "r,LPK C03 
C04 C05,C06 C07,Qm")))]
   ""
   "#"
   "&& reload_completed"
@@ -5544,24 +5546,24 @@
               (clobber (reg:CC REG_CC))])])
 
 (define_insn "*ashr<mode>3"
-  [(set (match_operand:ALL1 0 "register_operand"                  "=r,r,r,r,r  
        ,r  ,r  ,r")
-        (ashiftrt:ALL1 (match_operand:ALL1 1 "register_operand"    "0,0,0,0,0  
        ,0  ,r  ,0")
-                       (match_operand:QI 2 "nop_general_operand"   
"r,L,P,K,C03 C04 C05,C06,C07,Qm")))
+  [(set (match_operand:ALL1 0 "register_operand"                  "=r,r        
      ,r      ,r")
+        (ashiftrt:ALL1 (match_operand:ALL1 1 "register_operand"    "0,0        
      ,r      ,0")
+                       (match_operand:QI 2 "nop_general_operand"   "r,LPK C03 
C04 C05,C06 C07,Qm")))
    (clobber (reg:CC REG_CC))]
   "reload_completed"
   {
     return ashrqi3_out (insn, operands, NULL);
   }
-  [(set_attr "length" "5,0,1,2,5,4,3,9")
+  [(set_attr "length" "9")
    (set_attr "adjust_len" "ashrqi")])
 
 ;; "ashrhi3"
 ;; "ashrhq3"  "ashruhq3"
 ;; "ashrha3"  "ashruha3"
 (define_insn_and_split "ashr<mode>3"
-  [(set (match_operand:ALL2 0 "register_operand"                "=r,r,r,r    
,r,r,r")
-        (ashiftrt:ALL2 (match_operand:ALL2 1 "register_operand"  "0,0,0,r    
,0,0,0")
-                       (match_operand:QI 2 "nop_general_operand" "r,L,P,O 
C15,K,n,Qm")))]
+  [(set (match_operand:ALL2 0 "register_operand"                "=r,r  ,r      
  ,r,r")
+        (ashiftrt:ALL2 (match_operand:ALL2 1 "register_operand"  "0,0  ,r      
  ,0,0")
+                       (match_operand:QI 2 "nop_general_operand" "r,LPK,O C14 
C15,n,Qm")))]
   ""
   "#"
   "&& reload_completed"
@@ -5570,23 +5572,26 @@
                                   (match_dup 2)))
               (clobber (reg:CC REG_CC))])])
 
+;; "*ashrhi3"
+;; "*ashrhq3"  "*ashruhq3"
+;; "*ashrha3"  "*ashruha3"
 (define_insn "*ashr<mode>3"
-  [(set (match_operand:ALL2 0 "register_operand"                "=r,r,r,r    
,r,r,r")
-        (ashiftrt:ALL2 (match_operand:ALL2 1 "register_operand"  "0,0,0,r    
,0,0,0")
-                       (match_operand:QI 2 "nop_general_operand" "r,L,P,O 
C15,K,n,Qm")))
+  [(set (match_operand:ALL2 0 "register_operand"                "=r,r  ,r      
  ,r,r")
+        (ashiftrt:ALL2 (match_operand:ALL2 1 "register_operand"  "0,0  ,r      
  ,0,0")
+                       (match_operand:QI 2 "nop_general_operand" "r,LPK,O C14 
C15,n,Qm")))
    (clobber (reg:CC REG_CC))]
   "reload_completed"
   {
     return ashrhi3_out (insn, operands, NULL);
   }
-  [(set_attr "length" "6,0,2,5,4,10,10")
+  [(set_attr "length" "10")
    (set_attr "adjust_len" "ashrhi")])
 
 (define_insn_and_split "ashrpsi3"
-  [(set (match_operand:PSI 0 "register_operand"                 "=r,r,r,r    
,r")
-        (ashiftrt:PSI (match_operand:PSI 1 "register_operand"    "0,0,0,r    
,0")
-                      (match_operand:QI 2 "nonmemory_operand"    "r,P,K,O 
C23,n")))
-   (clobber (match_scratch:QI 3                                 "=X,X,X,X    
,&d"))]
+  [(set (match_operand:PSI 0 "register_operand"                 "=r,r ,r       
 ,r")
+        (ashiftrt:PSI (match_operand:PSI 1 "register_operand"    "0,0 ,r       
 ,0")
+                      (match_operand:QI 2 "nonmemory_operand"    "r,PK,O C22 
C23,n")))
+   (clobber (match_scratch:QI 3                                 "=X,X ,X       
 ,&d"))]
   ""
   "#"
   "&& reload_completed"
@@ -5597,10 +5602,10 @@
               (clobber (reg:CC REG_CC))])])
 
 (define_insn "*ashrpsi3"
-  [(set (match_operand:PSI 0 "register_operand"                 "=r,r,r,r    
,r")
-        (ashiftrt:PSI (match_operand:PSI 1 "register_operand"    "0,0,0,r    
,0")
-                      (match_operand:QI 2 "nonmemory_operand"    "r,P,K,O 
C23,n")))
-   (clobber (match_scratch:QI 3                                 "=X,X,X,X    
,&d"))
+  [(set (match_operand:PSI 0 "register_operand"                 "=r,r ,r       
 ,r")
+        (ashiftrt:PSI (match_operand:PSI 1 "register_operand"    "0,0 ,r       
 ,0")
+                      (match_operand:QI 2 "nonmemory_operand"    "r,PK,O C22 
C23,n")))
+   (clobber (match_scratch:QI 3                                 "=X,X ,X       
 ,&d"))
    (clobber (reg:CC REG_CC))]
   "reload_completed"
   {
@@ -5612,115 +5617,65 @@
 ;; "ashrsq3"  "ashrusq3"
 ;; "ashrsa3"  "ashrusa3"
 (define_insn_and_split "ashr<mode>3"
-  [(set (match_operand:ALL4 0 "register_operand"                  "=r,r,r,r    
,r,r,r")
-        (ashiftrt:ALL4 (match_operand:ALL4 1 "register_operand"    "0,0,0,r    
,0,0,0")
-                       (match_operand:QI 2 "nop_general_operand"   "r,L,P,O 
C31,K,n,Qm")))]
+  [(set (match_operand:ALL4 0 "register_operand"                  "=r,r  ,r    
    ,r  ,r  ,r,r")
+        (ashiftrt:ALL4 (match_operand:ALL4 1 "register_operand"    "0,0  ,r    
    ,0  ,r  ,0,0")
+                       (match_operand:QI 2 "nop_general_operand"   "r,LPK,O 
C30 C31,C4a,C4a,n,Qm")))]
   ""
   "#"
   "&& reload_completed"
   [(parallel [(set (match_dup 0)
                    (ashiftrt:ALL4 (match_dup 1)
                                   (match_dup 2)))
-              (clobber (reg:CC REG_CC))])])
+              (clobber (reg:CC REG_CC))])]
+  ""
+  [(set_attr "isa" "*,*,*,2op,3op,*,*")])
 
 (define_insn "*ashr<mode>3"
-  [(set (match_operand:ALL4 0 "register_operand"                  "=r,r,r,r    
,r,r,r")
-        (ashiftrt:ALL4 (match_operand:ALL4 1 "register_operand"    "0,0,0,r    
,0,0,0")
-                       (match_operand:QI 2 "nop_general_operand"   "r,L,P,O 
C31,K,n,Qm")))
+  [(set (match_operand:ALL4 0 "register_operand"                  "=r,r  ,r    
    ,r  ,r  ,r,r")
+        (ashiftrt:ALL4 (match_operand:ALL4 1 "register_operand"    "0,0  ,r    
    ,0  ,r  ,0,0")
+                       (match_operand:QI 2 "nop_general_operand"   "r,LPK,O 
C30 C31,C4a,C4a,n,Qm")))
    (clobber (reg:CC REG_CC))]
   "reload_completed"
   {
     return ashrsi3_out (insn, operands, NULL);
   }
-  [(set_attr "length" "8,0,4,6,8,10,12")
+  [(set_attr "isa" "*,*,*,2op,3op,*,*")
+   (set_attr "length" "12")
    (set_attr "adjust_len" "ashrsi")])
 
-;; Optimize if a scratch register from LD_REGS happens to be available.
-
-(define_peephole2
-  [(match_scratch:QI 3 "d")
-   (parallel [(set (match_operand:ALL2 0 "register_operand" "")
-                   (ashiftrt:ALL2 (match_operand:ALL2 1 "register_operand" "")
-                                  (match_operand:QI 2 "const_int_operand" "")))
-              (clobber (reg:CC REG_CC))])]
-  ""
-  [(parallel [(set (match_dup 0)
-                   (ashiftrt:ALL2 (match_dup 1)
-                                  (match_dup 2)))
-              (clobber (match_dup 3))
-              (clobber (reg:CC REG_CC))])])
 
 ;; "*ashrhi3_const"
 ;; "*ashrhq3_const"  "*ashruhq3_const"
 ;; "*ashrha3_const"  "*ashruha3_const"
-(define_insn_and_split "*ashr<mode>3_const_split"
-  [(set (match_operand:ALL2 0 "register_operand"                "=r,r,r    
,r,r")
-        (ashiftrt:ALL2 (match_operand:ALL2 1 "register_operand"  "0,0,r    
,0,0")
-                       (match_operand:QI 2 "const_int_operand"   "L,P,O 
C15,K,n")))
-   (clobber (match_scratch:QI 3                                 "=X,X,X    
,X,&d"))]
-  "reload_completed"
-  "#"
-  "&& reload_completed"
-  [(parallel [(set (match_dup 0)
-                   (ashiftrt:ALL2 (match_dup 1)
-                                  (match_dup 2)))
-              (clobber (match_dup 3))
-              (clobber (reg:CC REG_CC))])])
-
 (define_insn "*ashr<mode>3_const"
-  [(set (match_operand:ALL2 0 "register_operand"                "=r,r,r    
,r,r")
-        (ashiftrt:ALL2 (match_operand:ALL2 1 "register_operand"  "0,0,r    
,0,0")
-                       (match_operand:QI 2 "const_int_operand"   "L,P,O 
C15,K,n")))
-   (clobber (match_scratch:QI 3                                 "=X,X,X    
,X,&d"))
+  [(set (match_operand:ALL2 0 "register_operand"                "=r  ,r        
,r")
+        (ashiftrt:ALL2 (match_operand:ALL2 1 "register_operand"  "0  ,r        
,0")
+                       (match_operand:QI 2 "const_int_operand"   "LPK,O C14 
C15,n")))
+   (clobber (match_scratch:QI 3                                 "=X  ,X        
,&d"))
    (clobber (reg:CC REG_CC))]
   "reload_completed"
   {
     return ashrhi3_out (insn, operands, NULL);
   }
-  [(set_attr "length" "0,2,4,4,10")
+  [(set_attr "length" "10")
    (set_attr "adjust_len" "ashrhi")])
 
-(define_peephole2
-  [(match_scratch:QI 3 "d")
-   (parallel [(set (match_operand:ALL4 0 "register_operand" "")
-                   (ashiftrt:ALL4 (match_operand:ALL4 1 "register_operand" "")
-                                  (match_operand:QI 2 "const_int_operand" "")))
-              (clobber (reg:CC REG_CC))])]
-  ""
-  [(parallel [(set (match_dup 0)
-                   (ashiftrt:ALL4 (match_dup 1)
-                                  (match_dup 2)))
-              (clobber (match_dup 3))
-              (clobber (reg:CC REG_CC))])])
 
 ;; "*ashrsi3_const"
 ;; "*ashrsq3_const"  "*ashrusq3_const"
 ;; "*ashrsa3_const"  "*ashrusa3_const"
-(define_insn_and_split "*ashr<mode>3_const_split"
-  [(set (match_operand:ALL4 0 "register_operand"                "=r,r,r    ,r")
-        (ashiftrt:ALL4 (match_operand:ALL4 1 "register_operand"  "0,0,r    ,0")
-                       (match_operand:QI 2 "const_int_operand"   "L,P,O 
C31,n")))
-   (clobber (match_scratch:QI 3                                 "=X,X,X    
,&d"))]
-  "reload_completed"
-  "#"
-  "&& reload_completed"
-  [(parallel [(set (match_dup 0)
-                   (ashiftrt:ALL4 (match_dup 1)
-                                  (match_dup 2)))
-              (clobber (match_dup 3))
-              (clobber (reg:CC REG_CC))])])
-
 (define_insn "*ashr<mode>3_const"
-  [(set (match_operand:ALL4 0 "register_operand"                "=r,r,r    ,r")
-        (ashiftrt:ALL4 (match_operand:ALL4 1 "register_operand"  "0,0,r    ,0")
-                       (match_operand:QI 2 "const_int_operand"   "L,P,O 
C31,n")))
-   (clobber (match_scratch:QI 3                                 "=X,X,X    
,&d"))
+  [(set (match_operand:ALL4 0 "register_operand"                "=r ,r        
,r  ,r  ,r")
+        (ashiftrt:ALL4 (match_operand:ALL4 1 "register_operand"  "0 ,r        
,0  ,r  ,0")
+                       (match_operand:QI 2 "const_int_operand"   "LP,O C30 
C31,C4a,C4a,n")))
+   (clobber (match_operand:QI 3 "scratch_or_dreg_operand"       "=X ,X        
,&d ,&d ,&d"))
    (clobber (reg:CC REG_CC))]
   "reload_completed"
   {
     return ashrsi3_out (insn, operands, NULL);
   }
-  [(set_attr "length" "0,4,4,10")
+  [(set_attr "isa" "*,*,2op,3op,*")
+   (set_attr "length" "10")
    (set_attr "adjust_len" "ashrsi")])
 
 ;; >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >>
@@ -5802,9 +5757,9 @@
 ;; "lshrhq3"  "lshruhq3"
 ;; "lshrha3"  "lshruha3"
 (define_insn_and_split "lshr<mode>3"
-  [(set (match_operand:ALL2 0 "register_operand"                "=r,r,r,r,r  
,r,r,r")
-        (lshiftrt:ALL2 (match_operand:ALL2 1 "register_operand"  "0,0,0,r,r  
,0,0,0")
-                       (match_operand:QI 2 "nop_general_operand" 
"r,L,P,O,C15,K,n,Qm")))]
+  [(set (match_operand:ALL2 0 "register_operand"                "=r,r  ,r      
    ,r,r")
+        (lshiftrt:ALL2 (match_operand:ALL2 1 "register_operand"  "0,0  ,r      
    ,0,0")
+                       (match_operand:QI 2 "nop_general_operand" "r,LPK,O C7c 
C15,n,Qm")))]
   ""
   "#"
   "&& reload_completed"
@@ -5814,9 +5769,9 @@
               (clobber (reg:CC REG_CC))])])
 
 (define_insn "*lshr<mode>3"
-  [(set (match_operand:ALL2 0 "register_operand"                "=r,r,r,r,r  
,r,r,r")
-        (lshiftrt:ALL2 (match_operand:ALL2 1 "register_operand"  "0,0,0,r,r  
,0,0,0")
-                       (match_operand:QI 2 "nop_general_operand" 
"r,L,P,O,C15,K,n,Qm")))
+  [(set (match_operand:ALL2 0 "register_operand"                "=r,r  ,r      
  ,r,r")
+        (lshiftrt:ALL2 (match_operand:ALL2 1 "register_operand"  "0,0  ,r      
  ,0,0")
+                       (match_operand:QI 2 "nop_general_operand" "r,LPK,O C7c 
C15,n,Qm")))
    (clobber (reg:CC REG_CC))]
   "reload_completed"
   {
@@ -5854,27 +5809,30 @@
 ;; "lshrsq3"  "lshrusq3"
 ;; "lshrsa3"  "lshrusa3"
 (define_insn_and_split "lshr<mode>3"
-  [(set (match_operand:ALL4 0 "register_operand"                  
"=r,r,r,r,r,r  ,r,r")
-        (lshiftrt:ALL4 (match_operand:ALL4 1 "register_operand"    
"0,0,0,r,0,r  ,0,0")
-                       (match_operand:QI 2 "nop_general_operand"   
"r,L,P,O,K,C31,n,Qm")))]
+  [(set (match_operand:ALL4 0 "register_operand"                  "=r,r  ,r    
    ,r  ,r  ,r,r")
+        (lshiftrt:ALL4 (match_operand:ALL4 1 "register_operand"    "0,0  ,r    
    ,0  ,r  ,0,0")
+                       (match_operand:QI 2 "nop_general_operand"   "r,LPK,O 
C15 C31,C4r,C4r,n,Qm")))]
   ""
   "#"
   "&& reload_completed"
   [(parallel [(set (match_dup 0)
                    (lshiftrt:ALL4 (match_dup 1)
                                   (match_dup 2)))
-              (clobber (reg:CC REG_CC))])])
+              (clobber (reg:CC REG_CC))])]
+  ""
+  [(set_attr "isa" "*,*,*,2op,3op,*,*")])
 
 (define_insn "*lshr<mode>3"
-  [(set (match_operand:ALL4 0 "register_operand"                  
"=r,r,r,r,r,r  ,r,r")
-        (lshiftrt:ALL4 (match_operand:ALL4 1 "register_operand"    
"0,0,0,r,0,r  ,0,0")
-                       (match_operand:QI 2 "nop_general_operand"   
"r,L,P,O,K,C31,n,Qm")))
+  [(set (match_operand:ALL4 0 "register_operand"                  "=r,r  ,r    
    ,r  ,r  ,r,r")
+        (lshiftrt:ALL4 (match_operand:ALL4 1 "register_operand"    "0,0  ,r    
    ,0  ,r  ,0,0")
+                       (match_operand:QI 2 "nop_general_operand"   "r,LPK,O 
C15 C31,C4r,C4r,n,Qm")))
    (clobber (reg:CC REG_CC))]
   "reload_completed"
   {
     return lshrsi3_out (insn, operands, NULL);
   }
-  [(set_attr "adjust_len" "lshrsi")])
+  [(set_attr "isa" "*,*,*,2op,3op,*,*")
+   (set_attr "adjust_len" "lshrsi")])
 
 ;; Optimize if a scratch register from LD_REGS happens to be available.
 
@@ -5933,41 +5891,15 @@
     operands[2] = avr_to_int_mode (operands[0]);
   })
 
-(define_peephole2 ; "*lshrhi3_const"
-  [(match_scratch:QI 3 "d")
-   (parallel [(set (match_operand:ALL2 0 "register_operand" "")
-                   (lshiftrt:ALL2 (match_operand:ALL2 1 "register_operand" "")
-                                  (match_operand:QI 2 "const_int_operand" "")))
-              (clobber (reg:CC REG_CC))])]
-  ""
-  [(parallel [(set (match_dup 0)
-                   (lshiftrt:ALL2 (match_dup 1)
-                                  (match_dup 2)))
-              (clobber (match_dup 3))
-              (clobber (reg:CC REG_CC))])])
 
 ;; "*lshrhi3_const"
 ;; "*lshrhq3_const"  "*lshruhq3_const"
 ;; "*lshrha3_const"  "*lshruha3_const"
-(define_insn_and_split "*lshr<mode>3_const_split"
-  [(set (match_operand:ALL2 0 "register_operand"                "=r,r,r,r  
,r,r")
-        (lshiftrt:ALL2 (match_operand:ALL2 1 "register_operand"  "0,0,r,r  
,0,0")
-                       (match_operand:QI 2 "const_int_operand"   
"L,P,O,C15,K,n")))
-   (clobber (match_scratch:QI 3                                 "=X,X,X,X  
,X,&d"))]
-  "reload_completed"
-  "#"
-  "&& reload_completed"
-  [(parallel [(set (match_dup 0)
-                   (lshiftrt:ALL2 (match_dup 1)
-                                  (match_dup 2)))
-              (clobber (match_dup 3))
-              (clobber (reg:CC REG_CC))])])
-
 (define_insn "*lshr<mode>3_const"
-  [(set (match_operand:ALL2 0 "register_operand"                "=r,r,r,r  
,r,r")
-        (lshiftrt:ALL2 (match_operand:ALL2 1 "register_operand"  "0,0,r,r  
,0,0")
-                       (match_operand:QI 2 "const_int_operand"   
"L,P,O,C15,K,n")))
-   (clobber (match_scratch:QI 3                                 "=X,X,X,X  
,X,&d"))
+  [(set (match_operand:ALL2 0 "register_operand"                "=r  ,r        
,r")
+        (lshiftrt:ALL2 (match_operand:ALL2 1 "register_operand"  "0  ,r        
,0")
+                       (match_operand:QI 2 "const_int_operand"   "LPK,O C7c 
C15,n")))
+   (clobber (match_scratch:QI 3                                 "=X  ,X        
,&d"))
    (clobber (reg:CC REG_CC))]
   "reload_completed"
   {
@@ -5975,47 +5907,22 @@
   }
   [(set_attr "adjust_len" "lshrhi")])
 
-(define_peephole2 ; "*lshrsi3_const"
-  [(match_scratch:QI 3 "d")
-   (parallel [(set (match_operand:ALL4 0 "register_operand" "")
-                   (lshiftrt:ALL4 (match_operand:ALL4 1 "register_operand" "")
-                                  (match_operand:QI 2 "const_int_operand" "")))
-              (clobber (reg:CC REG_CC))])]
-  ""
-  [(parallel [(set (match_dup 0)
-                   (lshiftrt:ALL4 (match_dup 1)
-                                  (match_dup 2)))
-              (clobber (match_dup 3))
-              (clobber (reg:CC REG_CC))])])
 
 ;; "*lshrsi3_const"
 ;; "*lshrsq3_const"  "*lshrusq3_const"
 ;; "*lshrsa3_const"  "*lshrusa3_const"
-(define_insn_and_split "*lshr<mode>3_const_split"
-  [(set (match_operand:ALL4 0 "register_operand"               "=r,r,r,r  ,r")
-        (lshiftrt:ALL4 (match_operand:ALL4 1 "register_operand" "0,0,r,r  ,0")
-                       (match_operand:QI 2 "const_int_operand"  
"L,P,O,C31,n")))
-   (clobber (match_scratch:QI 3                                "=X,X,X,X  
,&d"))]
-  "reload_completed"
-  "#"
-  "&& reload_completed"
-  [(parallel [(set (match_dup 0)
-                   (lshiftrt:ALL4 (match_dup 1)
-                                  (match_dup 2)))
-              (clobber (match_dup 3))
-              (clobber (reg:CC REG_CC))])])
-
 (define_insn "*lshr<mode>3_const"
-  [(set (match_operand:ALL4 0 "register_operand"               "=r,r,r,r  ,r")
-        (lshiftrt:ALL4 (match_operand:ALL4 1 "register_operand" "0,0,r,r  ,0")
-                       (match_operand:QI 2 "const_int_operand"  
"L,P,O,C31,n")))
-   (clobber (match_scratch:QI 3                                "=X,X,X,X  
,&d"))
+  [(set (match_operand:ALL4 0 "register_operand"               "=r ,r        
,r  ,r  ,r")
+        (lshiftrt:ALL4 (match_operand:ALL4 1 "register_operand" "0 ,r        
,0  ,r  ,0")
+                       (match_operand:QI 2 "const_int_operand"  "LP,O C15 
C31,C4r,C4r,n")))
+   (clobber (match_operand:QI 3 "scratch_or_dreg_operand"      "=X ,X        
,&d ,&d ,&d"))
    (clobber (reg:CC REG_CC))]
   "reload_completed"
   {
     return lshrsi3_out (insn, operands, NULL);
   }
-  [(set_attr "adjust_len" "lshrsi")])
+  [(set_attr "isa" "*,*,2op,3op,*")
+   (set_attr "adjust_len" "lshrsi")])
 
 ;; abs(x) abs(x) abs(x) abs(x) abs(x) abs(x) abs(x) abs(x) abs(x) abs(x) abs(x)
 ;; abs
@@ -7099,7 +7006,7 @@
   [(parallel [(set (match_operand:HISI 0 "register_operand")
                    (plus:HISI (match_dup 0)
                               (match_operand:HISI 1 "nonmemory_operand")))
-              (clobber (match_operand:QI 3 "scratch_or_d_register_operand"))
+              (clobber (match_operand:QI 3 "scratch_or_dreg_operand"))
               (clobber (reg:CC REG_CC))])
    (parallel [(set (reg:CC REG_CC)
                    (compare:CC (match_dup 0)
@@ -8167,7 +8074,7 @@
    (parallel [(set (reg:CC REG_CC)
                    (compare:CC (match_dup 0)
                                (const_int -1)))
-              (clobber (match_operand:QI 1 "scratch_or_d_register_operand"))])
+              (clobber (match_operand:QI 1 "scratch_or_dreg_operand"))])
    (set (pc)
         (if_then_else (eqne (reg:CC REG_CC)
                             (const_int 0))
@@ -8247,7 +8154,7 @@
    (parallel [(set (reg:CC REG_CC)
                    (compare:CC (match_dup 0)
                                (const_int -1)))
-              (clobber (match_operand:QI 1 "scratch_or_d_register_operand"))])
+              (clobber (match_operand:QI 1 "scratch_or_dreg_operand"))])
    (set (pc)
         (if_then_else (eqne (reg:CC REG_CC)
                             (const_int 0))
diff --git a/gcc/config/avr/constraints.md b/gcc/config/avr/constraints.md
index a362f31e30b8..22bb4575089f 100644
--- a/gcc/config/avr/constraints.md
+++ b/gcc/config/avr/constraints.md
@@ -133,16 +133,36 @@
   (and (match_code "const_int")
        (match_test "ival == 7")))
 
+(define_constraint "C7c"
+  "Constant integer the range 7 @dots{} 12."
+  (and (match_code "const_int")
+       (match_test "IN_RANGE (ival, 7, 12)")))
+
+(define_constraint "C14"
+  "Constant integer 14."
+  (and (match_code "const_int")
+       (match_test "ival == 14")))
+
 (define_constraint "C15"
   "Constant integer 15."
   (and (match_code "const_int")
        (match_test "ival == 15")))
 
+(define_constraint "C22"
+  "Constant integer 22."
+  (and (match_code "const_int")
+       (match_test "ival == 22")))
+
 (define_constraint "C23"
   "Constant integer 23."
   (and (match_code "const_int")
        (match_test "ival == 23")))
 
+(define_constraint "C30"
+  "Constant integer 30."
+  (and (match_code "const_int")
+       (match_test "ival == 30")))
+
 (define_constraint "C31"
   "Constant integer 31."
   (and (match_code "const_int")
diff --git a/gcc/config/avr/predicates.md b/gcc/config/avr/predicates.md
index d852f1c9e084..a28c63a6478f 100644
--- a/gcc/config/avr/predicates.md
+++ b/gcc/config/avr/predicates.md
@@ -27,7 +27,7 @@
   (and (match_code "reg")
        (match_test "REGNO (op) >= 16 && REGNO (op) <= 31")))
 
-(define_predicate "scratch_or_d_register_operand"
+(define_predicate "scratch_or_dreg_operand"
   (ior (match_operand 0 "d_register_operand")
        (and (match_code ("scratch"))
             (match_operand 0 "scratch_operand"))))
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index a8662efb5cb2..44f0fd297b29 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -905,7 +905,7 @@ Objective-C and Objective-C++ Dialects}.
 -mdouble=@var{bits}  -mlong-double=@var{bits}
 -mn_flash=@var{size}  -mno-interrupts
 -mmain-is-OS_task  -mrelax  -mrmw  -mstrict-X  -mtiny-stack
--mrodata-in-ram  -mfract-convert-truncate
+-mrodata-in-ram  -mfract-convert-truncate  -msplit-bit-shift
 -mshort-calls  -mskip-bug  -nodevicelib  -nodevicespecs
 -Waddr-space-convert  -Wmisspelled-isr}
 
@@ -24252,6 +24252,15 @@ ld   @var{Rn}, X        ; @var{Rn} = *X
 sbiw r26, const   ; X -= const
 @end example
 
+@opindex msplit-bit-shift
+@item -msplit-bit-shift
+Split multi-byte shifts into a shift with a byte offset and a residual
+shift with a non-byte offset.  This optimization is turned on per default
+for @option{-O2} and higher, including @option{-Os} but excluding
+@option{-Oz}.  To date, only 4-byte shifts with a shift offset of
+at least 17 are split.  Splitting of shifts with an offset that is
+a multiple of 8 is controlled by @option{-mfuse-move}.
+
 @opindex mtiny-stack
 @item -mtiny-stack
 Only change the lower 8@tie{}bits of the stack pointer.

Reply via email to