public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Alexander Binzberger <alexander.binzberger@gmail.com>
To: gcc-patches@gcc.gnu.org
Subject: [PATCH] improved const shifts for AVR targets
Date: Tue, 4 Oct 2022 19:06:21 +0200	[thread overview]
Message-ID: <CAFFmr-7NZef+QOtv2rzcvu4Sc66sTsikGf_gju_fFgGGwi0m_w@mail.gmail.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 71798 bytes --]

Hi,
recently I used some arduino uno for a project and realized some areas
which do not output optimal asm code. Especially around shifts and function
calls.
With this as motivation and hacktoberfest I started patching things.
Since patch files do not provide a good overview and I hope for a
"hacktoberfest-accepted" label on the PR on github I also opened it there:
https://github.com/gcc-mirror/gcc/pull/73

This patch improves shifts with const right hand operand. While 8bit and
16bit shifts where mostly fine 24bit and 32bit where not handled well.

Testing
I checked output with a local installation of compiler explorer in asm and
a tiny unit test comparing shifts with mul/div by 2.
I however did not write any testcases in gcc for it.

Target
This patch is only targeting atmel avr family of chips.

Changelog
improved const shifts for AVR targets

Patch
-----
diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc
index 4ed390e4cf9..c7b70812d5c 100644
--- a/gcc/config/avr/avr.cc
+++ b/gcc/config/avr/avr.cc
@@ -6043,9 +6043,6 @@ out_shift_with_cnt (const char *templ, rtx_insn
*insn, rtx operands[],
   op[2] = operands[2];
   op[3] = operands[3];

-  if (plen)
-    *plen = 0;
-
   if (CONST_INT_P (operands[2]))
     {
       /* Operand 3 is a scratch register if this is a
@@ -6150,96 +6147,68 @@ 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;
-
-      if (!len)
- len = &k;
-
       switch (INTVAL (operands[2]))
  {
  default:
   if (INTVAL (operands[2]) < 8)
     break;

-  *len = 1;
-  return "clr %0";
-
- 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");
+    return avr_asm_len ("clr %0", operands, plen, 1);

  case 4:
   if (test_hard_reg_class (LD_REGS, operands[0]))
     {
-      *len = 2;
-      return ("swap %0" CR_TAB
-      "andi %0,0xf0");
+        return avr_asm_len ("swap %0" CR_TAB
+          "andi %0,0xf0", operands, plen, 2);
     }
-  *len = 4;
-  return ("lsl %0" CR_TAB
+    return avr_asm_len ("lsl %0" CR_TAB
   "lsl %0" CR_TAB
   "lsl %0" CR_TAB
-  "lsl %0");
+      "lsl %0", operands, plen, 4);

  case 5:
   if (test_hard_reg_class (LD_REGS, operands[0]))
     {
-      *len = 3;
-      return ("swap %0" CR_TAB
+        return avr_asm_len ("swap %0" CR_TAB
       "lsl %0"  CR_TAB
-      "andi %0,0xe0");
+          "andi %0,0xe0", operands, plen, 3);
     }
-  *len = 5;
-  return ("lsl %0" CR_TAB
+    return avr_asm_len ("lsl %0" CR_TAB
   "lsl %0" CR_TAB
   "lsl %0" CR_TAB
   "lsl %0" CR_TAB
-  "lsl %0");
+      "lsl %0", operands, plen, 5);

  case 6:
   if (test_hard_reg_class (LD_REGS, operands[0]))
     {
-      *len = 4;
-      return ("swap %0" CR_TAB
+        return avr_asm_len ("swap %0" CR_TAB
       "lsl %0"  CR_TAB
       "lsl %0"  CR_TAB
-      "andi %0,0xc0");
+          "andi %0,0xc0", operands, plen, 4);
     }
-  *len = 6;
-  return ("lsl %0" CR_TAB
+    return avr_asm_len ("lsl %0" CR_TAB
   "lsl %0" CR_TAB
   "lsl %0" CR_TAB
   "lsl %0" CR_TAB
   "lsl %0" CR_TAB
-  "lsl %0");
+      "lsl %0", operands, plen, 6);

  case 7:
-  *len = 3;
-  return ("ror %0" CR_TAB
+    return avr_asm_len ("ror %0" CR_TAB
   "clr %0" CR_TAB
-  "ror %0");
+      "ror %0", 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 "";
 }

@@ -6247,7 +6216,7 @@ 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]))
     {
@@ -6255,11 +6224,6 @@ ashlhi3_out (rtx_insn *insn, rtx operands[], int
*len)
                      && 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;
-
-      if (!len)
- len = &k;

       switch (INTVAL (operands[2]))
  {
@@ -6267,33 +6231,30 @@ 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
+        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");
+          "eor %B0,%A0", operands, plen, 6);
     }
   if (scratch)
     {
-      *len = 7;
-      return ("swap %A0"    CR_TAB
+        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");
+          "eor %B0,%A0", operands, plen, 7);
     }
   break;  /* optimize_size ? 6 : 8 */

@@ -6302,20 +6263,18 @@ ashlhi3_out (rtx_insn *insn, rtx operands[], int
*len)
     break;  /* scratch ? 5 : 6 */
   if (ldi_ok)
     {
-      *len = 8;
-      return ("lsl %A0"       CR_TAB
+        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");
+          "eor %B0,%A0", operands, plen, 8);
     }
   if (scratch)
     {
-      *len = 9;
-      return ("lsl %A0"     CR_TAB
+        return avr_asm_len ("lsl %A0"     CR_TAB
       "rol %B0"     CR_TAB
       "swap %A0"    CR_TAB
       "swap %B0"    CR_TAB
@@ -6323,15 +6282,14 @@ ashlhi3_out (rtx_insn *insn, rtx operands[], int
*len)
       "and %B0,%3"  CR_TAB
       "eor %B0,%A0" CR_TAB
       "and %A0,%3"  CR_TAB
-      "eor %B0,%A0");
+          "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
+    return avr_asm_len ("clr __tmp_reg__" CR_TAB
   "lsr %B0"         CR_TAB
   "ror %A0"         CR_TAB
   "ror __tmp_reg__" CR_TAB
@@ -6339,166 +6297,148 @@ ashlhi3_out (rtx_insn *insn, rtx operands[], int
*len)
   "ror %A0"         CR_TAB
   "ror __tmp_reg__" CR_TAB
   "mov %B0,%A0"     CR_TAB
-  "mov %A0,__tmp_reg__");
+      "mov %A0,__tmp_reg__", operands, plen, 9);

  case 7:
-  *len = 5;
-  return ("lsr %B0"     CR_TAB
+    return avr_asm_len ("lsr %B0"     CR_TAB
   "mov %B0,%A0" CR_TAB
   "clr %A0"     CR_TAB
   "ror %B0"     CR_TAB
-  "ror %A0");
+      "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
+    return avr_asm_len ("mov %B0,%A0" CR_TAB
   "clr %A0"     CR_TAB
-  "lsl %B0");
+      "lsl %B0", operands, plen, 3);

  case 10:
-  *len = 4;
-  return ("mov %B0,%A0" CR_TAB
+    return avr_asm_len ("mov %B0,%A0" CR_TAB
   "clr %A0"     CR_TAB
   "lsl %B0"     CR_TAB
-  "lsl %B0");
+      "lsl %B0", operands, plen, 4);

  case 11:
-  *len = 5;
-  return ("mov %B0,%A0" CR_TAB
+    return avr_asm_len ("mov %B0,%A0" CR_TAB
   "clr %A0"     CR_TAB
   "lsl %B0"     CR_TAB
   "lsl %B0"     CR_TAB
-  "lsl %B0");
+      "lsl %B0", operands, plen, 5);

  case 12:
   if (ldi_ok)
     {
-      *len = 4;
-      return ("mov %B0,%A0" CR_TAB
+        return avr_asm_len ("mov %B0,%A0" CR_TAB
       "clr %A0"     CR_TAB
       "swap %B0"    CR_TAB
-      "andi %B0,0xf0");
+          "andi %B0,0xf0", operands, plen, 4);
     }
   if (scratch)
     {
-      *len = 5;
-      return ("mov %B0,%A0" CR_TAB
+        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");
+          "and %B0,%3", operands, plen, 5);
     }
-  *len = 6;
-  return ("mov %B0,%A0" CR_TAB
+    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");
+      "lsl %B0", operands, plen, 6);

  case 13:
   if (ldi_ok)
     {
-      *len = 5;
-      return ("mov %B0,%A0" CR_TAB
+        return avr_asm_len ("mov %B0,%A0" CR_TAB
       "clr %A0"     CR_TAB
       "swap %B0"    CR_TAB
       "lsl %B0"     CR_TAB
-      "andi %B0,0xe0");
+          "andi %B0,0xe0", operands, plen, 5);
     }
   if (AVR_HAVE_MUL && scratch)
     {
-      *len = 5;
-      return ("ldi %3,0x20" CR_TAB
+        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__");
+          "clr __zero_reg__", operands, plen, 5);
     }
   if (optimize_size && scratch)
     break;  /* 5 */
   if (scratch)
     {
-      *len = 6;
-      return ("mov %B0,%A0" CR_TAB
+        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");
+          "and %B0,%3", operands, plen, 6);
     }
   if (AVR_HAVE_MUL)
     {
-      *len = 6;
-      return ("set"        CR_TAB
+        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__");
+          "clr __zero_reg__", operands, plen, 6);
     }
-  *len = 7;
-  return ("mov %B0,%A0" CR_TAB
+    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");
+      "lsl %B0", operands, plen, 7);

  case 14:
   if (AVR_HAVE_MUL && ldi_ok)
     {
-      *len = 5;
-      return ("ldi %B0,0x40" CR_TAB
+        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__");
+          "clr __zero_reg__", operands, plen, 5);
     }
   if (AVR_HAVE_MUL && scratch)
     {
-      *len = 5;
-      return ("ldi %3,0x40" CR_TAB
+        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__");
+          "clr __zero_reg__", operands, plen, 5);
     }
   if (optimize_size && ldi_ok)
     {
-      *len = 5;
-      return ("mov %B0,%A0" CR_TAB
+        return avr_asm_len ("mov %B0,%A0" CR_TAB
       "ldi %A0,6" "\n1:\t"
       "lsl %B0"     CR_TAB
       "dec %A0"     CR_TAB
-      "brne 1b");
+          "brne 1b", operands, plen, 5);
     }
   if (optimize_size && scratch)
     break;  /* 5 */
-  *len = 6;
-  return ("clr %B0" CR_TAB
+    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");
+      "clr %A0", operands, plen, 6);

  case 15:
-  *len = 4;
-  return ("clr %B0" CR_TAB
+    return avr_asm_len ("clr %B0" CR_TAB
   "lsr %A0" CR_TAB
   "ror %B0" CR_TAB
-  "clr %A0");
+      "clr %A0", operands, plen, 4);
  }
-      len = t;
     }
   out_shift_with_cnt ("lsl %A0" CR_TAB
-                      "rol %B0", insn, operands, len, 2);
+                      "rol %B0", insn, operands, plen, 2);
   return "";
 }

