https://gcc.gnu.org/g:9f7b323caab2215042df0ab0f4eef251c54128fc

commit r15-5467-g9f7b323caab2215042df0ab0f4eef251c54128fc
Author: Georg-Johann Lay <a...@gjlay.de>
Date:   Mon Nov 18 17:35:33 2024 +0100

    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-u24.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:
---
 gcc/config/avr/avr.cc                              | 1531 ++++++++------------
 gcc/config/avr/avr.md                              |  158 +-
 gcc/testsuite/gcc.target/avr/torture/shift-l-u16.c |   25 +
 gcc/testsuite/gcc.target/avr/torture/shift-l-u24.c |   25 +
 gcc/testsuite/gcc.target/avr/torture/shift-l-u32.c |   25 +
 gcc/testsuite/gcc.target/avr/torture/shift-l-u8.c  |   25 +
 gcc/testsuite/gcc.target/avr/torture/shift-r-i16.c |   25 +
 gcc/testsuite/gcc.target/avr/torture/shift-r-i24.c |   25 +
 gcc/testsuite/gcc.target/avr/torture/shift-r-i32.c |   25 +
 gcc/testsuite/gcc.target/avr/torture/shift-r-i8.c  |   25 +
 gcc/testsuite/gcc.target/avr/torture/shift-r-u16.c |   25 +
 gcc/testsuite/gcc.target/avr/torture/shift-r-u24.c |   25 +
 gcc/testsuite/gcc.target/avr/torture/shift-r-u32.c |   25 +
 gcc/testsuite/gcc.target/avr/torture/shift-r-u8.c  |   25 +
 gcc/testsuite/gcc.target/avr/torture/test-shift.h  |  125 ++
 15 files changed, 1142 insertions(+), 972 deletions(-)

diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc
index 0a9d26af0755..4ad07acd789b 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 d0d78ba818a0..04d838ef8a72 100644
--- a/gcc/config/avr/avr.md
+++ b/gcc/config/avr/avr.md
@@ -5147,9 +5147,9 @@
    (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 @@
               (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 @@
 ;; "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 @@
               (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 @@
 ;; "*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 @@
               (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 @@
 ;; "*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 @@
               (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_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 @@
               (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 @@
 ;; "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 @@
               (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 @@
 ;; "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 @@
               (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 @@
 ;; "*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 @@
               (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 @@
 ;; "*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 @@
               (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 000000000000..191c07bd7707
--- /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 000000000000..4fd66f3f621b
--- /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 000000000000..8c374f0c3995
--- /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 000000000000..d279dd1ae33e
--- /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 000000000000..80546ef1c876
--- /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 000000000000..45e1b0bab883
--- /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 000000000000..674878e43f3d
--- /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 000000000000..f3243dc6d454
--- /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 000000000000..9e358a83d44e
--- /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 000000000000..6acdd4e2672d
--- /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 000000000000..af55e5476324
--- /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 000000000000..e0bbb1e5194a
--- /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 000000000000..68305e2b2b6a
--- /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