This patch adds 3-operand alternatives to the shift insns for
offsets that are one less than the bit-size of the mode.
For example, ashrhi3 can support "r,r,C15" without overhead.
Apart from that, the asm out functions for the shifts now use
avr_asm_len to print assembly and to track the isnsns' lengths.

It adds new tests and passes without regression.

Ok for trunk?

Johann

--

gcc/
        * config/avr/avr.md (ashlhi3, *ashlhi3_const_split, *ashlhi3_const)
        (*ashlpsi3_split, *ashlpsi3)
        (ashlsi3, *ashlsi3_const_split, *ashlsi3_const)
        (ashrhi3, *ashrhi3, ashrpsi3, *ashrpsi3, ashrsi3, *ashrsi3)
(*ashrhi3_const_split, *ashrhi3_const, *ashrsi3_const_split, *ashrsi3_const):
        Add constraint alternatives that allow a 3-operand operation when the
        shift offset is one less than the mode's bitsize.
        * config/avr/avr.cc (ashl<mode>3_out, ashr<mode>3_out)
        (lshr<mode>3_out): Use avr_asm_len for asm_out and length tracking.
        (ashrhi3_out, ashlhi3_out): Support the new "r,r,C15" alternatives.
        (ashrsi3_out, ashlsi3_out): Support the new "r,r,C31" alternatives.
(avr_out_ashrpsi3, avr_out_ashlpsi3): Support the new "r,r,C23" alternatives.
gcc/testsuite/
        * gcc.target/avr/torture/test-shift.h: New file.
        * gcc.target/avr/torture/shift-l-u32.c: New test.
        * gcc.target/avr/torture/shift-r-u32.c: New test.
        * gcc.target/avr/torture/shift-r-i32.c: New test.
        * gcc.target/avr/torture/shift-l-u24.c: New test.
        * gcc.target/avr/torture/shift-r-u16.c: New test.
        * gcc.target/avr/torture/shift-r-i24.c: New test.
        * gcc.target/avr/torture/shift-l-u16.c: New test.
        * gcc.target/avr/torture/shift-r-u16.c: New test.
        * gcc.target/avr/torture/shift-r-i16.c: New test.
        * gcc.target/avr/torture/shift-l-u8.c: New test.
        * gcc.target/avr/torture/shift-r-u8.c: New test.
        * gcc.target/avr/torture/shift-r-i8.c: New test.
    AVR: Overhaul shift insns.
    
    This patch adds 3-operand alternatives to the shift insns for
    offsets that are one less than the bit-size of the mode.
    For example, ashrhi3 can support "r,r,C15" without overhead.
    Apart from that, the asm out functions for the shifts now use
    avr_asm_len to print assembly and to track the isnsns' lengths.
    
    gcc/
            * config/avr/avr.md (ashlhi3, *ashlhi3_const_split, *ashlhi3_const)
            (*ashlpsi3_split, *ashlpsi3)
            (ashlsi3, *ashlsi3_const_split, *ashlsi3_const)
            (ashrhi3, *ashrhi3, ashrpsi3, *ashrpsi3, ashrsi3, *ashrsi3)
            (*ashrhi3_const_split, *ashrhi3_const, *ashrsi3_const_split, *ashrsi3_const):
            Add constraint alternatives that allow a 3-operand operation when the
            shift offset is one less than the mode's bitsize.
            * config/avr/avr.cc (ashl<mode>3_out, ashr<mode>3_out)
            (lshr<mode>3_out): Use avr_asm_len for asm_out and length tracking.
            (ashrhi3_out, ashlhi3_out): Support the new "r,r,C15" alternatives.
            (ashrsi3_out, ashlsi3_out): Support the new "r,r,C31" alternatives.
            (avr_out_ashrpsi3, avr_out_ashlpsi3): Support the new "r,r,C23" alternatives.
    gcc/testsuite/
            * gcc.target/avr/torture/test-shift.h: New file.
            * gcc.target/avr/torture/shift-l-u32.c: New test.
            * gcc.target/avr/torture/shift-r-u32.c: New test.
            * gcc.target/avr/torture/shift-r-i32.c: New test.
            * gcc.target/avr/torture/shift-l-u24.c: New test.
            * gcc.target/avr/torture/shift-r-u16.c: New test.
            * gcc.target/avr/torture/shift-r-i24.c: New test.
            * gcc.target/avr/torture/shift-l-u16.c: New test.
            * gcc.target/avr/torture/shift-r-u16.c: New test.
            * gcc.target/avr/torture/shift-r-i16.c: New test.
            * gcc.target/avr/torture/shift-l-u8.c: New test.
            * gcc.target/avr/torture/shift-r-u8.c: New test.
            * gcc.target/avr/torture/shift-r-i8.c: New test.

diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc
index 8fab896b70f..725e47c2678 100644
--- a/gcc/config/avr/avr.cc
+++ b/gcc/config/avr/avr.cc
@@ -6598,7 +6598,9 @@ avr_out_cmp_ext (rtx xop[], rtx_code code, int *plen)
                available and SCRATCH, otherwise (no scratch available)
 
    TEMPL is an assembler template that shifts by one position.
