This patch is similar to https://gcc.gnu.org/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.


No regressions. Ok for trunk?

Johann

--

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.
        * 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.
        * config/avr/constraints.md (C7c): New constraint in 7...12.
        * config/avr/avr.cc (ashlhi3_out, lshrhi3_out)
        [case 7, 9, 10, 11, 12]: Support as 3-operand insn.
        (lshrsi3_out) [case 15]: Support as 3-operand insn.
        * doc/invoke.texi (AVR Options) <-msplit-bit-shift>: Document.
    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.
            * 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.
            * config/avr/constraints.md (C7c): New constraint in 7...12.
            * config/avr/avr.cc (ashlhi3_out, lshrhi3_out)
            [case 7, 9, 10, 11, 12]: Support as 3-operand insn.
            (lshrsi3_out) [case 15]: Support as 3-operand insn.
            * doc/invoke.texi (AVR Options) <-msplit-bit-shift>: Document.

diff --git a/gcc/config/avr/avr-passes.cc b/gcc/config/avr/avr-passes.cc
index 57c3fed1e41..3eedee5d206 100644
--- a/gcc/config/avr/avr-passes.cc
+++ b/gcc/config/avr/avr-passes.cc
@@ -4840,22 +4840,38 @@ 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, 30)
+      : code == LSHIFTRT ? IN_RANGE (offset, 9, 30) && offset != 15
+      : bad_case<bool> ();
+
+  return false;
 }
 
 
+/* Emit a DEST = SRC <code> OFF shift of QImode or HImode.
+   SCRATCH is a QImode d-register 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);
+  bool is_3op = off % 8 == 0;
+  is_3op |= mode == QImode && off == 7;
+  is_3op |= mode == HImode && off == 15;
+  is_3op |= (mode == HImode
+	     && (code == ASHIFT || code == LSHIFTRT)
+	     && IN_RANGE (off, 7, 12)); // "r,r,C7c"
   rtx shift;
 
-  if (off == GET_MODE_BITSIZE (mode) - 1)
+  if (is_3op)
     {
       shift = gen_rtx_fmt_ee (code, mode, src, GEN_INT (off));
     }
@@ -4870,7 +4886,7 @@ avr_emit_shift (rtx_code code, rtx dest, rtx src, int off, rtx 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 +4903,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 cc13dae9bfe..d9aa3d03f18 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
@@ -7566,6 +7574,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 +7644,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 +7832,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 +7861,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
@@ -12723,8 +12764,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.md b/gcc/config/avr/avr.md
index 59e327fe727..55648c460f7 100644
--- a/gcc/config/avr/avr.md
+++ b/gcc/config/avr/avr.md
@@ -5148,10 +5148,13 @@ (define_insn "*ashl<mode>3"
   [(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 @@ (define_insn_and_split "ashl<mode>3"
                                 (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 @@ (define_peephole2 ; ashlqi3_l_const6
     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 @@ (define_split
 ;; 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_split
   })
 
 
-(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"
   {
@@ -5612,61 +5614,36 @@ (define_insn "*ashrpsi3"
 ;; "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 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 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")
@@ -5680,47 +5657,22 @@ (define_insn "*ashr<mode>3_const"
   [(set_attr "length" "0,2,4,4,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 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 +5754,9 @@ (define_insn "*lshr<mode>3"
 ;; "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 +5766,9 @@ (define_insn_and_split "lshr<mode>3"
               (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 +5806,30 @@ (define_insn "*lshrpsi3"
 ;; "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 +5888,15 @@ (define_peephole2 ; lshrqi3_l_const6
     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 +5904,22 @@ (define_insn "*lshr<mode>3_const"
   }
   [(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 +7003,7 @@ (define_peephole2
   [(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 +8071,7 @@ (define_peephole ; "*dec-and-branchsi!=-1.d.clobber"
    (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 +8151,7 @@ (define_peephole ; "*dec-and-branchhi!=-1.d.clobber"
    (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 a362f31e30b..3562aff6c71 100644
--- a/gcc/config/avr/constraints.md
+++ b/gcc/config/avr/constraints.md
@@ -133,6 +133,11 @@ (define_constraint "C07"
   (and (match_code "const_int")
        (match_test "ival == 7")))
 
+(define_constraint "C7c"
+  "Constant integer int the range 7 @dots{} 12."
+  (and (match_code "const_int")
+       (match_test "IN_RANGE (ival, 7, 12)")))
+
 (define_constraint "C15"
   "Constant integer 15."
   (and (match_code "const_int")
diff --git a/gcc/config/avr/predicates.md b/gcc/config/avr/predicates.md
index d852f1c9e08..a28c63a6478 100644
--- a/gcc/config/avr/predicates.md
+++ b/gcc/config/avr/predicates.md
@@ -27,7 +27,7 @@ (define_predicate "d_register_operand"
   (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 c62c6bc5903..91126387694 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -903,7 +903,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}
 
@@ -24221,6 +24221,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