@@ -6506,13 +6446,22 @@ ashlhi3_out (rtx_insn *insn, rtx operands[], int
*len)
 /* 24-bit shift left */

 const char*
-avr_out_ashlpsi3 (rtx_insn *insn, rtx *op, int *plen)
+avr_out_ashlpsi3 (rtx_insn *insn, rtx *operands, int *plen)
 {
-  if (plen)
-    *plen = 0;
+  rtx op[5];
+
+  op[0] = operands[0];
+  op[1] = operands[1];
+  op[2] = operands[2];
+  op[3] = operands[3];

   if (CONST_INT_P (op[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]);
+
       switch (INTVAL (op[2]))
         {
         default:
@@ -6523,31 +6472,145 @@ avr_out_ashlpsi3 (rtx_insn *insn, rtx *op, int
*plen)
                               "clr %B0" CR_TAB
                               "clr %C0", op, plen, 3);

+        case 4:
+          if (optimize_size && scratch)
+            break;  /* 6 */
+          if (ldi_ok)
+            {
+              return avr_asm_len ("swap %C0"        CR_TAB
+                                  "andi %C0, 0xf0"  CR_TAB
+                                  "swap %B0"        CR_TAB
+                                  "eor %C0, %B0"    CR_TAB
+                                  "andi %B0, 0xf0"  CR_TAB
+                                  "eor %C0, %B0"    CR_TAB
+                                  "swap %A0"        CR_TAB
+                                  "eor %B0, %A0"    CR_TAB
+                                  "andi %A0, 0xf0"  CR_TAB
+                                  "eor %B0, %A0", op, plen, 10);
+            }
+          if (scratch)
+            {
+              return avr_asm_len ("swap %C0"      CR_TAB
+                                  "ldi %3,0xf0"   CR_TAB
+                                  "and %C0, %3"   CR_TAB
+                                  "swap %B0"      CR_TAB
+                                  "eor %C0, %B0"  CR_TAB
+                                  "and %B0, %3"   CR_TAB
+                                  "eor %C0, %B0"  CR_TAB
+                                  "swap %A0"      CR_TAB
+                                  "eor %B0, %A0"  CR_TAB
+                                  "and %A0, %3"   CR_TAB
+                                  "eor %B0, %A0", op, plen, 11);
+            }
+          break;  /* optimize_size ? 7 : 9 */
+
+        case 5:
+          if (optimize_size)
+            break;  /* scratch ? 6 : 7 */
+          if (ldi_ok)
+            {
+              return avr_asm_len ("lsl %A0"         CR_TAB
+                                  "rol %B0"         CR_TAB
+                                  "rol %C0"         CR_TAB
+                                  "swap %C0"        CR_TAB
+                                  "andi %C0, 0xf0"  CR_TAB
+                                  "swap %B0"        CR_TAB
+                                  "eor %C0, %B0"    CR_TAB
+                                  "andi %B0, 0xf0"  CR_TAB
+                                  "eor %C0, %B0"    CR_TAB
+                                  "swap %A0"        CR_TAB
+                                  "eor %B0, %A0"    CR_TAB
+                                  "andi %A0, 0xf0"  CR_TAB
+                                  "eor %B0, %A0", op, plen, 13);
+            }
+          if (scratch)
+            {
+              return avr_asm_len ("lsl %A0"         CR_TAB
+                                  "rol %B0"         CR_TAB
+                                  "rol %C0"         CR_TAB
+                                  "swap %C0"      CR_TAB
+                                  "ldi %3,0xf0"   CR_TAB
+                                  "and %C0, %3"   CR_TAB
+                                  "swap %B0"      CR_TAB
+                                  "eor %C0, %B0"  CR_TAB
+                                  "and %B0, %3"   CR_TAB
+                                  "eor %C0, %B0"  CR_TAB
+                                  "swap %A0"      CR_TAB
+                                  "eor %B0, %A0"  CR_TAB
+                                  "and %A0, %3"   CR_TAB
+                                  "eor %B0, %A0", op, plen, 14);
+            }
+          break;  /* 10 */
+
+        case 6:
+          if (optimize_size)
+            break;  /* scratch ? 6 : 7 */
+          return avr_asm_len ("clr __tmp_reg__" CR_TAB
+                  "lsr %C0"         CR_TAB
+                  "ror %B0"         CR_TAB
+                  "ror %A0"         CR_TAB
+                  "ror __tmp_reg__" CR_TAB
+                  "lsr %C0"         CR_TAB
+                  "ror %B0"         CR_TAB
+                  "ror %A0"         CR_TAB
+                  "ror __tmp_reg__" CR_TAB
+                  "mov %C0,%B0"     CR_TAB
+                  "mov %B0,%A0"     CR_TAB
+                  "mov %A0,__tmp_reg__", op, plen, 12);
+
+        case 7:
+          if (optimize_size)
+            break;  /* scratch ? 6 : 7 */
+          return avr_asm_len ("lsr %C0"     CR_TAB
+                  "mov %C0,%B0" CR_TAB
+                  "mov %B0,%A0" CR_TAB
+                  "clr %A0"     CR_TAB
+                  "ror %C0"     CR_TAB
+                  "ror %B0"     CR_TAB
+                  "ror %A0", op, plen, 7);
+
         case 8:
+        case 9:
+        case 10:
+        case 11:
+        case 12:
+        case 13:
+        case 14:
+        case 15:
           {
             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);
+              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);
+              avr_asm_len("clr %A0"      CR_TAB
+                          "mov %B0,%A1"  CR_TAB
+                          "mov %C0,%B1", op, plen, 3);
+            op[2] = GEN_INT((INTVAL (operands[2])) - 8);
+            return ashlhi3_out(insn, op, plen);
           }

         case 16:
+        case 17:
+        case 18:
+        case 19:
+        case 20:
+        case 21:
+        case 22:
           {
             int reg0 = REGNO (op[0]);
             int reg1 = REGNO (op[1]);

             if (reg0 + 2 != reg1)
-              avr_asm_len ("mov %C0,%A0", op, plen, 1);
+              avr_asm_len("mov %C0,%A0", op, plen, 1);

-            return avr_asm_len ("clr %B0"  CR_TAB
-                                "clr %A0", op, plen, 2);
+              avr_asm_len("clr %B0"  CR_TAB
+                          "clr %A0", op, plen, 2);
+            op[2] = GEN_INT((INTVAL (operands[2])) - 16);
+            return ashlqi3_out(insn, op, plen);
           }

         case 23:
@@ -6569,15 +6632,21 @@ 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)
 {
+  rtx op[5];
+
+  op[0] = operands[0];
+  op[1] = operands[1];
+  op[2] = operands[2];
+  op[3] = operands[3];
+
   if (CONST_INT_P (operands[2]))
     {
-      int k;
-      int *t = len;
-
-      if (!len)
- len = &k;
+      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]);

       switch (INTVAL (operands[2]))
  {
@@ -6586,125 +6655,247 @@ ashlsi3_out (rtx_insn *insn, rtx operands[], int
*len)
     break;

   if (AVR_HAVE_MOVW)
-    return *len = 3, ("clr %D0" CR_TAB
+      return avr_asm_len ("clr %D0" CR_TAB
       "clr %C0" CR_TAB
-      "movw %A0,%C0");
-  *len = 4;
-  return ("clr %D0" CR_TAB
+            "movw %A0,%C0", operands, plen, 3);
+
+    return avr_asm_len ("clr %D0" CR_TAB
   "clr %C0" CR_TAB
   "clr %B0" CR_TAB
-  "clr %A0");
+      "clr %A0", operands, plen, 4);

- case 8:
-  {
+  case 4:
+    if (optimize_size)
+      break;  /* scratch ? 7 : 8 */
+    if (ldi_ok)
+      {
+        return avr_asm_len ("swap %D0"        CR_TAB
+                            "swap %C0"        CR_TAB
+                            "swap %B0"        CR_TAB
+                            "swap %A0"        CR_TAB
+                            "andi %D0, 0xf0"  CR_TAB
+                            "eor %D0, %C0"    CR_TAB
+                            "andi %C0, 0xf0"  CR_TAB
+                            "eor %D0, %C0"    CR_TAB
+                            "eor %C0, %B0"    CR_TAB
+                            "andi %B0, 0xf0"  CR_TAB
+                            "eor %C0, %B0"    CR_TAB
+                            "eor %B0, %A0"    CR_TAB
+                            "andi %A0, 0xf0"  CR_TAB
+                            "eor %B0, %A0", op, plen, 14);
+      }
+    if (scratch)
+      {
+        return avr_asm_len ("swap %D0"        CR_TAB
+                            "swap %C0"        CR_TAB
+                            "swap %B0"        CR_TAB
+                            "swap %A0"        CR_TAB
+                            "ldi %3,0xf0"     CR_TAB
+                            "and %D0, %3"  CR_TAB
+                            "eor %D0, %C0"    CR_TAB
+                            "and %C0, %3"  CR_TAB
+                            "eor %D0, %C0"    CR_TAB
+                            "eor %C0, %B0"    CR_TAB
+                            "and %B0, %3"  CR_TAB
+                            "eor %C0, %B0"    CR_TAB
+                            "eor %B0, %A0"    CR_TAB
+                            "and %A0, %3"  CR_TAB
+                            "eor %B0, %A0", op, plen, 15);
+      }
+    break;  /* 10 */
+
+  case 5:
+    if (optimize_size)
+      break;  /* scratch ? 7 : 8 */
+    if (ldi_ok)
+      {
+        return avr_asm_len ("lsl %A0"         CR_TAB
+                            "rol %B0"         CR_TAB
+                            "rol %C0"         CR_TAB
+                            "rol %D0"         CR_TAB
+                            "swap %D0"        CR_TAB
+                            "swap %C0"        CR_TAB
+                            "swap %B0"        CR_TAB
+                            "swap %A0"        CR_TAB
+                            "andi %D0, 0xf0"  CR_TAB
+                            "eor %D0, %C0"    CR_TAB
+                            "andi %C0, 0xf0"  CR_TAB
+                            "eor %D0, %C0"    CR_TAB
+                            "eor %C0, %B0"    CR_TAB
+                            "andi %B0, 0xf0"  CR_TAB
+                            "eor %C0, %B0"    CR_TAB
+                            "eor %B0, %A0"    CR_TAB
+                            "andi %A0, 0xf0"  CR_TAB
+                            "eor %B0, %A0", op, plen, 18);
+      }
+    if (scratch)
+      {
+        return avr_asm_len ("lsl %A0"         CR_TAB
+                            "rol %B0"         CR_TAB
+                            "rol %C0"         CR_TAB
+                            "rol %D0"         CR_TAB
+                            "swap %D0"        CR_TAB
+                            "swap %C0"        CR_TAB
+                            "swap %B0"        CR_TAB
+                            "swap %A0"        CR_TAB
+                            "ldi %3,0xf0"     CR_TAB
+                            "and %D0, %3"  CR_TAB
+                            "eor %D0, %C0"    CR_TAB
+                            "and %C0, %3"  CR_TAB
+                            "eor %D0, %C0"    CR_TAB
+                            "eor %C0, %B0"    CR_TAB
+                            "and %B0, %3"  CR_TAB
+                            "eor %C0, %B0"    CR_TAB
+                            "eor %B0, %A0"    CR_TAB
+                            "and %A0, %3"  CR_TAB
+                            "eor %B0, %A0", op, plen, 19);
+      }
+    break;  /* 10 */
+
+  case 6:
+    if (optimize_size)
+      break;  /* scratch ? 7 : 8 */
+    return avr_asm_len ("clr __tmp_reg__" CR_TAB
+                        "lsr %D0"         CR_TAB
+                        "ror %C0"         CR_TAB
+                        "ror %B0"         CR_TAB
+                        "ror %A0"         CR_TAB
+                        "ror __tmp_reg__" CR_TAB
+                        "lsr %D0"         CR_TAB
+                        "ror %C0"         CR_TAB
+                        "ror %B0"         CR_TAB
+                        "ror %A0"         CR_TAB
+                        "ror __tmp_reg__" CR_TAB
+                        "mov %D0,%C0"     CR_TAB
+                        "mov %C0,%B0"     CR_TAB
+                        "mov %B0,%A0"     CR_TAB
+                        "mov %A0,__tmp_reg__", op, plen, 15);
+
+  case 7:
+    if (optimize_size)
+      break;  /* scratch ? 7 : 8 */
+    return avr_asm_len ("lsr %D0"     CR_TAB
+                        "mov %D0,%C0" CR_TAB
+                        "mov %C0,%B0" CR_TAB
+                        "mov %B0,%A0" CR_TAB
+                        "clr %A0"     CR_TAB
+                        "ror %D0"     CR_TAB
+                        "ror %C0"     CR_TAB
+                        "ror %B0"     CR_TAB
+                        "ror %A0", op, plen, 9);
+
+  case 8:
+  case 9:
+  case 10:
+  case 11:
+  case 12:
+  case 13:
+  case 14:
+  case 15:
+    {
     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");
+        avr_asm_len("mov %D0,%C1"  CR_TAB
+                    "mov %C0,%B1"  CR_TAB
+                    "mov %B0,%A1"  CR_TAB
+                    "clr %A0", operands, plen, 4);
     else
-      return ("clr %A0"      CR_TAB
-      "mov %B0,%A1"  CR_TAB
-      "mov %C0,%B1"  CR_TAB
-      "mov %D0,%C1");
-  }
-
- case 16:
-  {
+        avr_asm_len("clr %A0"      CR_TAB
+                    "mov %B0,%A1"  CR_TAB
+                    "mov %C0,%B1"  CR_TAB
+                    "mov %D0,%C1", operands, plen, 4);
+      op[2] = GEN_INT((INTVAL (operands[2])) - 8);
+      return avr_out_ashlpsi3(insn, op, plen);
+    }
+
+  case 16:
+  case 17:
+  case 18:
+  case 19:
+  case 20:
+  case 21:
+  case 22:
+  case 23:
+    {
     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");
+        avr_asm_len("clr %B0"      CR_TAB
+                    "clr %A0", op, plen, 2);
     if (AVR_HAVE_MOVW)
-      return *len = 3, ("movw %C0,%A1" CR_TAB
- "clr %B0"      CR_TAB
- "clr %A0");
+        avr_asm_len("movw %C0,%A1" CR_TAB
+                    "clr %B0"      CR_TAB
+                    "clr %A0", op, plen, 3);
     else
-      return *len = 4, ("mov %C0,%A1"  CR_TAB
- "mov %D0,%B1"  CR_TAB
- "clr %B0"      CR_TAB
- "clr %A0");
-  }
-
- case 24:
-  *len = 4;
-  return ("mov %D0,%A1"  CR_TAB
-  "clr %C0"      CR_TAB
-  "clr %B0"      CR_TAB
-  "clr %A0");
-
- case 31:
-  *len = 6;
-  return ("clr %D0" CR_TAB
+        avr_asm_len("mov %C0,%A1"  CR_TAB
+                    "mov %D0,%B1"  CR_TAB
+                    "clr %B0"      CR_TAB
+                    "clr %A0", op, plen, 4);
+      op[2] = GEN_INT((INTVAL (operands[2])) - 16);
+      return ashlhi3_out(insn, op, plen);
+    }
+
+  case 24:
+  case 25:
+  case 26:
+  case 27:
+  case 28:
+  case 29:
+  case 30:
+    {
+      avr_asm_len("mov %D0,%A1"  CR_TAB
+                  "clr %C0"      CR_TAB
+                  "clr %B0"      CR_TAB
+                  "clr %A0", op, plen, 4);
+      op[2] = GEN_INT((INTVAL (operands[2])) - 24);
+      return ashlqi3_out(insn, op, plen);
+    }
+
+  case 31:
+    return avr_asm_len ("clr %D0" CR_TAB
   "lsr %A0" CR_TAB
   "ror %D0" CR_TAB
   "clr %C0" CR_TAB
   "clr %B0" CR_TAB
-  "clr %A0");
+      "clr %A0", 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, op, plen, 4);
   return "";
 }

 /* 8bit arithmetic shift right  ((signed char)x >> i) */

 const char *