-   T_LEN is the length of this template.  */
+   T_LEN is the length of this template.
+   PLEN != 0: Set *PLEN to the length of the sequence in words.
+   PLEN == 0: Output instructions.  */
 
 void
 out_shift_with_cnt (const char *templ, rtx_insn *insn, rtx operands[],
@@ -6721,96 +6723,59 @@ out_shift_with_cnt (const char *templ, rtx_insn *insn, rtx operands[],
 /* 8bit shift left ((char)x << i)   */
 
 const char *
-ashlqi3_out (rtx_insn *insn, rtx operands[], int *len)
+ashlqi3_out (rtx_insn *insn, rtx operands[], int *plen)
 {
   if (CONST_INT_P (operands[2]))
     {
-      int k;
+      bool ldreg_p = test_hard_reg_class (LD_REGS, operands[0]);
+      int offs = INTVAL (operands[2]);
 
-      if (!len)
-	len = &k;
+      if (plen)
+	*plen = 0;
 
-      switch (INTVAL (operands[2]))
+      if (offs <= 3
+	  || (offs <= 6 && ! ldreg_p))
+	{
+	  for (int i = 0; i < offs; ++i)
+	    avr_asm_len ("lsl %0", operands, plen, 1);
+	  return "";
+	}
+
+      switch (offs)
 	{
 	default:
-	  if (INTVAL (operands[2]) < 8)
+	  if (offs < 8)
 	    break;
-
-	  *len = 1;
-	  return "clr %0";
+	  return avr_asm_len ("clr %0", operands, plen, 1);
 
 	case 1:
-	  *len = 1;
-	  return "lsl %0";
-
 	case 2:
-	  *len = 2;
-	  return ("lsl %0" CR_TAB
-		  "lsl %0");
-
 	case 3:
-	  *len = 3;
-	  return ("lsl %0" CR_TAB
-		  "lsl %0" CR_TAB
-		  "lsl %0");
+	  gcc_unreachable ();
 
 	case 4:
-	  if (test_hard_reg_class (LD_REGS, operands[0]))
-	    {
-	      *len = 2;
-	      return ("swap %0" CR_TAB
-		      "andi %0,0xf0");
-	    }
-	  *len = 4;
-	  return ("lsl %0" CR_TAB
-		  "lsl %0" CR_TAB
-		  "lsl %0" CR_TAB
-		  "lsl %0");
-
+	  return avr_asm_len ("swap %0" CR_TAB
+			      "andi %0,0xf0", operands, plen, 2);
 	case 5:
-	  if (test_hard_reg_class (LD_REGS, operands[0]))
-	    {
-	      *len = 3;
-	      return ("swap %0" CR_TAB
-		      "lsl %0"  CR_TAB
-		      "andi %0,0xe0");
-	    }
-	  *len = 5;
-	  return ("lsl %0" CR_TAB
-		  "lsl %0" CR_TAB
-		  "lsl %0" CR_TAB
-		  "lsl %0" CR_TAB
-		  "lsl %0");
-
+	  return avr_asm_len ("swap %0" CR_TAB
+			      "lsl %0"  CR_TAB
+			      "andi %0,0xe0", operands, plen, 3);
 	case 6:
-	  if (test_hard_reg_class (LD_REGS, operands[0]))
-	    {
-	      *len = 4;
-	      return ("swap %0" CR_TAB
-		      "lsl %0"  CR_TAB
-		      "lsl %0"  CR_TAB
-		      "andi %0,0xc0");
-	    }
-	  *len = 6;
-	  return ("lsl %0" CR_TAB
-		  "lsl %0" CR_TAB
-		  "lsl %0" CR_TAB
-		  "lsl %0" CR_TAB
-		  "lsl %0" CR_TAB
-		  "lsl %0");
-
+	  return avr_asm_len ("swap %0" CR_TAB
+			      "lsl %0"  CR_TAB
+			      "lsl %0"  CR_TAB
+			      "andi %0,0xc0", operands, plen, 4);
 	case 7:
-	  *len = 3;
-	  return ("bst %1,0" CR_TAB
-		  "clr %0"   CR_TAB
-		  "bld %0,7");
+	  return avr_asm_len ("bst %1,0" CR_TAB
+			      "clr %0"   CR_TAB
+			      "bld %0,7", operands, plen, 3);
 	}
     }
   else if (CONSTANT_P (operands[2]))
     fatal_insn ("internal compiler error.  Incorrect shift:", insn);
 
   out_shift_with_cnt ("lsl %0",
-		      insn, operands, len, 1);
+		      insn, operands, plen, 1);
   return "";
 }
 
@@ -6818,19 +6783,17 @@ ashlqi3_out (rtx_insn *insn, rtx operands[], int *len)
 /* 16bit shift left ((short)x << i)   */
 
 const char *
-ashlhi3_out (rtx_insn *insn, rtx operands[], int *len)
+ashlhi3_out (rtx_insn *insn, rtx operands[], int *plen)
 {
   if (CONST_INT_P (operands[2]))
     {
-      int scratch = (GET_CODE (PATTERN (insn)) == PARALLEL
-		     && XVECLEN (PATTERN (insn), 0) == 3
-		     && REG_P (operands[3]));
-      int ldi_ok = test_hard_reg_class (LD_REGS, operands[0]);
-      int k;
-      int *t = len;
+      bool scratch = (GET_CODE (PATTERN (insn)) == PARALLEL
+		      && XVECLEN (PATTERN (insn), 0) == 3
+		      && REG_P (operands[3]));
+      bool ldi_ok = test_hard_reg_class (LD_REGS, operands[0]);
 
-      if (!len)
-	len = &k;
+      if (plen)
+	*plen = 0;
 
       switch (INTVAL (operands[2]))
 	{
@@ -6838,238 +6801,182 @@ ashlhi3_out (rtx_insn *insn, rtx operands[], int *len)
 	  if (INTVAL (operands[2]) < 16)
 	    break;
 
-	  *len = 2;
-	  return ("clr %B0" CR_TAB
-		  "clr %A0");
-
+	  return avr_asm_len ("clr %B0" CR_TAB
+			      "clr %A0", operands, plen, 2);
 	case 4:
 	  if (optimize_size && scratch)
 	    break;  /* 5 */
 	  if (ldi_ok)
-	    {
-	      *len = 6;
-	      return ("swap %A0"      CR_TAB
-		      "swap %B0"      CR_TAB
-		      "andi %B0,0xf0" CR_TAB
-		      "eor %B0,%A0"   CR_TAB
-		      "andi %A0,0xf0" CR_TAB
-		      "eor %B0,%A0");
-	    }
+	    return avr_asm_len ("swap %A0"      CR_TAB
+				"swap %B0"      CR_TAB
+				"andi %B0,0xf0" CR_TAB
+				"eor %B0,%A0"   CR_TAB
+				"andi %A0,0xf0" CR_TAB
+				"eor %B0,%A0", operands, plen, 6);
 	  if (scratch)
-	    {
-	      *len = 7;
-	      return ("swap %A0"    CR_TAB
-		      "swap %B0"    CR_TAB
-		      "ldi %3,0xf0" CR_TAB
-		      "and %B0,%3"  CR_TAB
-		      "eor %B0,%A0" CR_TAB
-		      "and %A0,%3"  CR_TAB
-		      "eor %B0,%A0");
-	    }
+	    return avr_asm_len ("swap %A0"    CR_TAB
+				"swap %B0"    CR_TAB
+				"ldi %3,0xf0" CR_TAB
+				"and %B0,%3"  CR_TAB
+				"eor %B0,%A0" CR_TAB
+				"and %A0,%3"  CR_TAB
+				"eor %B0,%A0", operands, plen, 7);
 	  break;  /* optimize_size ? 6 : 8 */
 
 	case 5:
 	  if (optimize_size)
 	    break;  /* scratch ? 5 : 6 */
 	  if (ldi_ok)
-	    {
-	      *len = 8;
-	      return ("lsl %A0"       CR_TAB
-		      "rol %B0"       CR_TAB
-		      "swap %A0"      CR_TAB
-		      "swap %B0"      CR_TAB
-		      "andi %B0,0xf0" CR_TAB
-		      "eor %B0,%A0"   CR_TAB
-		      "andi %A0,0xf0" CR_TAB
-		      "eor %B0,%A0");
-	    }
+	    return avr_asm_len ("lsl %A0"       CR_TAB
+				"rol %B0"       CR_TAB
+				"swap %A0"      CR_TAB
+				"swap %B0"      CR_TAB
+				"andi %B0,0xf0" CR_TAB
+				"eor %B0,%A0"   CR_TAB
+				"andi %A0,0xf0" CR_TAB
+				"eor %B0,%A0", operands, plen, 8);
 	  if (scratch)
-	    {
-	      *len = 9;
-	      return ("lsl %A0"     CR_TAB
-		      "rol %B0"     CR_TAB
-		      "swap %A0"    CR_TAB
-		      "swap %B0"    CR_TAB
-		      "ldi %3,0xf0" CR_TAB
-		      "and %B0,%3"  CR_TAB
-		      "eor %B0,%A0" CR_TAB
-		      "and %A0,%3"  CR_TAB
-		      "eor %B0,%A0");
-	    }
+	    return avr_asm_len ("lsl %A0"     CR_TAB
+				"rol %B0"     CR_TAB
+				"swap %A0"    CR_TAB
+				"swap %B0"    CR_TAB
+				"ldi %3,0xf0" CR_TAB
+				"and %B0,%3"  CR_TAB
+				"eor %B0,%A0" CR_TAB
+				"and %A0,%3"  CR_TAB
+				"eor %B0,%A0", operands, plen, 9);
 	  break;  /* 10 */
 
 	case 6:
 	  if (optimize_size)
 	    break;  /* scratch ? 5 : 6 */
-	  *len = 9;
-	  return ("clr __tmp_reg__" CR_TAB
-		  "lsr %B0"         CR_TAB
-		  "ror %A0"         CR_TAB
-		  "ror __tmp_reg__" CR_TAB
-		  "lsr %B0"         CR_TAB
-		  "ror %A0"         CR_TAB
-		  "ror __tmp_reg__" CR_TAB
-		  "mov %B0,%A0"     CR_TAB
-		  "mov %A0,__tmp_reg__");
-
+	  return avr_asm_len ("clr __tmp_reg__" CR_TAB
+			      "lsr %B0"         CR_TAB
+			      "ror %A0"         CR_TAB
+			      "ror __tmp_reg__" CR_TAB
+			      "lsr %B0"         CR_TAB
+			      "ror %A0"         CR_TAB
+			      "ror __tmp_reg__" CR_TAB
+			      "mov %B0,%A0"     CR_TAB
+			      "mov %A0,__tmp_reg__", operands, plen, 9);
 	case 7:
-	  *len = 5;
-	  return ("lsr %B0"     CR_TAB
-		  "mov %B0,%A0" CR_TAB
-		  "clr %A0"     CR_TAB
-		  "ror %B0"     CR_TAB
-		  "ror %A0");
-
+	  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);
 	case 8:
-	  return *len = 2, ("mov %B0,%A1" CR_TAB
-			    "clr %A0");
-
+	  return avr_asm_len ("mov %B0,%A1" CR_TAB
+			      "clr %A0", operands, plen, 2);
 	case 9:
-	  *len = 3;
-	  return ("mov %B0,%A0" CR_TAB
-		  "clr %A0"     CR_TAB
-		  "lsl %B0");
-
+	  return avr_asm_len ("mov %B0,%A0" CR_TAB
+			      "clr %A0"     CR_TAB
+			      "lsl %B0", operands, plen, 3);
 	case 10:
-	  *len = 4;
-	  return ("mov %B0,%A0" CR_TAB
-		  "clr %A0"     CR_TAB
-		  "lsl %B0"     CR_TAB
-		  "lsl %B0");
-
+	  return avr_asm_len ("mov %B0,%A0" CR_TAB
+			      "clr %A0"     CR_TAB
+			      "lsl %B0"     CR_TAB
+			      "lsl %B0", operands, plen, 4);
 	case 11:
-	  *len = 5;
-	  return ("mov %B0,%A0" CR_TAB
-		  "clr %A0"     CR_TAB
-		  "lsl %B0"     CR_TAB
-		  "lsl %B0"     CR_TAB
-		  "lsl %B0");
-
+	  return avr_asm_len ("mov %B0,%A0" CR_TAB
+			      "clr %A0"     CR_TAB
+			      "lsl %B0"     CR_TAB
+			      "lsl %B0"     CR_TAB
+			      "lsl %B0", operands, plen, 5);
 	case 12:
 	  if (ldi_ok)
-	    {
-	      *len = 4;
-	      return ("mov %B0,%A0" CR_TAB
-		      "clr %A0"     CR_TAB
-		      "swap %B0"    CR_TAB
-		      "andi %B0,0xf0");
-	    }
+	    return avr_asm_len ("mov %B0,%A0" CR_TAB
+				"clr %A0"     CR_TAB
+				"swap %B0"    CR_TAB
+				"andi %B0,0xf0", operands, plen, 4);
 	  if (scratch)
-	    {
-	      *len = 5;
-	      return ("mov %B0,%A0" CR_TAB
-		      "clr %A0"     CR_TAB
-		      "swap %B0"    CR_TAB
-		      "ldi %3,0xf0" CR_TAB
-		      "and %B0,%3");
-	    }
-	  *len = 6;
-	  return ("mov %B0,%A0" CR_TAB
-		  "clr %A0"     CR_TAB
-		  "lsl %B0"     CR_TAB
-		  "lsl %B0"     CR_TAB
-		  "lsl %B0"     CR_TAB
-		  "lsl %B0");
-
+	    return avr_asm_len ("mov %B0,%A0" 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
+			      "clr %A0"     CR_TAB
+			      "lsl %B0"     CR_TAB
+			      "lsl %B0"     CR_TAB
+			      "lsl %B0"     CR_TAB
+			      "lsl %B0", operands, plen, 6);
 	case 13:
 	  if (ldi_ok)
-	    {
-	      *len = 5;
-	      return ("mov %B0,%A0" CR_TAB
-		      "clr %A0"     CR_TAB
-		      "swap %B0"    CR_TAB
-		      "lsl %B0"     CR_TAB
-		      "andi %B0,0xe0");
-	    }
+	    return avr_asm_len ("mov %B0,%A0" CR_TAB
+				"clr %A0"     CR_TAB
+				"swap %B0"    CR_TAB
+				"lsl %B0"     CR_TAB
+				"andi %B0,0xe0", operands, plen, 5);
 	  if (AVR_HAVE_MUL && scratch)
-	    {
-	      *len = 5;
-	      return ("ldi %3,0x20" CR_TAB
-		      "mul %A0,%3"  CR_TAB
-		      "mov %B0,r0"  CR_TAB
-		      "clr %A0"     CR_TAB
-		      "clr __zero_reg__");
-	    }
+	    return avr_asm_len ("ldi %3,0x20" CR_TAB
+				"mul %A0,%3"  CR_TAB
+				"mov %B0,r0"  CR_TAB
+				"clr %A0"     CR_TAB
+				"clr __zero_reg__", operands, plen, 5);
 	  if (optimize_size && scratch)
 	    break;  /* 5 */
+
 	  if (scratch)
-	    {
-	      *len = 6;
-	      return ("mov %B0,%A0" CR_TAB
-		      "clr %A0"     CR_TAB
-		      "swap %B0"    CR_TAB
-		      "lsl %B0"     CR_TAB
-		      "ldi %3,0xe0" CR_TAB
-		      "and %B0,%3");
-	    }
+	    return avr_asm_len ("mov %B0,%A0" CR_TAB
+				"clr %A0"     CR_TAB
+				"swap %B0"    CR_TAB
+				"lsl %B0"     CR_TAB
+				"ldi %3,0xe0" CR_TAB
+				"and %B0,%3", operands, plen, 6);
 	  if (AVR_HAVE_MUL)
-	    {
-	      *len = 6;
-	      return ("set"        CR_TAB
-		      "bld r1,5"   CR_TAB
-		      "mul %A0,r1" CR_TAB
-		      "mov %B0,r0" CR_TAB
-		      "clr %A0"    CR_TAB
-		      "clr __zero_reg__");
-	    }
-	  *len = 7;
-	  return ("mov %B0,%A0" CR_TAB
-		  "clr %A0"     CR_TAB
-		  "lsl %B0"     CR_TAB
-		  "lsl %B0"     CR_TAB
-		  "lsl %B0"     CR_TAB
-		  "lsl %B0"     CR_TAB
-		  "lsl %B0");
-
+	    return avr_asm_len ("set"        CR_TAB
+				"bld r1,5"   CR_TAB
+				"mul %A0,r1" CR_TAB
+				"mov %B0,r0" CR_TAB
+				"clr %A0"    CR_TAB
+				"clr __zero_reg__", operands, plen, 6);
+	  return avr_asm_len ("mov %B0,%A0" CR_TAB
+			      "clr %A0"     CR_TAB
+			      "lsl %B0"     CR_TAB
+			      "lsl %B0"     CR_TAB
+			      "lsl %B0"     CR_TAB
+			      "lsl %B0"     CR_TAB
+			      "lsl %B0", operands, plen, 7);
 	case 14:
 	  if (AVR_HAVE_MUL && ldi_ok)
-	    {
-	      *len = 5;
-	      return ("ldi %B0,0x40" CR_TAB
-		      "mul %A0,%B0"  CR_TAB
-		      "mov %B0,r0"   CR_TAB
-		      "clr %A0"      CR_TAB
-		      "clr __zero_reg__");
-	    }
+	    return avr_asm_len ("ldi %B0,0x40" CR_TAB
+				"mul %A0,%B0"  CR_TAB
+				"mov %B0,r0"   CR_TAB
+				"clr %A0"      CR_TAB
+				"clr __zero_reg__", operands, plen, 5);
 	  if (AVR_HAVE_MUL && scratch)
-	    {
-	      *len = 5;
-	      return ("ldi %3,0x40" CR_TAB
-		      "mul %A0,%3"  CR_TAB
-		      "mov %B0,r0"  CR_TAB
-		      "clr %A0"     CR_TAB
-		      "clr __zero_reg__");
-	    }
+	    return avr_asm_len ("ldi %3,0x40" CR_TAB
+				"mul %A0,%3"  CR_TAB
+				"mov %B0,r0"  CR_TAB
+				"clr %A0"     CR_TAB
+				"clr __zero_reg__", operands, plen, 5);
 	  if (optimize_size && ldi_ok)
-	    {
-	      *len = 5;
-	      return ("mov %B0,%A0" CR_TAB
-		      "ldi %A0,6" "\n1:\t"
-		      "lsl %B0"     CR_TAB
-		      "dec %A0"     CR_TAB
-		      "brne 1b");
-	    }
+	    return avr_asm_len ("mov %B0,%A0" CR_TAB
+				"ldi %A0,6" "\n1:\t"
+				"lsl %B0"     CR_TAB
+				"dec %A0"     CR_TAB
+				"brne 1b", operands, plen, 5);
 	  if (optimize_size && scratch)
 	    break;  /* 5 */
-	  *len = 6;
-	  return ("clr %B0" CR_TAB
-		  "lsr %A0" CR_TAB
-		  "ror %B0" CR_TAB
-		  "lsr %A0" CR_TAB
-		  "ror %B0" CR_TAB
-		  "clr %A0");
 
+	  return avr_asm_len ("clr %B0" CR_TAB
+			      "lsr %A0" CR_TAB
+			      "ror %B0" CR_TAB
+			      "lsr %A0" CR_TAB
+			      "ror %B0" CR_TAB
+			      "clr %A0", operands, plen, 6);
 	case 15:
-	  *len = 4;
-	  return ("clr %B0" CR_TAB
-		  "lsr %A0" CR_TAB
-		  "ror %B0" CR_TAB
-		  "clr %A0");
-	}
-      len = t;
+	  return avr_asm_len ("bst %A1,0" CR_TAB
+			      "clr %A0"   CR_TAB
+			      "clr %B0"   CR_TAB
+			      "bld %B0,7", operands, plen, 4);
+	} // switch
     }
+
   out_shift_with_cnt ("lsl %A0" CR_TAB
-		      "rol %B0", insn, operands, len, 2);
+			  "rol %B0", insn, operands, plen, 2);
   return "";
 }
 
@@ -7084,6 +6991,9 @@ avr_out_ashlpsi3 (rtx_insn *insn, rtx *op, int *plen)
 
   if (CONST_INT_P (op[2]))
     {
+      int reg0 = REGNO (op[0]);
+      int reg1 = REGNO (op[1]);
+
       switch (INTVAL (op[2]))
 	{
 	default:
@@ -7093,40 +7003,26 @@ avr_out_ashlpsi3 (rtx_insn *insn, rtx *op, int *plen)
 	  return avr_asm_len ("clr %A0" CR_TAB
 			      "clr %B0" CR_TAB
 			      "clr %C0", op, plen, 3);
-
 	case 8:
-	  {
-	    int reg0 = REGNO (op[0]);
-	    int reg1 = REGNO (op[1]);
-
-	    if (reg0 >= reg1)
-	      return avr_asm_len ("mov %C0,%B1"  CR_TAB
-				  "mov %B0,%A1"  CR_TAB
-				  "clr %A0", op, plen, 3);
-	    else
-	      return avr_asm_len ("clr %A0"      CR_TAB
-				  "mov %B0,%A1"  CR_TAB
-				  "mov %C0,%B1", op, plen, 3);
-	  }
-
+	  return reg0 >= reg1
+	    ? avr_asm_len ("mov %C0,%B1"  CR_TAB
+			   "mov %B0,%A1"  CR_TAB
+			   "clr %A0", op, plen, 3)
+	    : avr_asm_len ("clr %A0"      CR_TAB
+			   "mov %B0,%A1"  CR_TAB
+			   "mov %C0,%B1", op, plen, 3);
 	case 16:
-	  {
-	    int reg0 = REGNO (op[0]);
-	    int reg1 = REGNO (op[1]);
-
-	    if (reg0 + 2 != reg1)
-	      avr_asm_len ("mov %C0,%A1", op, plen, 1);
-
-	    return avr_asm_len ("clr %B0"  CR_TAB
-				"clr %A0", op, plen, 2);
-	  }
+	  if (reg0 + 2 != reg1)
+	    avr_asm_len ("mov %C0,%A1", op, plen, 1);
 
+	  return avr_asm_len ("clr %B0"  CR_TAB
+			      "clr %A0", op, plen, 2);
 	case 23:
-	  return avr_asm_len ("clr %C0" CR_TAB
-			      "lsr %A0" CR_TAB
-			      "ror %C0" CR_TAB
-			      "clr %B0" CR_TAB
-			      "clr %A0", op, plen, 5);
+	  return avr_asm_len ("bst %A1,0" CR_TAB
+			      "clr %A0"   CR_TAB
+			      "clr %B0"   CR_TAB
+			      "clr %C0"   CR_TAB
+			      "bld %C0,7", op, plen, 5);
 	}
     }
 
@@ -7140,15 +7036,15 @@ avr_out_ashlpsi3 (rtx_insn *insn, rtx *op, int *plen)
 /* 32bit shift left ((long)x << i)   */
 
 const char *
-ashlsi3_out (rtx_insn *insn, rtx operands[], int *len)
+ashlsi3_out (rtx_insn *insn, rtx operands[], int *plen)
 {
   if (CONST_INT_P (operands[2]))
     {
-      int k;
-      int *t = len;
+      int reg0 = true_regnum (operands[0]);
+      int reg1 = true_regnum (operands[1]);
 
-      if (!len)
-	len = &k;
+      if (plen)
+	*plen = 0;
 
       switch (INTVAL (operands[2]))
 	{
@@ -7156,73 +7052,61 @@ ashlsi3_out (rtx_insn *insn, rtx operands[], int *len)
 	  if (INTVAL (operands[2]) < 32)
 	    break;
 
-	  if (AVR_HAVE_MOVW)
-	    return *len = 3, ("clr %D0" CR_TAB
-			      "clr %C0" CR_TAB
-			      "movw %A0,%C0");
-	  *len = 4;
-	  return ("clr %D0" CR_TAB
-		  "clr %C0" CR_TAB
-		  "clr %B0" CR_TAB
-		  "clr %A0");
-
+	  return AVR_HAVE_MOVW
+	    ? avr_asm_len ("clr %D0" CR_TAB
+			   "clr %C0" CR_TAB
+			   "movw %A0,%C0", operands, plen, 3)
+	    : avr_asm_len ("clr %D0" CR_TAB
+			   "clr %C0" CR_TAB
+			   "clr %B0" CR_TAB
+			   "clr %A0", operands, plen, 4);
 	case 8:
-	  {
-	    int reg0 = true_regnum (operands[0]);
-	    int reg1 = true_regnum (operands[1]);
-	    *len = 4;
-	    if (reg0 >= reg1)
-	      return ("mov %D0,%C1"  CR_TAB
-		      "mov %C0,%B1"  CR_TAB
-		      "mov %B0,%A1"  CR_TAB
-		      "clr %A0");
-	    else
-	      return ("clr %A0"      CR_TAB
-		      "mov %B0,%A1"  CR_TAB
-		      "mov %C0,%B1"  CR_TAB
-		      "mov %D0,%C1");
-	  }
-
+	  return reg0 >= reg1
+	    ? avr_asm_len ("mov %D0,%C1"  CR_TAB
+			   "mov %C0,%B1"  CR_TAB
+			   "mov %B0,%A1"  CR_TAB
+			   "clr %A0", operands, plen, 4)
+	    : avr_asm_len ("clr %A0"      CR_TAB
+			   "mov %B0,%A1"  CR_TAB
+			   "mov %C0,%B1"  CR_TAB
+			   "mov %D0,%C1", operands, plen, 4);
 	case 16:
-	  {
-	    int reg0 = true_regnum (operands[0]);
-	    int reg1 = true_regnum (operands[1]);
-	    if (reg0 + 2 == reg1)
-	      return *len = 2, ("clr %B0"      CR_TAB
-				"clr %A0");
-	    if (AVR_HAVE_MOVW)
-	      return *len = 3, ("movw %C0,%A1" CR_TAB
-				"clr %B0"      CR_TAB
-				"clr %A0");
-	    else
-	      return *len = 4, ("mov %C0,%A1"  CR_TAB
-				"mov %D0,%B1"  CR_TAB
-				"clr %B0"      CR_TAB
-				"clr %A0");
-	  }
-
+	  if (reg0 + 2 == reg1)
+	    return avr_asm_len ("clr %B0"  CR_TAB
+				"clr %A0", operands, plen, 2);
+	  return AVR_HAVE_MOVW
+	    ? avr_asm_len ("movw %C0,%A1" CR_TAB
+			   "clr %B0"      CR_TAB
+			   "clr %A0", operands, plen, 3)
+	    : avr_asm_len ("mov %C0,%A1"  CR_TAB
+			   "mov %D0,%B1"  CR_TAB
+			   "clr %B0"      CR_TAB
+			   "clr %A0", operands, plen, 4);
 	case 24:
-	  *len = 4;
-	  return ("mov %D0,%A1"  CR_TAB
-		  "clr %C0"      CR_TAB
-		  "clr %B0"      CR_TAB
-		  "clr %A0");
-
+	  return avr_asm_len ("mov %D0,%A1"  CR_TAB
+			      "clr %C0"      CR_TAB
+			      "clr %B0"      CR_TAB
+			      "clr %A0", operands, plen, 4);
 	case 31:
-	  *len = 6;
-	  return ("clr %D0" CR_TAB
-		  "lsr %A0" CR_TAB
-		  "ror %D0" CR_TAB
-		  "clr %C0" CR_TAB
-		  "clr %B0" CR_TAB
-		  "clr %A0");
+	  return AVR_HAVE_MOVW
+	    ? avr_asm_len ("bst %A1,0"    CR_TAB
+			   "clr %A0"      CR_TAB
+			   "clr %B0"      CR_TAB
+			   "movw %C0,%A0" CR_TAB
+			   "bld %D0,7", operands, plen, 5)
+	    : avr_asm_len ("bst %A1,0" CR_TAB
+			   "clr %A0"   CR_TAB
+			   "clr %B0"   CR_TAB
+			   "clr %D0"   CR_TAB
+			   "clr %C0"   CR_TAB
+			   "bld %D0,7", operands, plen, 6);
 	}
-      len = t;
     }
+
   out_shift_with_cnt ("lsl %A0" CR_TAB
 		      "rol %B0" CR_TAB
 		      "rol %C0" CR_TAB
-		      "rol %D0", insn, operands, len, 4);
+		      "rol %D0", insn, operands, plen, 4);
   return "";
 }
 
@@ -7275,19 +7159,17 @@ ashrqi3_out (rtx_insn *insn, rtx operands[], int *plen)
 /* 16bit arithmetic shift right  ((signed short)x >> i) */
 
 const char *