-ashrqi3_out (rtx_insn *insn, rtx operands[], int *len)
+ashrqi3_out (rtx_insn *insn, rtx operands[], int *plen)
 {
   if (CONST_INT_P (operands[2]))
     {
-      int k;
-
-      if (!len)
- len = &k;
-
       switch (INTVAL (operands[2]))
  {
- case 1:
-  *len = 1;
-  return "asr %0";
-
- case 2:
-  *len = 2;
-  return ("asr %0" CR_TAB
-  "asr %0");

- case 3:
-  *len = 3;
-  return ("asr %0" CR_TAB
-  "asr %0" CR_TAB
-  "asr %0");
-
- case 4:
-  *len = 4;
-  return ("asr %0" CR_TAB
-  "asr %0" CR_TAB
-  "asr %0" CR_TAB
-  "asr %0");
-
- case 5:
-  *len = 5;
-  return ("asr %0" CR_TAB
-  "asr %0" CR_TAB
-  "asr %0" CR_TAB
-  "asr %0" CR_TAB
-  "asr %0");
-
- case 6:
-  *len = 4;
-  return ("bst %0,6"  CR_TAB
+  case 4:
+    return avr_asm_len ("asr %0" CR_TAB
+            "asr %0" CR_TAB
+            "asr %0" CR_TAB
+            "asr %0", operands, plen, 4);
+
+  case 5:
+    return avr_asm_len ("asr %0" CR_TAB
+            "asr %0" CR_TAB
+            "asr %0" CR_TAB
+            "asr %0" CR_TAB
+            "asr %0", operands, plen, 5);
+
+  case 6:
+    return avr_asm_len ("bst %0,6"  CR_TAB
   "lsl %0"    CR_TAB
   "sbc %0,%0" CR_TAB
-  "bld %0,0");
+      "bld %0,0", operands, plen, 4);

  default:
   if (INTVAL (operands[2]) < 8)
@@ -6713,16 +6904,15 @@ ashrqi3_out (rtx_insn *insn, rtx operands[], int
*len)
   /* fall through */

  case 7:
-  *len = 2;
-  return ("lsl %0" CR_TAB
-  "sbc %0,%0");
+    return avr_asm_len ("lsl %0" CR_TAB
+      "sbc %0,%0", operands, plen, 2);
  }
     }
   else if (CONSTANT_P (operands[2]))
     fatal_insn ("internal compiler error.  Incorrect shift:", insn);

   out_shift_with_cnt ("asr %0",
-                      insn, operands, len, 1);
+                      insn, operands, plen, 1);
   return "";
 }

@@ -6730,7 +6920,7 @@ ashrqi3_out (rtx_insn *insn, rtx operands[], int *len)
 /* 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]))
     {
@@ -6738,11 +6928,6 @@ ashrhi3_out (rtx_insn *insn, rtx operands[], int
*len)
                      && 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;
-
-      if (!len)
- len = &k;

       switch (INTVAL (operands[2]))
  {
@@ -6754,22 +6939,20 @@ 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
+    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");
+      "rol %B0", operands, plen, 8);

  case 7:
-  *len = 4;
-  return ("lsl %A0"     CR_TAB
+    return avr_asm_len ("lsl %A0"     CR_TAB
   "mov %A0,%B0" CR_TAB
   "rol %A0"     CR_TAB
-  "sbc %B0,%B0");
+      "sbc %B0,%B0", operands, plen, 4);

  case 8:
   {
@@ -6777,101 +6960,92 @@ ashrhi3_out (rtx_insn *insn, rtx operands[], int
*len)
     int reg1 = true_regnum (operands[1]);

     if (reg0 == reg1)
-      return *len = 3, ("mov %A0,%B0" CR_TAB
+        return avr_asm_len ("mov %A0,%B0" CR_TAB
  "lsl %B0"     CR_TAB
- "sbc %B0,%B0");
+        "sbc %B0,%B0", operands, plen, 3);
     else
-      return *len = 4, ("mov %A0,%B1" CR_TAB
+        return avr_asm_len ("mov %A0,%B1" CR_TAB
         "clr %B0"     CR_TAB
         "sbrc %A0,7"  CR_TAB
-        "dec %B0");
+              "dec %B0", operands, plen, 4);
   }

  case 9:
-  *len = 4;
-  return ("mov %A0,%B0" CR_TAB
+    return avr_asm_len ("mov %A0,%B0" CR_TAB
   "lsl %B0"      CR_TAB
   "sbc %B0,%B0" CR_TAB
-  "asr %A0");
+      "asr %A0", operands, plen, 4);

  case 10:
-  *len = 5;
-  return ("mov %A0,%B0" CR_TAB
+    return avr_asm_len ("mov %A0,%B0" CR_TAB
   "lsl %B0"     CR_TAB
   "sbc %B0,%B0" CR_TAB
   "asr %A0"     CR_TAB
-  "asr %A0");
+      "asr %A0", operands, plen, 5);

  case 11:
   if (AVR_HAVE_MUL && ldi_ok)
     {
-      *len = 5;
-      return ("ldi %A0,0x20" CR_TAB
+        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__");
+          "clr __zero_reg__", operands, plen, 5);
     }
   if (optimize_size && scratch)
     break;  /* 5 */
-  *len = 6;
-  return ("mov %A0,%B0" CR_TAB
+    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");
+      "asr %A0", operands, plen, 6);

  case 12:
   if (AVR_HAVE_MUL && ldi_ok)
     {
-      *len = 5;
-      return ("ldi %A0,0x10" CR_TAB
+        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__");
+          "clr __zero_reg__", operands, plen, 5);
     }
   if (optimize_size && scratch)
     break;  /* 5 */
-  *len = 7;
-  return ("mov %A0,%B0" CR_TAB
+    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");
+      "asr %A0", operands, plen, 7);

  case 13:
   if (AVR_HAVE_MUL && ldi_ok)
     {
-      *len = 5;
-      return ("ldi %A0,0x08" CR_TAB
+        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__");
+          "clr __zero_reg__", operands, plen, 5);
     }
   if (optimize_size)
-    break;  /* scratch ? 5 : 7 */
-  *len = 8;
-  return ("mov %A0,%B0" CR_TAB
+      break;  /* scratch ? 5 : 6 */
+    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");
+      "asr %A0", operands, plen, 8);

  case 14:
-  *len = 5;
-  return ("lsl %B0"     CR_TAB
+    return avr_asm_len ("lsl %B0"     CR_TAB
   "sbc %A0,%A0" CR_TAB
   "lsl %B0"     CR_TAB
   "mov %B0,%A0" CR_TAB
-  "rol %A0");
+      "rol %A0", operands, plen, 5);

  default:
   if (INTVAL (operands[2]) < 16)
@@ -6880,14 +7054,13 @@ ashrhi3_out (rtx_insn *insn, rtx operands[], int
*len)
   /* fall through */

  case 15:
-  return *len = 3, ("lsl %B0"     CR_TAB
+    return avr_asm_len ("lsl %B0"     CR_TAB
     "sbc %A0,%A0" CR_TAB
-    "mov %B0,%A0");
+          "mov %B0,%A0", operands, plen, 3);
  }
-      len = t;
     }
   out_shift_with_cnt ("asr %B0" CR_TAB
-                      "ror %A0", insn, operands, len, 2);
+                      "ror %A0", insn, operands, plen, 2);
   return "";
 }

@@ -6895,40 +7068,93 @@ ashrhi3_out (rtx_insn *insn, rtx operands[], int
*len)
 /* 24-bit arithmetic shift right */

 const char*
-avr_out_ashrpsi3 (rtx_insn *insn, rtx *op, int *plen)
+avr_out_ashrpsi3 (rtx_insn *insn, rtx *operands, int *plen)
 {
+  rtx op[5];
+
+  op[0] = operands[0];
+  op[1] = operands[1];
+  op[2] = operands[2];
+  op[3] = operands[3];
+
   int dest = REGNO (op[0]);
   int src = REGNO (op[1]);

   if (CONST_INT_P (op[2]))
     {
-      if (plen)
-        *plen = 0;
-
       switch (INTVAL (op[2]))
         {
+        case 4:
+        case 5:
+          /* XXX try to optimize this too? */
+          break;
+
+        case 6:
+          if (optimize_size)
+            break;  /* scratch ? 6 : 7 */
+          return avr_asm_len ("mov __tmp_reg__,%A0" CR_TAB
+            "mov %A0,%B0"         CR_TAB
+            "mov %B0,%C0"         CR_TAB
+            "lsl __tmp_reg__"     CR_TAB
+            "rol %A0"             CR_TAB
+            "rol %B0"             CR_TAB
+            "sbc %C0,%C0"         CR_TAB
+            "lsl __tmp_reg__"     CR_TAB
+            "rol %A0"             CR_TAB
+            "rol %B0"             CR_TAB
+            "rol %C0", operands, plen, 11);
+
+        case 7:
+          return avr_asm_len ("lsl %A0"     CR_TAB
+            "rol %B0"     CR_TAB
+            "rol %C0"     CR_TAB
+            "mov %A0,%B0" CR_TAB
+            "mov %B0,%C0" CR_TAB
+            "sbc %C0,%C0", operands, plen, 6);
+
         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);
+        case 9:
+        case 10:
+        case 11:
+        case 12:
+        case 13:
+        case 14:
+        case 15:
+          {
+            if (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);
+            else
+              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);
+            op[2] = GEN_INT((INTVAL (operands[2])) - 8);
+            return ashrhi3_out(insn, op, plen);
+          }

         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);
+        case 17:
+        case 18:
+        case 19:
+        case 20:
+        case 21:
+        case 22:
+          {
+            if (dest != src + 2)
+              avr_asm_len("mov %A0,%C1", op, plen, 1);
+
+            avr_asm_len("clr %B0"     CR_TAB
+                        "sbrc %A0,7"  CR_TAB
+                        "com %B0"     CR_TAB
+                        "mov %C0,%B0", op, plen, 4);
+            op[2] = GEN_INT((INTVAL (operands[2])) - 16);
+            return ashrqi3_out(insn, op, plen);
+          }

         default:
           if (INTVAL (op[2]) < 24)
@@ -6954,71 +7180,136 @@ 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;
+  rtx op[5];

-      if (!len)
- len = &k;
+  op[0] = operands[0];
+  op[1] = operands[1];
+  op[2] = operands[2];
+  op[3] = operands[3];

+  if (CONST_INT_P (operands[2]))
+    {
       switch (INTVAL (operands[2]))
  {
- case 8:
-  {
+  case 4:
+  case 5:
+    /* XXX try to optimize this too? */
+    break;
+
+  case 6:
+    if (optimize_size)
+      break;  /* scratch ? 7 : 8 */
+    return avr_asm_len ("mov __tmp_reg__,%A0" CR_TAB
+      "mov %A0,%B0"         CR_TAB
+      "mov %B0,%C0"         CR_TAB
+      "mov %C0,%D0"         CR_TAB
+      "lsl __tmp_reg__"     CR_TAB
+      "rol %A0"             CR_TAB
+      "rol %B0"             CR_TAB
+      "rol %C0"             CR_TAB
+      "sbc %D0,%D0"         CR_TAB
+      "lsl __tmp_reg__"     CR_TAB
+      "rol %A0"             CR_TAB
+      "rol %B0"             CR_TAB
+      "rol %C0"             CR_TAB
+      "rol %D0", operands, plen, 14);
+
+  case 7:
+    return avr_asm_len ("lsl %A0"     CR_TAB
+      "rol %B0"     CR_TAB
+      "rol %C0"     CR_TAB
+      "rol %D0"     CR_TAB
+      "mov %A0,%B0" CR_TAB
+      "mov %B0,%C0" CR_TAB
+      "mov %C0,%D0" CR_TAB
+      "sbc %D0,%D0", operands, plen, 8);
+
+  case 8:
+  case 9:
+  case 10:
+  case 11:
+  case 12:
+  case 13:
+  case 14:
+  case 15:
+    {
     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");
+        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", op, plen, 6);
     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");
-  }
-
- case 16:
-  {
+        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", op, plen, 6);
+      op[2] = GEN_INT((INTVAL (operands[2])) - 8);
+      return avr_out_ashrpsi3(insn, op, plen);
+    }
+
+  case 16:
+  case 17:
+  case 18:
+  case 19:
+  case 20:
+  case 21:
+  case 22:
+  case 23:
+    {
     int reg0 = true_regnum (operands[0]);
     int reg1 = true_regnum (operands[1]);

     if (reg0 == reg1 + 2)
-      return *len = 4, ("clr %D0"     CR_TAB
- "sbrc %B0,7"  CR_TAB
- "com %D0"     CR_TAB
- "mov %C0,%D0");
+        avr_asm_len("clr %D0"     CR_TAB
+                    "sbrc %B0,7"  CR_TAB
+                    "com %D0"     CR_TAB
+                    "mov %C0,%D0", op, plen, 4);
     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");
+        avr_asm_len("movw %A0,%C1" CR_TAB
+                    "clr %D0"      CR_TAB
+                    "sbrc %B0,7"   CR_TAB
+                    "com %D0"      CR_TAB
+                    "mov %C0,%D0", op, plen, 5);
     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");
-  }
-
- case 24:
-  return *len = 6, ("mov %A0,%D1" CR_TAB
+        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", op, plen, 6);
+      op[2] = GEN_INT((INTVAL (operands[2])) - 16);
+      return ashrhi3_out(insn, op, plen);
+    }
+
+  case 24:
+  case 25:
+  case 26:
+  case 27:
+  case 28:
+  case 29:
+  case 30:
+    {
+      int reg0 = true_regnum (operands[0]);
+      int reg1 = true_regnum (operands[1]);
+
+      if (reg0 == reg1 + 2)
+        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");
+          "mov %C0,%D0", op, plen, 6);
+      op[2] = GEN_INT((INTVAL (operands[2])) - 24);
+      return ashrqi3_out(insn, op, plen);
+    }

  default:
   if (INTVAL (operands[2]) < 32)
@@ -7028,37 +7319,33 @@ ashrsi3_out (rtx_insn *insn, rtx operands[], int
*len)

  case 31:
   if (AVR_HAVE_MOVW)
-    return *len = 4, ("lsl %D0"     CR_TAB
+      return avr_asm_len ("lsl %D0"     CR_TAB
       "sbc %A0,%A0" CR_TAB
       "mov %B0,%A0" CR_TAB
-      "movw %C0,%A0");
+            "movw %C0,%A0", operands, plen, 4);
   else
-    return *len = 5, ("lsl %D0"     CR_TAB
+      return avr_asm_len ("lsl %D0"     CR_TAB
       "sbc %A0,%A0" CR_TAB
       "mov %B0,%A0" CR_TAB
       "mov %C0,%A0" CR_TAB
-      "mov %D0,%A0");
+            "mov %D0,%A0", operands, plen, 5);
  }
-      len = t;
     }
   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;