-ashrhi3_out (rtx_insn *insn, rtx operands[], int *len)
+ashrhi3_out (rtx_insn *insn, rtx operands[], int *plen)
 {
   if (CONST_INT_P (operands[2]))
     {
-      int scratch = (GET_CODE (PATTERN (insn)) == PARALLEL
-		     && XVECLEN (PATTERN (insn), 0) == 3
-		     && REG_P (operands[3]));
-      int ldi_ok = test_hard_reg_class (LD_REGS, operands[0]);
-      int k;
-      int *t = len;
+      bool scratch = (GET_CODE (PATTERN (insn)) == PARALLEL
+		      && XVECLEN (PATTERN (insn), 0) == 3
+		      && REG_P (operands[3]));
+      bool ldi_ok = test_hard_reg_class (LD_REGS, operands[0]);
 
-      if (!len)
-	len = &k;
+      if (plen)
+	*plen = 0;
 
       switch (INTVAL (operands[2]))
 	{
@@ -7299,125 +7181,99 @@ ashrhi3_out (rtx_insn *insn, rtx operands[], int *len)
 	case 6:
 	  if (optimize_size)
 	    break;  /* scratch ? 5 : 6 */
-	  *len = 8;
-	  return ("mov __tmp_reg__,%A0" CR_TAB
-		  "mov %A0,%B0"         CR_TAB
-		  "lsl __tmp_reg__"     CR_TAB
-		  "rol %A0"             CR_TAB
-		  "sbc %B0,%B0"         CR_TAB
-		  "lsl __tmp_reg__"     CR_TAB
-		  "rol %A0"             CR_TAB
-		  "rol %B0");
-
+	  return avr_asm_len ("mov __tmp_reg__,%A0" CR_TAB
+			      "mov %A0,%B0"         CR_TAB
+			      "lsl __tmp_reg__"     CR_TAB
+			      "rol %A0"             CR_TAB
+			      "sbc %B0,%B0"         CR_TAB
+			      "lsl __tmp_reg__"     CR_TAB
+			      "rol %A0"             CR_TAB
+			      "rol %B0", operands, plen, 8);
 	case 7:
-	  *len = 4;
-	  return ("lsl %A0"     CR_TAB
-		  "mov %A0,%B0" CR_TAB
-		  "rol %A0"     CR_TAB
-		  "sbc %B0,%B0");
-
+	  return avr_asm_len ("lsl %A0"     CR_TAB
+			      "mov %A0,%B0" CR_TAB
+			      "rol %A0"     CR_TAB
+			      "sbc %B0,%B0", operands, plen, 4);
 	case 8:
 	  {
 	    int reg0 = true_regnum (operands[0]);
 	    int reg1 = true_regnum (operands[1]);
 
-	    if (reg0 == reg1)
-	      return *len = 3, ("mov %A0,%B0" CR_TAB
-				"lsl %B0"     CR_TAB
-				"sbc %B0,%B0");
-	    else
-	      return *len = 4, ("mov %A0,%B1" CR_TAB
-				"clr %B0"     CR_TAB
-				"sbrc %A0,7"  CR_TAB
-				"dec %B0");
+	    return reg0 == reg1
+	      ? avr_asm_len ("mov %A0,%B0" CR_TAB
+			     "lsl %B0"     CR_TAB
+			     "sbc %B0,%B0", operands, plen, 3)
+	      : avr_asm_len ("mov %A0,%B1" CR_TAB
+			     "clr %B0"     CR_TAB
+			     "sbrc %A0,7"  CR_TAB
+			     "dec %B0", operands, plen, 4);
 	  }
 
 	case 9:
-	  *len = 4;
-	  return ("mov %A0,%B0" CR_TAB
-		  "lsl %B0"      CR_TAB
-		  "sbc %B0,%B0" CR_TAB
-		  "asr %A0");
-
+	  return avr_asm_len ("mov %A0,%B0" CR_TAB
+			      "lsl %B0"      CR_TAB
+			      "sbc %B0,%B0" CR_TAB
+			      "asr %A0", operands, plen, 4);
 	case 10:
-	  *len = 5;
-	  return ("mov %A0,%B0" CR_TAB
-		  "lsl %B0"     CR_TAB
-		  "sbc %B0,%B0" CR_TAB
-		  "asr %A0"     CR_TAB
-		  "asr %A0");
-
+	  return avr_asm_len ("mov %A0,%B0" CR_TAB
+			      "lsl %B0"     CR_TAB
+			      "sbc %B0,%B0" CR_TAB
+			      "asr %A0"     CR_TAB
+			      "asr %A0", operands, plen, 5);
 	case 11:
 	  if (AVR_HAVE_MUL && ldi_ok)
-	    {
-	      *len = 5;
-	      return ("ldi %A0,0x20" CR_TAB
-		      "muls %B0,%A0" CR_TAB
-		      "mov %A0,r1"   CR_TAB
-		      "sbc %B0,%B0"  CR_TAB
-		      "clr __zero_reg__");
-	    }
+	    return avr_asm_len ("ldi %A0,0x20" CR_TAB
+				"muls %B0,%A0" CR_TAB
+				"mov %A0,r1"   CR_TAB
+				"sbc %B0,%B0"  CR_TAB
+				"clr __zero_reg__", operands, plen, 5);
 	  if (optimize_size && scratch)
 	    break;  /* 5 */
-	  *len = 6;
-	  return ("mov %A0,%B0" CR_TAB
-		  "lsl %B0"     CR_TAB
-		  "sbc %B0,%B0" CR_TAB
-		  "asr %A0"     CR_TAB
-		  "asr %A0"     CR_TAB
-		  "asr %A0");
-
+	  return avr_asm_len ("mov %A0,%B0" CR_TAB
+			      "lsl %B0"     CR_TAB
+			      "sbc %B0,%B0" CR_TAB
+			      "asr %A0"     CR_TAB
+			      "asr %A0"     CR_TAB
+			      "asr %A0", operands, plen, 6);
 	case 12:
 	  if (AVR_HAVE_MUL && ldi_ok)
-	    {
-	      *len = 5;
-	      return ("ldi %A0,0x10" CR_TAB
-		      "muls %B0,%A0" CR_TAB
-		      "mov %A0,r1"   CR_TAB
-		      "sbc %B0,%B0"  CR_TAB
-		      "clr __zero_reg__");
-	    }
+	    return avr_asm_len ("ldi %A0,0x10" CR_TAB
+				"muls %B0,%A0" CR_TAB
+				"mov %A0,r1"   CR_TAB
+				"sbc %B0,%B0"  CR_TAB
+				"clr __zero_reg__", operands, plen, 5);
 	  if (optimize_size && scratch)
 	    break;  /* 5 */
-	  *len = 7;
-	  return ("mov %A0,%B0" CR_TAB
-		  "lsl %B0"     CR_TAB
-		  "sbc %B0,%B0" CR_TAB
-		  "asr %A0"     CR_TAB
-		  "asr %A0"     CR_TAB
-		  "asr %A0"     CR_TAB
-		  "asr %A0");
-
+	  return avr_asm_len ("mov %A0,%B0" CR_TAB
+			      "lsl %B0"     CR_TAB
+			      "sbc %B0,%B0" CR_TAB
+			      "asr %A0"     CR_TAB
+			      "asr %A0"     CR_TAB
+			      "asr %A0"     CR_TAB
+			      "asr %A0", operands, plen, 7);
 	case 13:
 	  if (AVR_HAVE_MUL && ldi_ok)
-	    {
-	      *len = 5;
-	      return ("ldi %A0,0x08" CR_TAB
-		      "muls %B0,%A0" CR_TAB
-		      "mov %A0,r1"   CR_TAB
-		      "sbc %B0,%B0"  CR_TAB
-		      "clr __zero_reg__");
-	    }
+	    return avr_asm_len ("ldi %A0,0x08" CR_TAB
+				"muls %B0,%A0" CR_TAB
+				"mov %A0,r1"   CR_TAB
+				"sbc %B0,%B0"  CR_TAB
+				"clr __zero_reg__", operands, plen, 5);
 	  if (optimize_size)
 	    break;  /* scratch ? 5 : 7 */
-	  *len = 8;
-	  return ("mov %A0,%B0" CR_TAB
-		  "lsl %B0"     CR_TAB
-		  "sbc %B0,%B0" CR_TAB
-		  "asr %A0"     CR_TAB
-		  "asr %A0"     CR_TAB
-		  "asr %A0"     CR_TAB
-		  "asr %A0"     CR_TAB
-		  "asr %A0");
-
+	  return avr_asm_len ("mov %A0,%B0" CR_TAB
+			      "lsl %B0"     CR_TAB
+			      "sbc %B0,%B0" CR_TAB
+			      "asr %A0"     CR_TAB
+			      "asr %A0"     CR_TAB
+			      "asr %A0"     CR_TAB
+			      "asr %A0"     CR_TAB
+			      "asr %A0", operands, plen, 8);
 	case 14:
-	  *len = 5;
-	  return ("lsl %B0"     CR_TAB
-		  "sbc %A0,%A0" CR_TAB
-		  "lsl %B0"     CR_TAB
-		  "mov %B0,%A0" CR_TAB
-		  "rol %A0");
-
+	  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);
 	default:
 	  if (INTVAL (operands[2]) < 16)
 	    break;
@@ -7425,14 +7281,22 @@ ashrhi3_out (rtx_insn *insn, rtx operands[], int *len)
 	  /* fall through */
 
 	case 15:
-	  return *len = 3, ("lsl %B0"     CR_TAB
-			    "sbc %A0,%A0" CR_TAB
-			    "mov %B0,%A0");
-	}
-      len = t;
+	  {
+	    rtx xop[2] = { operands[0], operands[1] };
+	    if (! reg_unused_after (insn, xop[1]))
+	      {
+		avr_asm_len ("mov %B0,%B1", xop, plen, 1);
+		xop[1] = xop[0];
+	      }
+	    return avr_asm_len ("lsl %B1"     CR_TAB
+				"sbc %A0,%A0" CR_TAB
+				"mov %B0,%A0", xop, plen, 3);
+	  }
+	} // switch
     }
+
   out_shift_with_cnt ("asr %B0" CR_TAB
-		      "ror %A0", insn, operands, len, 2);
+		      "ror %A0", insn, operands, plen, 2);
   return "";
 }
 
@@ -7453,28 +7317,24 @@ avr_out_ashrpsi3 (rtx_insn *insn, rtx *op, int *plen)
       switch (INTVAL (op[2]))
 	{
 	case 8:
-	  if (dest <= src)
-	    return avr_asm_len ("mov %A0,%B1" CR_TAB
-				"mov %B0,%C1" CR_TAB
-				"clr %C0"     CR_TAB
-				"sbrc %B0,7"  CR_TAB
-				"dec %C0", op, plen, 5);
-	  else
-	    return avr_asm_len ("clr %C0"     CR_TAB
-				"sbrc %C1,7"  CR_TAB
-				"dec %C0"     CR_TAB
-				"mov %B0,%C1" CR_TAB
-				"mov %A0,%B1", op, plen, 5);
-
+	  return dest <= src
+	    ? avr_asm_len ("mov %A0,%B1" CR_TAB
+			   "mov %B0,%C1" CR_TAB
+			   "clr %C0"     CR_TAB
+			   "sbrc %B0,7"  CR_TAB
+			   "dec %C0", op, plen, 5)
+	    : avr_asm_len ("clr %C0"     CR_TAB
+			   "sbrc %C1,7"  CR_TAB
+			   "dec %C0"     CR_TAB
+			   "mov %B0,%C1" CR_TAB
+			   "mov %A0,%B1", op, plen, 5);
 	case 16:
 	  if (dest != src + 2)
 	    avr_asm_len ("mov %A0,%C1", op, plen, 1);
-
 	  return avr_asm_len ("clr %B0"     CR_TAB
 			      "sbrc %A0,7"  CR_TAB
 			      "com %B0"     CR_TAB
 			      "mov %C0,%B0", op, plen, 4);
-
 	default:
 	  if (INTVAL (op[2]) < 24)
 	    break;
@@ -7482,10 +7342,18 @@ avr_out_ashrpsi3 (rtx_insn *insn, rtx *op, int *plen)
 	  /* fall through */
 
 	case 23:
-	  return avr_asm_len ("lsl %C0"     CR_TAB
-			      "sbc %A0,%A0" CR_TAB
-			      "mov %B0,%A0" CR_TAB
-			      "mov %C0,%A0", op, plen, 4);
+	  {
+	    rtx xop[2] = { op[0], op[1] };
+	    if (! reg_unused_after (insn, xop[1]))
+	      {
+		avr_asm_len ("mov %C0,%C1", xop, plen, 1);
+		xop[1] = xop[0];
+	      }
+	    return avr_asm_len ("lsl %C1"     CR_TAB
+				"sbc %A0,%A0" CR_TAB
+				"mov %B0,%A0" CR_TAB
+				"mov %C0,%A0", xop, plen, 4);
+	  }
 	} /* switch */
     }
 
@@ -7499,72 +7367,57 @@ avr_out_ashrpsi3 (rtx_insn *insn, rtx *op, int *plen)
 /* 32-bit arithmetic shift right  ((signed long)x >> i) */
 
 const char *
-ashrsi3_out (rtx_insn *insn, rtx operands[], int *len)
+ashrsi3_out (rtx_insn *insn, rtx operands[], int *plen)
 {
   if (CONST_INT_P (operands[2]))
     {
-      int k;
-      int *t = len;
+      if (plen)
+	*plen = 0;
 
-      if (!len)
-	len = &k;
+      int reg0 = true_regnum (operands[0]);
+      int reg1 = true_regnum (operands[1]);
 
       switch (INTVAL (operands[2]))
 	{
 	case 8:
-	  {
-	    int reg0 = true_regnum (operands[0]);
-	    int reg1 = true_regnum (operands[1]);
-	    *len=6;
-	    if (reg0 <= reg1)
-	      return ("mov %A0,%B1" CR_TAB
-		      "mov %B0,%C1" CR_TAB
-		      "mov %C0,%D1" CR_TAB
-		      "clr %D0"     CR_TAB
-		      "sbrc %C0,7"  CR_TAB
-		      "dec %D0");
-	    else
-	      return ("clr %D0"     CR_TAB
-		      "sbrc %D1,7"  CR_TAB
-		      "dec %D0"     CR_TAB
-		      "mov %C0,%D1" CR_TAB
-		      "mov %B0,%C1" CR_TAB
-		      "mov %A0,%B1");
-	  }
-
+	  return reg0 <= reg1
+	    ? avr_asm_len ("mov %A0,%B1" CR_TAB
+			   "mov %B0,%C1" CR_TAB
+			   "mov %C0,%D1" CR_TAB
+			   "clr %D0"     CR_TAB
+			   "sbrc %C0,7"  CR_TAB
+			   "dec %D0", operands, plen, 6)
+	    : avr_asm_len ("clr %D0"     CR_TAB
+			   "sbrc %D1,7"  CR_TAB
+			   "dec %D0"     CR_TAB
+			   "mov %C0,%D1" CR_TAB
+			   "mov %B0,%C1" CR_TAB
+			   "mov %A0,%B1", operands, plen, 6);
 	case 16:
-	  {
-	    int reg0 = true_regnum (operands[0]);
-	    int reg1 = true_regnum (operands[1]);
-
-	    if (reg0 == reg1 + 2)
-	      return *len = 4, ("clr %D0"     CR_TAB
+	  if (reg0 == reg1 + 2)
+	    return avr_asm_len ("clr %D0"     CR_TAB
 				"sbrc %B0,7"  CR_TAB
 				"com %D0"     CR_TAB
-				"mov %C0,%D0");
-	    if (AVR_HAVE_MOVW)
-	      return *len = 5, ("movw %A0,%C1" CR_TAB
-				"clr %D0"      CR_TAB
-				"sbrc %B0,7"   CR_TAB
-				"com %D0"      CR_TAB
-				"mov %C0,%D0");
-	    else
-	      return *len = 6, ("mov %B0,%D1" CR_TAB
-				"mov %A0,%C1" CR_TAB
-				"clr %D0"     CR_TAB
-				"sbrc %B0,7"  CR_TAB
-				"com %D0"     CR_TAB
-				"mov %C0,%D0");
-	  }
-
+				"mov %C0,%D0", operands, plen, 4);
+	  return AVR_HAVE_MOVW
+	    ? avr_asm_len ("movw %A0,%C1" CR_TAB
+			   "clr %D0"      CR_TAB
+			   "sbrc %B0,7"   CR_TAB
+			   "com %D0"      CR_TAB
+			   "mov %C0,%D0", operands, plen, 5)
+	    : avr_asm_len ("mov %B0,%D1" CR_TAB
+			   "mov %A0,%C1" CR_TAB
+			   "clr %D0"     CR_TAB
+			   "sbrc %B0,7"  CR_TAB
+			   "com %D0"     CR_TAB
+			   "mov %C0,%D0", operands, plen, 6);
 	case 24:
-	  return *len = 6, ("mov %A0,%D1" CR_TAB
-			    "clr %D0"     CR_TAB
-			    "sbrc %A0,7"  CR_TAB
-			    "com %D0"     CR_TAB
-			    "mov %B0,%D0" CR_TAB
-			    "mov %C0,%D0");
-
+	  return avr_asm_len ("mov %A0,%D1" CR_TAB
+			      "clr %D0"     CR_TAB
+			      "sbrc %A0,7"  CR_TAB
+			      "com %D0"     CR_TAB
+			      "mov %B0,%D0" CR_TAB
+			      "mov %C0,%D0", operands, plen, 6);
 	default:
 	  if (INTVAL (operands[2]) < 32)
 	    break;
@@ -7572,377 +7425,287 @@ ashrsi3_out (rtx_insn *insn, rtx operands[], int *len)
 	  /* fall through */
 
 	case 31:
-	  if (AVR_HAVE_MOVW)
-	    return *len = 4, ("lsl %D0"     CR_TAB
-			      "sbc %A0,%A0" CR_TAB
-			      "mov %B0,%A0" CR_TAB
-			      "movw %C0,%A0");
-	  else
-	    return *len = 5, ("lsl %D0"     CR_TAB
-			      "sbc %A0,%A0" CR_TAB
-			      "mov %B0,%A0" CR_TAB
-			      "mov %C0,%A0" CR_TAB
-			      "mov %D0,%A0");
-	}
-      len = t;
+	  {
+	    rtx xop[2] = { operands[0], operands[1] };
+	    if (! reg_unused_after (insn, xop[1]))
+	      {
+		avr_asm_len ("mov %D0,%D1", xop, plen, 1);
+		xop[1] = xop[0];
+	      }
+	    return AVR_HAVE_MOVW
+	      ? avr_asm_len ("lsl %D1"     CR_TAB
+			     "sbc %A0,%A0" CR_TAB
+			     "mov %B0,%A0" CR_TAB
+			     "movw %C0,%A0", xop, plen, 4)
+	      : avr_asm_len ("lsl %D1"     CR_TAB
+			     "sbc %A0,%A0" CR_TAB
+			     "mov %B0,%A0" CR_TAB
+			     "mov %C0,%A0" CR_TAB
+			     "mov %D0,%A0", xop, plen, 5);
+	  }
+	} // switch
     }
+
   out_shift_with_cnt ("asr %D0" CR_TAB
 		      "ror %C0" CR_TAB
 		      "ror %B0" CR_TAB
-		      "ror %A0", insn, operands, len, 4);
+		      "ror %A0", insn, operands, plen, 4);
   return "";
 }
 
 /* 8-bit logic shift right ((unsigned char)x >> i) */
 
 const char *
-lshrqi3_out (rtx_insn *insn, rtx operands[], int *len)
+lshrqi3_out (rtx_insn *insn, rtx operands[], int *plen)
 {
   if (CONST_INT_P (operands[2]))
     {
-      int k;
+      bool ldreg_p = test_hard_reg_class (LD_REGS, operands[0]);
+      int offs = INTVAL (operands[2]);
 
-      if (!len)
-	len = &k;
+      if (plen)
+	*plen = 0;
+
+      if (offs <= 3
+	  || (offs <= 6 && ! ldreg_p))
+	{
+	  for (int i = 0; i < offs; ++i)
+	    avr_asm_len ("lsr %0", operands, plen, 1);
+	  return "";
+	}
 
       switch (INTVAL (operands[2]))
 	{
 	default:
 	  if (INTVAL (operands[2]) < 8)
 	    break;
-
-	  *len = 1;
-	  return "clr %0";
+	  return avr_asm_len ("clr %0", operands, plen, 1);
 
 	case 1:
-	  *len = 1;
-	  return "lsr %0";
-
 	case 2:
-	  *len = 2;
-	  return ("lsr %0" CR_TAB
-		  "lsr %0");
 	case 3:
-	  *len = 3;
-	  return ("lsr %0" CR_TAB
-		  "lsr %0" CR_TAB
-		  "lsr %0");
+	  gcc_unreachable ();
 
 	case 4:
-	  if (test_hard_reg_class (LD_REGS, operands[0]))
-	    {
-	      *len=2;
-	      return ("swap %0" CR_TAB
-		      "andi %0,0x0f");
-	    }
-	  *len = 4;
-	  return ("lsr %0" CR_TAB
-		  "lsr %0" CR_TAB
-		  "lsr %0" CR_TAB
-		  "lsr %0");
-
+	  return avr_asm_len ("swap %0" CR_TAB
+			      "andi %0,0x0f", operands, plen, 2);
 	case 5:
-	  if (test_hard_reg_class (LD_REGS, operands[0]))
-	    {
-	      *len = 3;
-	      return ("swap %0" CR_TAB
-		      "lsr %0"  CR_TAB
-		      "andi %0,0x7");
-	    }
-	  *len = 5;
-	  return ("lsr %0" CR_TAB
-		  "lsr %0" CR_TAB
-		  "lsr %0" CR_TAB
-		  "lsr %0" CR_TAB
-		  "lsr %0");
-
+	  return avr_asm_len ("swap %0" CR_TAB
+			      "lsr %0"  CR_TAB
+			      "andi %0,0x7", operands, plen, 3);
 	case 6:
-	  if (test_hard_reg_class (LD_REGS, operands[0]))
-	    {
-	      *len = 4;
-	      return ("swap %0" CR_TAB
-		      "lsr %0"  CR_TAB
-		      "lsr %0"  CR_TAB
-		      "andi %0,0x3");
-	    }
-	  *len = 6;
-	  return ("lsr %0" CR_TAB
-		  "lsr %0" CR_TAB
-		  "lsr %0" CR_TAB
-		  "lsr %0" CR_TAB
-		  "lsr %0" CR_TAB
-		  "lsr %0");
-
+	  return avr_asm_len ("swap %0" CR_TAB
+			      "lsr %0"  CR_TAB
+			      "lsr %0"  CR_TAB
+			      "andi %0,0x3", operands, plen, 4);
 	case 7:
-	  *len = 3;
-	  return ("bst %1,7" CR_TAB
-		  "clr %0"   CR_TAB
-		  "bld %0,0");
+	  return avr_asm_len ("bst %1,7" CR_TAB
+			      "clr %0"   CR_TAB
+			      "bld %0,0", operands, plen, 3);
 	}
     }
   else if (CONSTANT_P (operands[2]))
     fatal_insn ("internal compiler error.  Incorrect shift:", insn);
 
   out_shift_with_cnt ("lsr %0",
-		      insn, operands, len, 1);
+		      insn, operands, plen, 1);
   return "";
 }
 
 /* 16-bit logic shift right ((unsigned short)x >> i) */
 
 const char *