-
-      if (!len)
- len = &k;
+      int ldi_ok = test_hard_reg_class (LD_REGS, operands[0]);

       switch (INTVAL (operands[2]))
  {
@@ -7066,87 +7353,65 @@ lshrqi3_out (rtx_insn *insn, rtx operands[], int
*len)
   if (INTVAL (operands[2]) < 8)
     break;

-  *len = 1;
-  return "clr %0";
-
- 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");
+    return avr_asm_len("clr %0", operands, plen, 1);

  case 4:
-  if (test_hard_reg_class (LD_REGS, operands[0]))
+    if (ldi_ok)
     {
-      *len=2;
-      return ("swap %0" CR_TAB
-      "andi %0,0x0f");
+        return avr_asm_len ("swap %0" CR_TAB
+          "andi %0,0x0f", operands, plen, 2);
     }
-  *len = 4;
-  return ("lsr %0" CR_TAB
+    return avr_asm_len ("lsr %0" CR_TAB
   "lsr %0" CR_TAB
   "lsr %0" CR_TAB
-  "lsr %0");
+      "lsr %0", operands, plen, 4);

  case 5:
-  if (test_hard_reg_class (LD_REGS, operands[0]))
+    if (ldi_ok)
     {
-      *len = 3;
-      return ("swap %0" CR_TAB
+        return avr_asm_len ("swap %0" CR_TAB
       "lsr %0"  CR_TAB
-      "andi %0,0x7");
+          "andi %0,0x7", operands, plen, 3);
     }
-  *len = 5;
-  return ("lsr %0" CR_TAB
+    return avr_asm_len ("lsr %0" CR_TAB
   "lsr %0" CR_TAB
   "lsr %0" CR_TAB
   "lsr %0" CR_TAB
-  "lsr %0");
+      "lsr %0", operands, plen, 5);

  case 6:
-  if (test_hard_reg_class (LD_REGS, operands[0]))
+    if (ldi_ok)
     {
-      *len = 4;
-      return ("swap %0" CR_TAB
+        return avr_asm_len ("swap %0" CR_TAB
       "lsr %0"  CR_TAB
       "lsr %0"  CR_TAB
-      "andi %0,0x3");
+          "andi %0,0x3", operands, plen, 4);
     }
-  *len = 6;
-  return ("lsr %0" CR_TAB
+    return avr_asm_len ("lsr %0" CR_TAB
   "lsr %0" CR_TAB
   "lsr %0" CR_TAB
   "lsr %0" CR_TAB
   "lsr %0" CR_TAB
-  "lsr %0");
+      "lsr %0", operands, plen, 6);

  case 7:
-  *len = 3;
-  return ("rol %0" CR_TAB
+    return avr_asm_len ("rol %0" CR_TAB
   "clr %0" CR_TAB
-  "rol %0");
+      "rol %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]))
     {
@@ -7154,11 +7419,6 @@ lshrhi3_out (rtx_insn *insn, rtx operands[], int
*len)
                      && 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;
-
-      if (!len)
- len = &k;

       switch (INTVAL (operands[2]))
  {
@@ -7166,33 +7426,30 @@ lshrhi3_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 %B0"      CR_TAB
+        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");
+          "eor %A0,%B0", operands, plen, 6);
     }
   if (scratch)
     {
-      *len = 7;
-      return ("swap %B0"    CR_TAB
+        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");
+          "eor %A0,%B0", operands, plen, 7);
     }
   break;  /* optimize_size ? 6 : 8 */

@@ -7201,20 +7458,18 @@ lshrhi3_out (rtx_insn *insn, rtx operands[], int
*len)
     break;  /* scratch ? 5 : 6 */
   if (ldi_ok)
     {
-      *len = 8;
-      return ("lsr %B0"       CR_TAB
+        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");
+          "eor %A0,%B0", operands, plen, 8);
     }
   if (scratch)
     {
-      *len = 9;
-      return ("lsr %B0"     CR_TAB
+        return avr_asm_len ("lsr %B0"     CR_TAB
       "ror %A0"     CR_TAB
       "swap %B0"    CR_TAB
       "swap %A0"    CR_TAB
@@ -7222,15 +7477,14 @@ lshrhi3_out (rtx_insn *insn, rtx operands[], int
*len)
       "and %A0,%3"  CR_TAB
       "eor %A0,%B0" CR_TAB
       "and %B0,%3"  CR_TAB
-      "eor %A0,%B0");
+          "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
+    return avr_asm_len ("clr __tmp_reg__" CR_TAB
   "lsl %A0"         CR_TAB
   "rol %B0"         CR_TAB
   "rol __tmp_reg__" CR_TAB
@@ -7238,166 +7492,148 @@ lshrhi3_out (rtx_insn *insn, rtx operands[], int
*len)
   "rol %B0"         CR_TAB
   "rol __tmp_reg__" CR_TAB
   "mov %A0,%B0"     CR_TAB
-  "mov %B0,__tmp_reg__");
+      "mov %B0,__tmp_reg__", operands, plen, 9);

  case 7:
-  *len = 5;
-  return ("lsl %A0"     CR_TAB
+    return avr_asm_len ("lsl %A0"     CR_TAB
   "mov %A0,%B0" CR_TAB
   "rol %A0"     CR_TAB
   "sbc %B0,%B0" CR_TAB
-  "neg %B0");
+      "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
+    return avr_asm_len ("mov %A0,%B0" CR_TAB
   "clr %B0"     CR_TAB
-  "lsr %A0");
+      "lsr %A0", operands, plen, 3);

  case 10:
-  *len = 4;
-  return ("mov %A0,%B0" CR_TAB
+    return avr_asm_len ("mov %A0,%B0" CR_TAB
   "clr %B0"     CR_TAB
   "lsr %A0"     CR_TAB
-  "lsr %A0");
+      "lsr %A0", operands, plen, 4);

  case 11:
-  *len = 5;
-  return ("mov %A0,%B0" CR_TAB
+    return avr_asm_len ("mov %A0,%B0" CR_TAB
   "clr %B0"     CR_TAB
   "lsr %A0"     CR_TAB
   "lsr %A0"     CR_TAB
-  "lsr %A0");
+      "lsr %A0", operands, plen, 5);

  case 12:
   if (ldi_ok)
     {
-      *len = 4;
-      return ("mov %A0,%B0" CR_TAB
+        return avr_asm_len ("mov %A0,%B0" CR_TAB
       "clr %B0"     CR_TAB
       "swap %A0"    CR_TAB
-      "andi %A0,0x0f");
+          "andi %A0,0x0f", operands, plen, 4);
     }
   if (scratch)
     {
-      *len = 5;
-      return ("mov %A0,%B0" CR_TAB
+        return avr_asm_len ("mov %A0,%B0" CR_TAB
       "clr %B0"     CR_TAB
       "swap %A0"    CR_TAB
       "ldi %3,0x0f" CR_TAB
-      "and %A0,%3");
+          "and %A0,%3", operands, plen, 5);
     }
-  *len = 6;
-  return ("mov %A0,%B0" CR_TAB
+    return 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");
+      "lsr %A0", operands, plen, 6);

  case 13:
   if (ldi_ok)
     {
-      *len = 5;
-      return ("mov %A0,%B0" CR_TAB
+        return avr_asm_len ("mov %A0,%B0" CR_TAB
       "clr %B0"     CR_TAB
       "swap %A0"    CR_TAB
       "lsr %A0"     CR_TAB
-      "andi %A0,0x07");
+          "andi %A0,0x07", operands, plen, 5);
     }
   if (AVR_HAVE_MUL && scratch)
     {
-      *len = 5;
-      return ("ldi %3,0x08" CR_TAB
+        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__");
+          "clr __zero_reg__", operands, plen, 5);
     }
   if (optimize_size && scratch)
     break;  /* 5 */
   if (scratch)
     {
-      *len = 6;
-      return ("mov %A0,%B0" CR_TAB
+        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");
+          "and %A0,%3", operands, plen, 6);
     }
   if (AVR_HAVE_MUL)
     {
-      *len = 6;
-      return ("set"        CR_TAB
+        return 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__");
+          "clr __zero_reg__", operands, plen, 6);
     }
-  *len = 7;
-  return ("mov %A0,%B0" CR_TAB
+    return 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");
+      "lsr %A0", operands, plen, 7);

  case 14:
   if (AVR_HAVE_MUL && ldi_ok)
     {
-      *len = 5;
-      return ("ldi %A0,0x04" CR_TAB
+        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__");
+          "clr __zero_reg__", operands, plen, 5);
     }
   if (AVR_HAVE_MUL && scratch)
     {
-      *len = 5;
-      return ("ldi %3,0x04" CR_TAB
+        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__");
+          "clr __zero_reg__", operands, plen, 5);
     }
   if (optimize_size && ldi_ok)
     {
-      *len = 5;
-      return ("mov %A0,%B0" CR_TAB
+        return avr_asm_len ("mov %A0,%B0" CR_TAB
       "ldi %B0,6" "\n1:\t"
       "lsr %A0"     CR_TAB
       "dec %B0"     CR_TAB
-      "brne 1b");
+          "brne 1b", operands, plen, 5);
     }
   if (optimize_size && scratch)
     break;  /* 5 */
-  *len = 6;
-  return ("clr %A0" CR_TAB
+    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");
+      "clr %B0", operands, plen, 6);

  case 15:
-  *len = 4;
-  return ("clr %A0" CR_TAB
+    return avr_asm_len ("clr %A0" CR_TAB
   "lsl %B0" CR_TAB
   "rol %A0" CR_TAB
-  "clr %B0");
+      "clr %B0", 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 "";
 }

@@ -7405,34 +7641,162 @@ lshrhi3_out (rtx_insn *insn, rtx operands[], int
*len)
 /* 24-bit logic shift right */

 const char*
-avr_out_lshrpsi3 (rtx_insn *insn, rtx *op, int *plen)
+avr_out_lshrpsi3 (rtx_insn *insn, rtx *operands, int *plen)
 {
+  rtx op[5];
+
+  op[0] = operands[0];
+  op[1] = operands[1];
+  op[2] = operands[2];
+  op[3] = operands[3];
+
   int dest = REGNO (op[0]);
   int src = REGNO (op[1]);

   if (CONST_INT_P (op[2]))
     {
-      if (plen)
-        *plen = 0;
+      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]);

       switch (INTVAL (op[2]))
         {
+
+        case 4:
+          if (optimize_size)
+            break;  /* scratch ? 6 : 7 */
+          if (ldi_ok)
+            {
+              return avr_asm_len ("swap %C0"      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"   CR_TAB
+                                  "eor %B0,%C0"   CR_TAB
+                                  "andi %C0,0x0f" CR_TAB
+                                  "eor %B0,%C0", op, plen, 10);
+            }
+          if (scratch)
+            {
+              return avr_asm_len ("swap %C0"      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"   CR_TAB
+                                  "eor %B0,%C0"   CR_TAB
+                                  "and %C0,%3"    CR_TAB
+                                  "eor %B0,%C0", op, plen, 11);
+            }
+          break;
+
+        case 5:
+          if (optimize_size)
+            break;  /* scratch ? 6 : 7 */
+          if (ldi_ok)
+            {
+              return avr_asm_len ("lsr %C0"       CR_TAB
+                                  "ror %B0"       CR_TAB
+                                  "ror %A0"       CR_TAB
+                                  "swap %C0"      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"   CR_TAB
+                                  "eor %B0,%C0"   CR_TAB
+                                  "andi %C0,0x0f" CR_TAB
+                                  "eor %B0,%C0", op, plen, 13);
+            }
+          if (scratch)
+            {
+              return avr_asm_len ("lsr %C0"       CR_TAB
+                                  "ror %B0"       CR_TAB
+                                  "ror %A0"       CR_TAB
+                                  "swap %C0"      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"   CR_TAB
+                                  "eor %B0,%C0"   CR_TAB
+                                  "and %C0,%3"    CR_TAB
+                                  "eor %B0,%C0", op, plen, 14);
+            }
+          break;  /* 10 */
+
+        case 6:
+          if (optimize_size)
+            break;  /* scratch ? 6 : 7 */
+          return avr_asm_len ("clr __tmp_reg__" CR_TAB
+                              "lsl %A0"         CR_TAB
+                              "rol %B0"         CR_TAB
+                              "rol %C0"         CR_TAB
+                              "rol __tmp_reg__" CR_TAB
+                              "lsl %A0"         CR_TAB
+                              "rol %B0"         CR_TAB
+                              "rol %C0"         CR_TAB
+                              "rol __tmp_reg__" CR_TAB
+                              "mov %A0,%B0"     CR_TAB
+                              "mov %B0,%C0"     CR_TAB
+                              "mov %C0,__tmp_reg__", op, plen, 12);
+
+        case 7:
+          if (optimize_size)
+            break;  /* scratch ? 6 : 7 */
+          return avr_asm_len ("lsl %A0"         CR_TAB
+                              "rol %B0"         CR_TAB
+                              "rol %C0"         CR_TAB
+                              "mov %A0,%B0"     CR_TAB
+                              "mov %B0,%C0"     CR_TAB
+                              "sbc %C0,%C0"     CR_TAB
+                              "neg %C0", op, plen, 7);
+
         case 8:
-          if (dest <= src)
-            return avr_asm_len ("mov %A0,%B1" CR_TAB
-                                "mov %B0,%C1" CR_TAB
-                                "clr %C0", op, plen, 3);
-          else
-            return avr_asm_len ("clr %C0"     CR_TAB
-                                "mov %B0,%C1" CR_TAB
-                                "mov %A0,%B1", op, plen, 3);
+        case 9:
+        case 10:
+        case 11:
+        case 12:
+        case 13:
+        case 14:
+        case 15:
+          {
+            if (dest <= src)
+              avr_asm_len("mov %A0,%B1" CR_TAB
+                          "mov %B0,%C1" CR_TAB
+                          "clr %C0", op, plen, 3);
+            else
+              avr_asm_len("clr %C0"     CR_TAB
+                          "mov %B0,%C1" CR_TAB
+                          "mov %A0,%B1", op, plen, 3);
+            op[2] = GEN_INT((INTVAL (operands[2])) - 8);
+            return lshrhi3_out(insn, op, plen);
+          }

         case 16:
-          if (dest != src + 2)
-            avr_asm_len ("mov %A0,%C1", op, plen, 1);
+        case 17:
+        case 18:
+        case 19:
+        case 20:
+        case 21:
+        case 22:
+          {
+            if (dest != src + 2)
+              avr_asm_len("mov %A0,%C1", op, plen, 1);

-          return avr_asm_len ("clr %B0"  CR_TAB
-                              "clr %C0", op, plen, 2);
+            avr_asm_len("clr %B0"  CR_TAB
+                        "clr %C0", op, plen, 2);
+            op[2] = GEN_INT((INTVAL (operands[2])) - 16);
+            return lshrqi3_out(insn, op, plen);
+          }

         default:
           if (INTVAL (op[2]) < 24)
@@ -7459,15 +7823,21 @@ 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)
 {
+  rtx op[5];
+
+  op[0] = operands[0];
+  op[1] = operands[1];
+  op[2] = operands[2];
+  op[3] = operands[3];
+
   if (CONST_INT_P (operands[2]))
     {
-      int k;
-      int *t = len;
-
-      if (!len)
- len = &k;
+      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]);

       switch (INTVAL (operands[2]))
  {
@@ -7476,72 +7846,217 @@ lshrsi3_out (rtx_insn *insn, rtx operands[], int
*len)
     break;

   if (AVR_HAVE_MOVW)
-    return *len = 3, ("clr %D0" CR_TAB
+      return avr_asm_len ("clr %D0" CR_TAB
       "clr %C0" CR_TAB
-      "movw %A0,%C0");
-  *len = 4;
-  return ("clr %D0" CR_TAB
+            "movw %A0,%C0", operands, plen, 3);
+
+    return avr_asm_len ("clr %D0" CR_TAB
   "clr %C0" CR_TAB
   "clr %B0" CR_TAB
-  "clr %A0");
+      "clr %A0", operands, plen, 4);

- case 8:
-  {
+  case 4:
+    if (optimize_size)
+      break;  /* scratch ? 7 : 8 */
+    if (ldi_ok)
+      {
+        return avr_asm_len ("swap %D0"      CR_TAB
+                            "swap %C0"      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"   CR_TAB
+                            "eor %B0,%C0"   CR_TAB
+                            "andi %C0,0x0f" CR_TAB
+                            "eor %B0,%C0"   CR_TAB
+                            "eor %C0,%D0"   CR_TAB
+                            "andi %D0,0x0f" CR_TAB
+                            "eor %C0,%D0", op, plen, 14);
+      }
+    if (scratch)
+      {
+        return avr_asm_len ("swap %D0"      CR_TAB
+                            "swap %C0"      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"   CR_TAB
+                            "eor %B0,%C0"   CR_TAB
+                            "and %C0,%3" CR_TAB
+                            "eor %B0,%C0"   CR_TAB
+                            "eor %C0,%D0"   CR_TAB
+                            "and %D0,%3" CR_TAB
+                            "eor %C0,%D0", op, plen, 15);
+      }
+    break;
+
+  case 5:
+    if (optimize_size)
+      break;  /* scratch ? 7 : 8 */
+    if (ldi_ok)
+      {
+        return avr_asm_len ("lsr %D0"       CR_TAB
+                            "ror %C0"       CR_TAB
+                            "ror %B0"       CR_TAB
+                            "ror %A0"       CR_TAB
+                            "swap %D0"      CR_TAB
+                            "swap %C0"      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"   CR_TAB
+                            "eor %B0,%C0"   CR_TAB
+                            "andi %C0,0x0f" CR_TAB
+                            "eor %B0,%C0"   CR_TAB
+                            "eor %C0,%D0"   CR_TAB
+                            "andi %D0,0x0f" CR_TAB
+                            "eor %C0,%D0", op, plen, 18);
+      }
+    if (scratch)
+      {
+        return avr_asm_len ("lsr %D0"       CR_TAB
+                            "ror %C0"       CR_TAB
+                            "ror %B0"       CR_TAB
+                            "ror %A0"       CR_TAB
+                            "swap %D0"      CR_TAB
+                            "swap %C0"      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"   CR_TAB
+                            "eor %B0,%C0"   CR_TAB
+                            "and %C0,%3" CR_TAB
+                            "eor %B0,%C0"   CR_TAB
+                            "eor %C0,%D0"   CR_TAB
+                            "and %D0,%3" CR_TAB
+                            "eor %C0,%D0", op, plen, 19);
+      }
+    break;  /* 10 */
+
+  case 6:
+    if (optimize_size)
+      break;  /* scratch ? 7 : 8 */
+    return avr_asm_len ("clr __tmp_reg__" CR_TAB
+                        "lsl %A0"         CR_TAB
+                        "rol %B0"         CR_TAB
+                        "rol %C0"         CR_TAB
+                        "rol %D0"         CR_TAB
+                        "rol __tmp_reg__" CR_TAB
+                        "lsl %A0"         CR_TAB
+                        "rol %B0"         CR_TAB
+                        "rol %C0"         CR_TAB
+                        "rol %D0"         CR_TAB
+                        "rol __tmp_reg__" CR_TAB
+                        "mov %A0,%B0"     CR_TAB
+                        "mov %B0,%C0"     CR_TAB
+                        "mov %C0,%D0"     CR_TAB
+                        "mov %D0,__tmp_reg__", op, plen, 15);
+
+  case 7:
+    if (optimize_size)
+      break;  /* scratch ? 7 : 8 */
+    return avr_asm_len ("lsl %A0"         CR_TAB
+                        "rol %B0"         CR_TAB
+                        "rol %C0"         CR_TAB
+                        "rol %D0"         CR_TAB
+                        "mov %A0,%B0"     CR_TAB
+                        "mov %B0,%C0"     CR_TAB
+                        "mov %C0,%D0"     CR_TAB
+                        "sbc %D0,%D0"     CR_TAB
+                        "neg %D0", op, plen, 9);
+
+  case 8:
+  case 9:
+  case 10:
+  case 11:
+  case 12:
+  case 13:
+  case 14:
+  case 15:
+    {
     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");
+        avr_asm_len("mov %A0,%B1" CR_TAB
+                    "mov %B0,%C1" CR_TAB
+                    "mov %C0,%D1" CR_TAB
+                    "clr %D0", op, plen, 4);
     else
-      return ("clr %D0"     CR_TAB
-      "mov %C0,%D1" CR_TAB
-      "mov %B0,%C1" CR_TAB
-      "mov %A0,%B1");
-  }
-
- case 16:
-  {
+        avr_asm_len("clr %D0"     CR_TAB
+                    "mov %C0,%D1" CR_TAB
+                    "mov %B0,%C1" CR_TAB
+                    "mov %A0,%B1", op, plen, 4);
+      op[2] = GEN_INT((INTVAL (operands[2])) - 8);
+      return avr_out_lshrpsi3(insn, op, plen);
+    }
+
+  case 16:
+  case 17:
+  case 18:
+  case 19:
+  case 20:
+  case 21:
+  case 22:
+  case 23:
+    {
     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");
+        avr_asm_len("clr %C0"     CR_TAB
+                    "clr %D0", op, plen, 2);
     if (AVR_HAVE_MOVW)
-      return *len = 3, ("movw %A0,%C1" CR_TAB
- "clr %C0"      CR_TAB
- "clr %D0");
+        avr_asm_len("movw %A0,%C1" CR_TAB
+                    "clr %C0"      CR_TAB
+                    "clr %D0", op, plen, 3);
     else
-      return *len = 4, ("mov %B0,%D1" CR_TAB
- "mov %A0,%C1" CR_TAB
- "clr %C0"     CR_TAB
- "clr %D0");
-  }
-
- case 24:
-  return *len = 4, ("mov %A0,%D1" CR_TAB
-    "clr %B0"     CR_TAB
-    "clr %C0"     CR_TAB
-    "clr %D0");
-
- case 31:
-  *len = 6;
-  return ("clr %A0"    CR_TAB
+        avr_asm_len("mov %B0,%D1" CR_TAB
+                    "mov %A0,%C1" CR_TAB
+                    "clr %C0"     CR_TAB
+                    "clr %D0", op, plen, 4);
+      op[2] = GEN_INT((INTVAL (operands[2])) - 16);
+      return lshrhi3_out(insn, op, plen);
+    }
+
+  case 24:
+  case 25:
+  case 26:
+  case 27:
+  case 28:
+  case 29:
+  case 30:
+    {
+      avr_asm_len("mov %A0,%D1" CR_TAB
+                  "clr %B0"     CR_TAB
+                  "clr %C0"     CR_TAB
+                  "clr %D0", op, plen, 4);
+      op[2] = GEN_INT((INTVAL (operands[2])) - 24);
+      return lshrqi3_out(insn, op, plen);
+    }
+
+  case 31:
+    return avr_asm_len ("clr %A0"    CR_TAB
   "sbrc %D0,7" CR_TAB
   "inc %A0"    CR_TAB
   "clr %B0"    CR_TAB
   "clr %C0"    CR_TAB
-  "clr %D0");
+      "clr %D0", operands, plen, 6);
  }
-      len = t;
     }
   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 "";
 }

             reply	other threads:[~2022-10-04 17:06 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-10-04 17:06 Alexander Binzberger [this message]
2022-10-12 17:57 ` Jeff Law
2022-10-15 12:08   ` A. Binzberger
2022-10-29  4:52     ` Jeff Law
2022-10-15 16:10 Georg Johann Lay

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CAFFmr-7NZef+QOtv2rzcvu4Sc66sTsikGf_gju_fFgGGwi0m_w@mail.gmail.com \
    --to=alexander.binzberger@gmail.com \
    --cc=gcc-patches@gcc.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).