-lshrhi3_out (rtx_insn *insn, rtx operands[], int *len)
+lshrhi3_out (rtx_insn *insn, rtx operands[], int *plen)
 {
   if (CONST_INT_P (operands[2]))
     {
-      int scratch = (GET_CODE (PATTERN (insn)) == PARALLEL
-		     && XVECLEN (PATTERN (insn), 0) == 3
-		     && REG_P (operands[3]));
-      int ldi_ok = test_hard_reg_class (LD_REGS, operands[0]);
-      int k;
-      int *t = len;
+      bool scratch = (GET_CODE (PATTERN (insn)) == PARALLEL
+		      && XVECLEN (PATTERN (insn), 0) == 3
+		      && REG_P (operands[3]));
+      bool ldi_ok = test_hard_reg_class (LD_REGS, operands[0]);
 
-      if (!len)
-	len = &k;
+      if (plen)
+	*plen = 0;
 
       switch (INTVAL (operands[2]))
 	{
 	default:
 	  if (INTVAL (operands[2]) < 16)
 	    break;
-
-	  *len = 2;
-	  return ("clr %B0" CR_TAB
-		  "clr %A0");
+	  return avr_asm_len ("clr %B0" CR_TAB
+			      "clr %A0", operands, plen, 2);
 
 	case 4:
 	  if (optimize_size && scratch)
 	    break;  /* 5 */
 	  if (ldi_ok)
-	    {
-	      *len = 6;
-	      return ("swap %B0"      CR_TAB
-		      "swap %A0"      CR_TAB
-		      "andi %A0,0x0f" CR_TAB
-		      "eor %A0,%B0"   CR_TAB
-		      "andi %B0,0x0f" CR_TAB
-		      "eor %A0,%B0");
-	    }
+	    return avr_asm_len ("swap %B0"      CR_TAB
+				"swap %A0"      CR_TAB
+				"andi %A0,0x0f" CR_TAB
+				"eor %A0,%B0"   CR_TAB
+				"andi %B0,0x0f" CR_TAB
+				"eor %A0,%B0", operands, plen, 6);
 	  if (scratch)
-	    {
-	      *len = 7;
-	      return ("swap %B0"    CR_TAB
-		      "swap %A0"    CR_TAB
-		      "ldi %3,0x0f" CR_TAB
-		      "and %A0,%3"  CR_TAB
-		      "eor %A0,%B0" CR_TAB
-		      "and %B0,%3"  CR_TAB
-		      "eor %A0,%B0");
-	    }
+	    return avr_asm_len ("swap %B0"    CR_TAB
+				"swap %A0"    CR_TAB
+				"ldi %3,0x0f" CR_TAB
+				"and %A0,%3"  CR_TAB
+				"eor %A0,%B0" CR_TAB
+				"and %B0,%3"  CR_TAB
+				"eor %A0,%B0", operands, plen, 7);
 	  break;  /* optimize_size ? 6 : 8 */
 
 	case 5:
 	  if (optimize_size)
 	    break;  /* scratch ? 5 : 6 */
 	  if (ldi_ok)
-	    {
-	      *len = 8;
-	      return ("lsr %B0"       CR_TAB
-		      "ror %A0"       CR_TAB
-		      "swap %B0"      CR_TAB
-		      "swap %A0"      CR_TAB
-		      "andi %A0,0x0f" CR_TAB
-		      "eor %A0,%B0"   CR_TAB
-		      "andi %B0,0x0f" CR_TAB
-		      "eor %A0,%B0");
-	    }
+	    return avr_asm_len ("lsr %B0"       CR_TAB
+				"ror %A0"       CR_TAB
+				"swap %B0"      CR_TAB
+				"swap %A0"      CR_TAB
+				"andi %A0,0x0f" CR_TAB
+				"eor %A0,%B0"   CR_TAB
+				"andi %B0,0x0f" CR_TAB
+				"eor %A0,%B0", operands, plen, 8);
 	  if (scratch)
-	    {
-	      *len = 9;
-	      return ("lsr %B0"     CR_TAB
-		      "ror %A0"     CR_TAB
-		      "swap %B0"    CR_TAB
-		      "swap %A0"    CR_TAB
-		      "ldi %3,0x0f" CR_TAB
-		      "and %A0,%3"  CR_TAB
-		      "eor %A0,%B0" CR_TAB
-		      "and %B0,%3"  CR_TAB
-		      "eor %A0,%B0");
-	    }
+	    return avr_asm_len ("lsr %B0"     CR_TAB
+				"ror %A0"     CR_TAB
+				"swap %B0"    CR_TAB
+				"swap %A0"    CR_TAB
+				"ldi %3,0x0f" CR_TAB
+				"and %A0,%3"  CR_TAB
+				"eor %A0,%B0" CR_TAB
+				"and %B0,%3"  CR_TAB
+				"eor %A0,%B0", operands, plen, 9);
 	  break;  /* 10 */
 
 	case 6:
 	  if (optimize_size)
 	    break;  /* scratch ? 5 : 6 */
-	  *len = 9;
-	  return ("clr __tmp_reg__" CR_TAB
-		  "lsl %A0"         CR_TAB
-		  "rol %B0"         CR_TAB
-		  "rol __tmp_reg__" CR_TAB
-		  "lsl %A0"         CR_TAB
-		  "rol %B0"         CR_TAB
-		  "rol __tmp_reg__" CR_TAB
-		  "mov %A0,%B0"     CR_TAB
-		  "mov %B0,__tmp_reg__");
-
+	  return avr_asm_len ("clr __tmp_reg__" CR_TAB
+			      "lsl %A0"         CR_TAB
+			      "rol %B0"         CR_TAB
+			      "rol __tmp_reg__" CR_TAB
+			      "lsl %A0"         CR_TAB
+			      "rol %B0"         CR_TAB
+			      "rol __tmp_reg__" CR_TAB
+			      "mov %A0,%B0"     CR_TAB
+			      "mov %B0,__tmp_reg__", operands, plen, 9);
 	case 7:
-	  *len = 5;
-	  return ("lsl %A0"     CR_TAB
-		  "mov %A0,%B0" CR_TAB
-		  "rol %A0"     CR_TAB
-		  "sbc %B0,%B0" CR_TAB
-		  "neg %B0");
-
+	  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);
 	case 8:
-	  return *len = 2, ("mov %A0,%B1" CR_TAB
-			    "clr %B0");
-
+	  return avr_asm_len ("mov %A0,%B1" CR_TAB
+			      "clr %B0", operands, plen, 2);
 	case 9:
-	  *len = 3;
-	  return ("mov %A0,%B0" CR_TAB
-		  "clr %B0"     CR_TAB
-		  "lsr %A0");
-
+	  return avr_asm_len ("mov %A0,%B0" CR_TAB
+			      "clr %B0"     CR_TAB
+			      "lsr %A0", operands, plen, 3);
 	case 10:
-	  *len = 4;
-	  return ("mov %A0,%B0" CR_TAB
-		  "clr %B0"     CR_TAB
-		  "lsr %A0"     CR_TAB
-		  "lsr %A0");
-
+	  return avr_asm_len ("mov %A0,%B0" CR_TAB
+			      "clr %B0"     CR_TAB
+			      "lsr %A0"     CR_TAB
+			      "lsr %A0", operands, plen, 4);
 	case 11:
-	  *len = 5;
-	  return ("mov %A0,%B0" CR_TAB
-		  "clr %B0"     CR_TAB
-		  "lsr %A0"     CR_TAB
-		  "lsr %A0"     CR_TAB
-		  "lsr %A0");
-
+	  return avr_asm_len ("mov %A0,%B0" CR_TAB
+			      "clr %B0"     CR_TAB
+			      "lsr %A0"     CR_TAB
+			      "lsr %A0"     CR_TAB
+			      "lsr %A0", operands, plen, 5);
 	case 12:
 	  if (ldi_ok)
-	    {
-	      *len = 4;
-	      return ("mov %A0,%B0" CR_TAB
-		      "clr %B0"     CR_TAB
-		      "swap %A0"    CR_TAB
-		      "andi %A0,0x0f");
-	    }
-	  if (scratch)
-	    {
-	      *len = 5;
-	      return ("mov %A0,%B0" CR_TAB
-		      "clr %B0"     CR_TAB
-		      "swap %A0"    CR_TAB
-		      "ldi %3,0x0f" CR_TAB
-		      "and %A0,%3");
-	    }
-	  *len = 6;
-	  return ("mov %A0,%B0" CR_TAB
-		  "clr %B0"     CR_TAB
-		  "lsr %A0"     CR_TAB
-		  "lsr %A0"     CR_TAB
-		  "lsr %A0"     CR_TAB
-		  "lsr %A0");
-
+	    return avr_asm_len ("mov %A0,%B0" 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
+			   "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
+			   "clr %B0"     CR_TAB
+			   "lsr %A0"     CR_TAB
+			   "lsr %A0"     CR_TAB
+			   "lsr %A0"     CR_TAB
+			   "lsr %A0", operands, plen, 6);
 	case 13:
 	  if (ldi_ok)
-	    {
-	      *len = 5;
-	      return ("mov %A0,%B0" CR_TAB
-		      "clr %B0"     CR_TAB
-		      "swap %A0"    CR_TAB
-		      "lsr %A0"     CR_TAB
-		      "andi %A0,0x07");
-	    }
+	    return avr_asm_len ("mov %A0,%B0" CR_TAB
+				"clr %B0"     CR_TAB
+				"swap %A0"    CR_TAB
+				"lsr %A0"     CR_TAB
+				"andi %A0,0x07", operands, plen, 5);
 	  if (AVR_HAVE_MUL && scratch)
-	    {
-	      *len = 5;
-	      return ("ldi %3,0x08" CR_TAB
-		      "mul %B0,%3"  CR_TAB
-		      "mov %A0,r1"  CR_TAB
-		      "clr %B0"     CR_TAB
-		      "clr __zero_reg__");
-	    }
+	    return avr_asm_len ("ldi %3,0x08" CR_TAB
+				"mul %B0,%3"  CR_TAB
+				"mov %A0,r1"  CR_TAB
+				"clr %B0"     CR_TAB
+				"clr __zero_reg__", operands, plen, 5);
 	  if (optimize_size && scratch)
 	    break;  /* 5 */
 	  if (scratch)
-	    {
-	      *len = 6;
-	      return ("mov %A0,%B0" CR_TAB
-		      "clr %B0"     CR_TAB
-		      "swap %A0"    CR_TAB
-		      "lsr %A0"     CR_TAB
-		      "ldi %3,0x07" CR_TAB
-		      "and %A0,%3");
-	    }
-	  if (AVR_HAVE_MUL)
-	    {
-	      *len = 6;
-	      return ("set"        CR_TAB
-		      "bld r1,3"   CR_TAB
-		      "mul %B0,r1" CR_TAB
-		      "mov %A0,r1" CR_TAB
-		      "clr %B0"    CR_TAB
-		      "clr __zero_reg__");
-	    }
-	  *len = 7;
-	  return ("mov %A0,%B0" CR_TAB
-		  "clr %B0"     CR_TAB
-		  "lsr %A0"     CR_TAB
-		  "lsr %A0"     CR_TAB
-		  "lsr %A0"     CR_TAB
-		  "lsr %A0"     CR_TAB
-		  "lsr %A0");
-
+	    return avr_asm_len ("mov %A0,%B0" CR_TAB
+				"clr %B0"     CR_TAB
+				"swap %A0"    CR_TAB
+				"lsr %A0"     CR_TAB
+				"ldi %3,0x07" CR_TAB
+				"and %A0,%3", operands, plen, 6);
+	  return AVR_HAVE_MUL
+	    ? avr_asm_len ("set"        CR_TAB
+			   "bld r1,3"   CR_TAB
+			   "mul %B0,r1" CR_TAB
+			   "mov %A0,r1" CR_TAB
+			   "clr %B0"    CR_TAB
+			   "clr __zero_reg__", operands, plen, 6)
+	    : avr_asm_len ("mov %A0,%B0" CR_TAB
+			   "clr %B0"     CR_TAB
+			   "lsr %A0"     CR_TAB
+			   "lsr %A0"     CR_TAB
+			   "lsr %A0"     CR_TAB
+			   "lsr %A0"     CR_TAB
+			   "lsr %A0", operands, plen, 7);
 	case 14:
 	  if (AVR_HAVE_MUL && ldi_ok)
-	    {
-	      *len = 5;
-	      return ("ldi %A0,0x04" CR_TAB
-		      "mul %B0,%A0"  CR_TAB
-		      "mov %A0,r1"   CR_TAB
-		      "clr %B0"      CR_TAB
-		      "clr __zero_reg__");
-	    }
+	    return avr_asm_len ("ldi %A0,0x04" CR_TAB
+				"mul %B0,%A0"  CR_TAB
+				"mov %A0,r1"   CR_TAB
+				"clr %B0"      CR_TAB
+				"clr __zero_reg__", operands, plen, 5);
 	  if (AVR_HAVE_MUL && scratch)
-	    {
-	      *len = 5;
-	      return ("ldi %3,0x04" CR_TAB
-		      "mul %B0,%3"  CR_TAB
-		      "mov %A0,r1"  CR_TAB
-		      "clr %B0"     CR_TAB
-		      "clr __zero_reg__");
-	    }
+	    return avr_asm_len ("ldi %3,0x04" CR_TAB
+				"mul %B0,%3"  CR_TAB
+				"mov %A0,r1"  CR_TAB
+				"clr %B0"     CR_TAB
+				"clr __zero_reg__", operands, plen, 5);
 	  if (optimize_size && ldi_ok)
-	    {
-	      *len = 5;
-	      return ("mov %A0,%B0" CR_TAB
-		      "ldi %B0,6" "\n1:\t"
-		      "lsr %A0"     CR_TAB
-		      "dec %B0"     CR_TAB
-		      "brne 1b");
-	    }
+	    return avr_asm_len ("mov %A0,%B0" CR_TAB
+				"ldi %B0,6" "\n1:\t"
+				"lsr %A0"     CR_TAB
+				"dec %B0"     CR_TAB
+				"brne 1b", operands, plen, 5);
 	  if (optimize_size && scratch)
 	    break;  /* 5 */
-	  *len = 6;
-	  return ("clr %A0" CR_TAB
-		  "lsl %B0" CR_TAB
-		  "rol %A0" CR_TAB
-		  "lsl %B0" CR_TAB
-		  "rol %A0" CR_TAB
-		  "clr %B0");
-
+	  return avr_asm_len ("clr %A0" CR_TAB
+			      "lsl %B0" CR_TAB
+			      "rol %A0" CR_TAB
+			      "lsl %B0" CR_TAB
+			      "rol %A0" CR_TAB
+			      "clr %B0", operands, plen, 6);
 	case 15:
-	  *len = 4;
-	  return ("bst %B1,7" CR_TAB
-		  "clr %A0"   CR_TAB
-		  "clr %B0"   CR_TAB
-		  "bld %A0,0");
+	  return avr_asm_len ("bst %B1,7" CR_TAB
+			      "clr %A0"   CR_TAB
+			      "clr %B0"   CR_TAB
+			      "bld %A0,0", operands, plen, 4);
 	}
-      len = t;
     }
+
   out_shift_with_cnt ("lsr %B0" CR_TAB
-		      "ror %A0", insn, operands, len, 2);
+		      "ror %A0", insn, operands, plen, 2);
   return "";
 }
 
@@ -8004,15 +7767,15 @@ avr_out_lshrpsi3 (rtx_insn *insn, rtx *op, int *plen)
 /* 32-bit logic shift right ((unsigned int)x >> i) */
 
 const char *
-lshrsi3_out (rtx_insn *insn, rtx operands[], int *len)
+lshrsi3_out (rtx_insn *insn, rtx operands[], int *plen)
 {
   if (CONST_INT_P (operands[2]))
     {
-      int k;
-      int *t = len;
+      int reg0 = true_regnum (operands[0]);
+      int reg1 = true_regnum (operands[1]);
 
-      if (!len)
-	len = &k;
+      if (plen)
+	*plen = 0;
 
       switch (INTVAL (operands[2]))
 	{
@@ -8020,79 +7783,61 @@ lshrsi3_out (rtx_insn *insn, rtx operands[], int *len)
 	  if (INTVAL (operands[2]) < 32)
 	    break;
 
-	  if (AVR_HAVE_MOVW)
-	    return *len = 3, ("clr %D0" CR_TAB
-			      "clr %C0" CR_TAB
-			      "movw %A0,%C0");
-	  *len = 4;
-	  return ("clr %D0" CR_TAB
-		  "clr %C0" CR_TAB
-		  "clr %B0" CR_TAB
-		  "clr %A0");
-
+	  return AVR_HAVE_MOVW
+	    ? avr_asm_len ("clr %D0" CR_TAB
+			   "clr %C0" CR_TAB
+			   "movw %A0,%C0", operands, plen, 3)
+	    : avr_asm_len ("clr %D0" CR_TAB
+			   "clr %C0" CR_TAB
+			   "clr %B0" CR_TAB
+			   "clr %A0", operands, plen, 4);
 	case 8:
-	  {
-	    int reg0 = true_regnum (operands[0]);
-	    int reg1 = true_regnum (operands[1]);
-	    *len = 4;
-	    if (reg0 <= reg1)
-	      return ("mov %A0,%B1" CR_TAB
-		      "mov %B0,%C1" CR_TAB
-		      "mov %C0,%D1" CR_TAB
-		      "clr %D0");
-	    else
-	      return ("clr %D0"     CR_TAB
-		      "mov %C0,%D1" CR_TAB
-		      "mov %B0,%C1" CR_TAB
-		      "mov %A0,%B1");
-	  }
-
+	  return reg0 <= reg1
+	    ? avr_asm_len ("mov %A0,%B1" CR_TAB
+			   "mov %B0,%C1" CR_TAB
+			   "mov %C0,%D1" CR_TAB
+			   "clr %D0", operands, plen, 4)
+	    : avr_asm_len ("clr %D0"     CR_TAB
+			   "mov %C0,%D1" CR_TAB
+			   "mov %B0,%C1" CR_TAB
+			   "mov %A0,%B1", operands, plen, 4);
 	case 16:
-	  {
-	    int reg0 = true_regnum (operands[0]);
-	    int reg1 = true_regnum (operands[1]);
-
-	    if (reg0 == reg1 + 2)
-	      return *len = 2, ("clr %C0"     CR_TAB
-				"clr %D0");
-	    if (AVR_HAVE_MOVW)
-	      return *len = 3, ("movw %A0,%C1" CR_TAB
-				"clr %C0"      CR_TAB
-				"clr %D0");
-	    else
-	      return *len = 4, ("mov %B0,%D1" CR_TAB
-				"mov %A0,%C1" CR_TAB
-				"clr %C0"     CR_TAB
-				"clr %D0");
-	  }
-
+	  if (reg0 == reg1 + 2)
+	    return avr_asm_len ("clr %C0"  CR_TAB
+				"clr %D0", operands, plen, 2);
+	  return AVR_HAVE_MOVW
+	    ? avr_asm_len ("movw %A0,%C1" CR_TAB
+			   "clr %C0"      CR_TAB
+			   "clr %D0", operands, plen, 3)
+	    : avr_asm_len ("mov %B0,%D1" CR_TAB
+			   "mov %A0,%C1" CR_TAB
+			   "clr %C0"     CR_TAB
+			   "clr %D0", operands, plen, 4);
 	case 24:
-	  return *len = 4, ("mov %A0,%D1" CR_TAB
-			    "clr %B0"     CR_TAB
-			    "clr %C0"     CR_TAB
-			    "clr %D0");
-
+	  return avr_asm_len ("mov %A0,%D1" CR_TAB
+			      "clr %B0"     CR_TAB
+			      "clr %C0"     CR_TAB
+			      "clr %D0", operands, plen, 4);
 	case 31:
-	  if (AVR_HAVE_MOVW)
-	    return *len = 5, ("bst %D1,7"    CR_TAB
-			      "clr %A0"      CR_TAB
-			      "clr %B0"      CR_TAB
-			      "movw %C0,%A0" CR_TAB
-			      "bld %A0,0");
-	  *len = 6;
-	  return ("bst %D1,7" CR_TAB
-		  "clr %A0"   CR_TAB
-		  "clr %B0"   CR_TAB
-		  "clr %C0"   CR_TAB
-		  "clr %D0"   CR_TAB
-		  "bld %A0,0");
-	}
-      len = t;
+	  return AVR_HAVE_MOVW
+	    ? avr_asm_len ("bst %D1,7"    CR_TAB
+			   "clr %A0"      CR_TAB
+			   "clr %B0"      CR_TAB
+			   "movw %C0,%A0" CR_TAB
+			   "bld %A0,0", operands, plen, 5)
+	    : avr_asm_len ("bst %D1,7" CR_TAB
+			   "clr %A0"   CR_TAB
+			   "clr %B0"   CR_TAB
+			   "clr %C0"   CR_TAB
+			   "clr %D0"   CR_TAB
+			   "bld %A0,0", operands, plen, 6);
+	} // switch
     }
+
   out_shift_with_cnt ("lsr %D0" CR_TAB
 		      "ror %C0" CR_TAB
 		      "ror %B0" CR_TAB
-		      "ror %A0", insn, operands, len, 4);
+		      "ror %A0", insn, operands, plen, 4);
   return "";
 }
 
diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md
index d0d78ba818a..04d838ef8a7 100644
--- a/gcc/config/avr/avr.md
+++ b/gcc/config/avr/avr.md
@@ -5147,9 +5147,9 @@ (define_insn "*ashl<mode>3"
    (set_attr "adjust_len" "ashlqi")])
 
 (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,K,n,Qm")))]
+  [(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")))]
   ""
   "#"
   "&& reload_completed"
@@ -5159,15 +5159,15 @@ (define_insn_and_split "ashl<mode>3"
               (clobber (reg:CC REG_CC))])])
 
 (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,K,n,Qm")))
+  [(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")))
    (clobber (reg:CC REG_CC))]
   "reload_completed"
   {
     return ashlhi3_out (insn, operands, NULL);
   }
-  [(set_attr "length" "6,0,2,2,4,10,10")
+  [(set_attr "length" "6,0,2,3,4,10,10")
    (set_attr "adjust_len" "ashlhi")])
 
 
@@ -5257,9 +5257,9 @@ (define_peephole2
 ;; "ashlsq3"  "ashlusq3"
 ;; "ashlsa3"  "ashlusa3"
 (define_insn_and_split "ashl<mode>3"
-  [(set (match_operand:ALL4 0 "register_operand"                "=r,r,r,r,r,r,r")
-        (ashift: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,K,n,Qm")))]
+  [(set (match_operand:ALL4 0 "register_operand"                "=r,r,r,r    ,r,r,r")
+        (ashift: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")))]
   ""
   "#"
   "&& reload_completed"
@@ -5269,15 +5269,15 @@ (define_insn_and_split "ashl<mode>3"
               (clobber (reg:CC REG_CC))])])
 
 (define_insn "*ashl<mode>3"
-  [(set (match_operand:ALL4 0 "register_operand"                "=r,r,r,r,r,r,r")
-        (ashift: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,K,n,Qm")))
+  [(set (match_operand:ALL4 0 "register_operand"                "=r,r,r,r    ,r,r,r")
+        (ashift: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")))
    (clobber (reg:CC REG_CC))]
   "reload_completed"
   {
     return ashlsi3_out (insn, operands, NULL);
   }
-  [(set_attr "length" "8,0,4,4,8,10,12")
+  [(set_attr "length" "8,0,4,5,8,10,12")
    (set_attr "adjust_len" "ashlsi")])
 
 ;; Optimize if a scratch register from LD_REGS happens to be available.
@@ -5354,10 +5354,10 @@ (define_peephole2
 ;; "*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,K,n")))
-   (clobber (match_scratch:QI 3                               "=X,X,X,X,&d"))]
+  [(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"
@@ -5368,10 +5368,10 @@ (define_insn_and_split "*ashl<mode>3_const_split"
               (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,K,n")))
-   (clobber (match_scratch:QI 3                               "=X,X,X,X,&d"))
+  [(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"))
    (clobber (reg:CC REG_CC))]
   "reload_completed"
   {
@@ -5397,10 +5397,10 @@ (define_peephole2
 ;; "*ashlsq3_const"  "*ashlusq3_const"
 ;; "*ashlsa3_const"  "*ashlusa3_const"
 (define_insn_and_split "*ashl<mode>3_const_split"
-  [(set (match_operand:ALL4 0 "register_operand"              "=r,r,r,r")
-        (ashift:ALL4 (match_operand:ALL4 1 "register_operand"  "0,0,r,0")
-                     (match_operand:QI 2 "const_int_operand"   "L,P,O,n")))
-   (clobber (match_scratch:QI 3                               "=X,X,X,&d"))]
+  [(set (match_operand:ALL4 0 "register_operand"              "=r,r,r    ,r")
+        (ashift: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"
@@ -5411,16 +5411,16 @@ (define_insn_and_split "*ashl<mode>3_const_split"
               (clobber (reg:CC REG_CC))])])
 
 (define_insn "*ashl<mode>3_const"
-  [(set (match_operand:ALL4 0 "register_operand"              "=r,r,r,r")
-        (ashift:ALL4 (match_operand:ALL4 1 "register_operand"  "0,0,r,0")
-                     (match_operand:QI 2 "const_int_operand"   "L,P,O,n")))
-   (clobber (match_scratch:QI 3                               "=X,X,X,&d"))
+  [(set (match_operand:ALL4 0 "register_operand"              "=r,r,r    ,r")
+        (ashift: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"))
    (clobber (reg:CC REG_CC))]
   "reload_completed"
   {
     return ashlsi3_out (insn, operands, NULL);
   }
-  [(set_attr "length" "0,4,4,10")
+  [(set_attr "length" "0,4,5,10")
    (set_attr "adjust_len" "ashlsi")])
 
 (define_expand "ashlpsi3"
@@ -5451,10 +5451,10 @@ (define_expand "ashlpsi3"
   })
 
 (define_insn_and_split "*ashlpsi3_split"
-  [(set (match_operand:PSI 0 "register_operand"             "=r,r,r,r")
-        (ashift:PSI (match_operand:PSI 1 "register_operand"  "0,0,r,0")
-                    (match_operand:QI 2 "nonmemory_operand"  "r,P,O,n")))
-   (clobber (match_scratch:QI 3                             "=X,X,X,&d"))]
+  [(set (match_operand:PSI 0 "register_operand"             "=r,r,r    ,r")
+        (ashift:PSI (match_operand:PSI 1 "register_operand"  "0,0,r    ,0")
+                    (match_operand:QI 2 "nonmemory_operand"  "r,P,O C23,n")))
+   (clobber (match_scratch:QI 3                             "=X,X,X    ,&d"))]
   ""
   "#"
   "&& reload_completed"
@@ -5465,10 +5465,10 @@ (define_insn_and_split "*ashlpsi3_split"
               (clobber (reg:CC REG_CC))])])
 
 (define_insn "*ashlpsi3"
-  [(set (match_operand:PSI 0 "register_operand"             "=r,r,r,r")
-        (ashift:PSI (match_operand:PSI 1 "register_operand"  "0,0,r,0")
-                    (match_operand:QI 2 "nonmemory_operand"  "r,P,O,n")))
-   (clobber (match_scratch:QI 3                             "=X,X,X,&d"))
+  [(set (match_operand:PSI 0 "register_operand"             "=r,r,r    ,r")
+        (ashift:PSI (match_operand:PSI 1 "register_operand"  "0,0,r    ,0")
+                    (match_operand:QI 2 "nonmemory_operand"  "r,P,O C23,n")))
+   (clobber (match_scratch:QI 3                             "=X,X,X    ,&d"))
    (clobber (reg:CC REG_CC))]
   "reload_completed"
   {
@@ -5509,34 +5509,34 @@ (define_insn "*ashr<mode>3"
 ;; "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,K,n,Qm")))]
+  [(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")))]
   ""
   "#"
   "&& reload_completed"
-  [(parallel [(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,K,n,Qm")))
+  [(parallel [(set (match_dup 0)
+                   (ashiftrt:ALL2 (match_dup 1)
+                                  (match_dup 2)))
               (clobber (reg:CC REG_CC))])])
 
 (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,K,n,Qm")))
+  [(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")))
    (clobber (reg:CC REG_CC))]
   "reload_completed"
   {
     return ashrhi3_out (insn, operands, NULL);
   }
-  [(set_attr "length" "6,0,2,4,4,10,10")
+  [(set_attr "length" "6,0,2,5,4,10,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,n")))
-   (clobber (match_scratch:QI 3                                 "=X,X,X,X,&d"))]
+  [(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"))]
   ""
   "#"
   "&& reload_completed"
@@ -5547,10 +5547,10 @@ (define_insn_and_split "ashrpsi3"
               (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,n")))
-   (clobber (match_scratch:QI 3                                 "=X,X,X,X,&d"))
+  [(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"))
    (clobber (reg:CC REG_CC))]
   "reload_completed"
   {
@@ -5562,9 +5562,9 @@ (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,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,0,r    ,0,0,0")
+                       (match_operand:QI 2 "nop_general_operand"   "r,L,P,O C31,K,n,Qm")))]
   ""
   "#"
   "&& reload_completed"
@@ -5574,9 +5574,9 @@ (define_insn_and_split "ashr<mode>3"
               (clobber (reg:CC REG_CC))])])
 
 (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,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,0,r    ,0,0,0")
+                       (match_operand:QI 2 "nop_general_operand"   "r,L,P,O C31,K,n,Qm")))
    (clobber (reg:CC REG_CC))]
   "reload_completed"
   {
@@ -5604,10 +5604,10 @@ (define_peephole2
 ;; "*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,K,n")))
-   (clobber (match_scratch:QI 3                                 "=X,X,X,X,&d"))]
+  [(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"
@@ -5618,10 +5618,10 @@ (define_insn_and_split "*ashr<mode>3_const_split"
               (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,K,n")))
-   (clobber (match_scratch:QI 3                                 "=X,X,X,X,&d"))
+  [(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"))
    (clobber (reg:CC REG_CC))]
   "reload_completed"
   {
@@ -5647,10 +5647,10 @@ (define_peephole2
 ;; "*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,n")))
-   (clobber (match_scratch:QI 3                                 "=X,X,X,&d"))]
+  [(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"
@@ -5661,10 +5661,10 @@ (define_insn_and_split "*ashr<mode>3_const_split"
               (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,n")))
-   (clobber (match_scratch:QI 3                                 "=X,X,X,&d"))
+  [(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"))
    (clobber (reg:CC REG_CC))]
   "reload_completed"
   {
diff --git a/gcc/testsuite/gcc.target/avr/torture/shift-l-u16.c b/gcc/testsuite/gcc.target/avr/torture/shift-l-u16.c
new file mode 100644
index 00000000000..191c07bd770
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/torture/shift-l-u16.c
@@ -0,0 +1,25 @@
+/* { dg-do run } */
+/* { dg-additional-options { -std=gnu99 -fwrapv } } */
+
+#define OP <<
+#define BITS 16
+typedef __UINT16_TYPE__ T;
+
+#include "test-shift.h"
+
+const AS T vals[] =
+  {
+    1, 0x01a2, 0x7f32, 0x7e81, 0x7654
+  };
+  
+int main (void)
+{
+  for (int i = 0; i < ARRAY_SIZE (vals); ++i)
+    {
+      testx (vals[i]);
+      testx (-vals[i]);
+    }
+  testx (0x8000);
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/avr/torture/shift-l-u24.c b/gcc/testsuite/gcc.target/avr/torture/shift-l-u24.c
new file mode 100644
index 00000000000..4fd66f3f621
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/torture/shift-l-u24.c
@@ -0,0 +1,25 @@
+/* { dg-do run } */
+/* { dg-additional-options { -std=gnu99 -fwrapv } } */
+
+#define OP <<
+#define BITS 24
+typedef __uint24 T;
+
+#include "test-shift.h"
+
+const AS T vals[] =
+  {
+    1, 0x01a273, 0x7f324b, 0x7e801, 0x765432
+  };
+  
+int main (void)
+{
+  for (int i = 0; i < ARRAY_SIZE (vals); ++i)
+    {
+      testx (vals[i]);
+      testx (-vals[i]);
+    }
+  testx (0x800000);
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/avr/torture/shift-l-u32.c b/gcc/testsuite/gcc.target/avr/torture/shift-l-u32.c
new file mode 100644
index 00000000000..8c374f0c399
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/torture/shift-l-u32.c
@@ -0,0 +1,25 @@
+/* { dg-do run } */
+/* { dg-additional-options { -std=gnu99 -fwrapv } } */
+
+#define OP <<
+#define BITS 32
+typedef __UINT32_TYPE__ T;
+
+#include "test-shift.h"
+
+const AS T vals[] =
+  {
+    1, 0x01a273b9, 0x7f324b01, 0x7e80102, 0x76543219
+  };
+  
+int main (void)
+{
+  for (int i = 0; i < ARRAY_SIZE (vals); ++i)
+    {
+      testx (vals[i]);
+      testx (-vals[i]);
+    }
+  testx (0x80000000);
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/avr/torture/shift-l-u8.c b/gcc/testsuite/gcc.target/avr/torture/shift-l-u8.c
new file mode 100644
index 00000000000..d279dd1ae33
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/torture/shift-l-u8.c
@@ -0,0 +1,25 @@
+/* { dg-do run } */
+/* { dg-additional-options { -std=gnu99 -fwrapv } } */
+
+#define OP <<
+#define BITS 8
+typedef __UINT8_TYPE__ T;
+
+#include "test-shift.h"
+
+const AS T vals[] =
+  {
+    1, 0x55, 0x7f, 0x6e, 0x54
+  };
+  
+int main (void)
+{
+  for (int i = 0; i < ARRAY_SIZE (vals); ++i)
+    {
+      testx (vals[i]);
+      testx (-vals[i]);
+    }
+  testx (0x80);
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/avr/torture/shift-r-i16.c b/gcc/testsuite/gcc.target/avr/torture/shift-r-i16.c
new file mode 100644
index 00000000000..80546ef1c87
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/torture/shift-r-i16.c
@@ -0,0 +1,25 @@
+/* { dg-do run } */
+/* { dg-additional-options { -std=gnu99 -fwrapv } } */
+
+#define OP >>
+#define BITS 16
+typedef __INT16_TYPE__ T;
+
+#include "test-shift.h"
+
+const AS T vals[] =
+  {
+    1, 0x01a2, 0x7f32, 0x7e81, 0x7654
+  };
+  
+int main (void)
+{
+  for (int i = 0; i < ARRAY_SIZE (vals); ++i)
+    {
+      testx (vals[i]);
+      testx (-vals[i]);
+    }
+  testx ((T) 0x8000);
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/avr/torture/shift-r-i24.c b/gcc/testsuite/gcc.target/avr/torture/shift-r-i24.c
new file mode 100644
index 00000000000..45e1b0bab88
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/torture/shift-r-i24.c
@@ -0,0 +1,25 @@
+/* { dg-do run } */
+/* { dg-additional-options { -std=gnu99 -fwrapv } } */
+
+#define OP >>
+#define BITS 24
+typedef __int24 T;
+
+#include "test-shift.h"
+
+const AS T vals[] =
+  {
+    1, 0x01a273, 0x7f324b, 0x7e801, 0x765432
+  };
+  
+int main (void)
+{
+  for (int i = 0; i < ARRAY_SIZE (vals); ++i)
+    {
+      testx (vals[i]);
+      testx (-vals[i]);
+    }
+  testx ((T) 0x800000);
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/avr/torture/shift-r-i32.c b/gcc/testsuite/gcc.target/avr/torture/shift-r-i32.c
new file mode 100644
index 00000000000..674878e43f3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/torture/shift-r-i32.c
@@ -0,0 +1,25 @@
+/* { dg-do run } */
+/* { dg-additional-options { -std=gnu99 -fwrapv } } */
+
+#define OP >>
+#define BITS 32
+typedef __INT32_TYPE__ T;
+
+#include "test-shift.h"
+
+const AS T vals[] =
+  {
+    1, 0x01a273b9, 0x7f324b01, 0x7e80102, 0x76543219
+  };
+  
+int main (void)
+{
+  for (int i = 0; i < ARRAY_SIZE (vals); ++i)
+    {
+      testx (vals[i]);
+      testx (-vals[i]);
+    }
+  testx (0x80000000);
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/avr/torture/shift-r-i8.c b/gcc/testsuite/gcc.target/avr/torture/shift-r-i8.c
new file mode 100644
index 00000000000..f3243dc6d45
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/torture/shift-r-i8.c
@@ -0,0 +1,25 @@
+/* { dg-do run } */
+/* { dg-additional-options { -std=gnu99 -fwrapv } } */
+
+#define OP >>
+#define BITS 8
+typedef __INT8_TYPE__ T;
+
+#include "test-shift.h"
+
+const AS T vals[] =
+  {
+    1, 0x72, 0x32, 0x6f, 0x76
+  };
+  
+int main (void)
+{
+  for (int i = 0; i < ARRAY_SIZE (vals); ++i)
+    {
+      testx (vals[i]);
+      testx (-vals[i]);
+    }
+  testx ((T) 0x80);
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/avr/torture/shift-r-u16.c b/gcc/testsuite/gcc.target/avr/torture/shift-r-u16.c
new file mode 100644
index 00000000000..9e358a83d44
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/torture/shift-r-u16.c
@@ -0,0 +1,25 @@
+/* { dg-do run } */
+/* { dg-additional-options { -std=gnu99 -fwrapv } } */
+
+#define OP >>
+#define BITS 16
+typedef __UINT16_TYPE__ T;
+
+#include "test-shift.h"
+
+const AS T vals[] =
+  {
+    1, 0x01a2, 0x7f32, 0x7e81, 0x7654
+  };
+  
+int main (void)
+{
+  for (int i = 0; i < ARRAY_SIZE (vals); ++i)
+    {
+      testx (vals[i]);
+      testx (-vals[i]);
+    }
+  testx (0x8000);
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/avr/torture/shift-r-u24.c b/gcc/testsuite/gcc.target/avr/torture/shift-r-u24.c
new file mode 100644
index 00000000000..6acdd4e2672
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/torture/shift-r-u24.c
@@ -0,0 +1,25 @@
+/* { dg-do run } */
+/* { dg-additional-options { -std=gnu99 -fwrapv } } */
+
+#define OP >>
+#define BITS 24
+typedef __uint24 T;
+
+#include "test-shift.h"
+
+const AS T vals[] =
+  {
+    1, 0x01a273, 0x7f324b, 0x7e801, 0x765432
+  };
+  
+int main (void)
+{
+  for (int i = 0; i < ARRAY_SIZE (vals); ++i)
+    {
+      testx (vals[i]);
+      testx (-vals[i]);
+    }
+  testx (0x800000);
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/avr/torture/shift-r-u32.c b/gcc/testsuite/gcc.target/avr/torture/shift-r-u32.c
new file mode 100644
index 00000000000..af55e547632
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/torture/shift-r-u32.c
@@ -0,0 +1,25 @@
+/* { dg-do run } */
+/* { dg-additional-options { -std=gnu99 -fwrapv } } */
+
+#define OP >>
+#define BITS 32
+typedef __UINT32_TYPE__ T;
+
+#include "test-shift.h"
+
+const AS T vals[] =
+  {
+    1, 0x01a273b9, 0x7f324b01, 0x7e80102, 0x76543219
+  };
+  
+int main (void)
+{
+  for (int i = 0; i < ARRAY_SIZE (vals); ++i)
+    {
+      testx (vals[i]);
+      testx (-vals[i]);
+    }
+  testx (0x80000000);
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/avr/torture/shift-r-u8.c b/gcc/testsuite/gcc.target/avr/torture/shift-r-u8.c
new file mode 100644
index 00000000000..e0bbb1e5194
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/torture/shift-r-u8.c
@@ -0,0 +1,25 @@
+/* { dg-do run } */
+/* { dg-additional-options { -std=gnu99 -fwrapv } } */
+
+#define OP >>
+#define BITS 8
+typedef __UINT8_TYPE__ T;
+
+#include "test-shift.h"
+
+const AS T vals[] =
+  {
+    1, 0x55, 0x7f, 0x78, 0x54
+  };
+  
+int main (void)
+{
+  for (int i = 0; i < ARRAY_SIZE (vals); ++i)
+    {
+      testx (vals[i]);
+      testx (-vals[i]);
+    }
+  testx (0x80);
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/avr/torture/test-shift.h b/gcc/testsuite/gcc.target/avr/torture/test-shift.h
new file mode 100644
index 00000000000..68305e2b2b6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/torture/test-shift.h
@@ -0,0 +1,125 @@
+#define NI __attribute__((noipa))
+
+NI
+T shiftN (T x, int n)
+{
+  return x OP n;
+}
+
+#define MK_FUN(N)				\
+  NI						\
+  T shift_##N##_r22 (T x)			\
+  {						\
+    return x OP N;				\
+  }						\
+  						\
+  NI						\
+  T shift_##N##_r20 (T x)			\
+  {						\
+    register T r20 __asm("20") = x OP N;	\
+    __asm ("nop ; %0" : "+r" (r20));		\
+    return r20;					\
+  }						\
+						\
+  NI						\
+  T shift_##N##_r24 (T x)			\
+  {						\
+    register T r24 __asm("24") = x OP N;	\
+    __asm ("nop ; %0" : "+r" (r24));		\
+    return r24;					\
+  }						\
+
+MK_FUN (1)
+MK_FUN (2)
+MK_FUN (3)
+MK_FUN (4)
+MK_FUN (5)
+MK_FUN (6)
+MK_FUN (7)
+
+#if BITS > 8
+MK_FUN (8)
+MK_FUN (9)
+MK_FUN (10)
+MK_FUN (11)
+MK_FUN (12)
+MK_FUN (13)
+MK_FUN (14)
+MK_FUN (15)
+#endif
+
+#if BITS > 16
+MK_FUN (16)
+MK_FUN (17)
+MK_FUN (18)
+MK_FUN (19)
+MK_FUN (20)
+MK_FUN (21)
+MK_FUN (22)
+MK_FUN (23)
+#endif
+
+#if BITS > 24
+MK_FUN (24)
+MK_FUN (25)
+MK_FUN (26)
+MK_FUN (27)
+MK_FUN (28)
+MK_FUN (29)
+MK_FUN (30)
+MK_FUN (31)
+#endif
+
+#define ARRAY_SIZE(X) ((int) (sizeof (X) / sizeof (*X)))
+
+#ifdef __FLASH
+#define AS __flash
+#else
+#define AS /* empty */
+#endif
+
+typedef T (*fun_t) (T);
+
+typedef struct
+{
+  fun_t f[3];
+} fun3_t;
+
+#define FN(N) { { shift_##N##_r20, shift_##N##_r22, shift_##N##_r24 } }
+
+const AS fun3_t funcs[] =
+  {
+    FN (1), FN (2), FN (3), FN (4), FN (5), FN (6), FN (7),
+#if BITS > 8
+    FN (8), FN (9), FN (10), FN (11), FN (12), FN (13), FN (14), FN (15),
+#endif
+#if BITS > 16
+    FN (16), FN (17), FN (18), FN (19), FN (20), FN (21), FN (22), FN (23),
+#endif
+#if BITS > 24
+    FN (24), FN (25), FN (26), FN (27), FN (28), FN (29), FN (30), FN (31),
+#endif
+  };
+
+void test1 (fun_t fun, T x, int n)
+{
+  T res = shiftN (x, n);
+  if (res != fun (x))
+    __builtin_abort ();
+}
+
+void testx (T x)
+{
+  for (int i = 0; i < ARRAY_SIZE (funcs); ++i)
+    {
+      const int n = 1 + i;
+      const T res = shiftN (x, n);
+
+      for (int j = 0; j < ARRAY_SIZE (funcs[i].f); ++j)
+	{
+	  fun_t f = funcs[i].f[j];
+	  if (f (x) != res)
+	    __builtin_abort ();
+	}
+    }
+}

Reply via email to