Index: config/avr/avr.md
===================================================================
--- config/avr/avr.md	(revision 178999)
+++ config/avr/avr.md	(working copy)
@@ -128,6 +128,14 @@ (define_attr "length" ""
 		       (const_int 2))]
         (const_int 2)))
 
+;; Some complex insns don't need length adjustment and thererfore
+;; the length of these insns need not/must not be altered.
+;; It is easier to state this in an insn attribute
+;; than to clutter up avr.c:adjust_insn_length().
+(define_attr "adjust_len"
+  "yes,no,reload_in32"
+  (const_string "yes"))
+
 ;; Define mode iterators
 (define_mode_iterator QIHI  [(QI "") (HI "")])
 (define_mode_iterator QIHI2 [(QI "") (HI "")])
@@ -456,7 +464,7 @@ (define_insn "*reload_insi"
   {
     return output_reload_insisf (insn, operands, operands[2], NULL);
   }
-  [(set_attr "length" "8")
+  [(set_attr "adjust_len" "reload_in32")
    (set_attr "cc" "clobber")])
 
 
@@ -466,7 +474,7 @@ (define_insn "*movsi"
   "(register_operand (operands[0],SImode)
     || register_operand (operands[1],SImode) || const0_rtx == operands[1])"
   {
-    return output_movsisf (insn, operands, NULL_RTX, NULL);
+    return output_movsisf (insn, operands, NULL);
   }
   [(set_attr "length" "4,4,8,9,4,10")
    (set_attr "cc" "none,set_zn,clobber,clobber,clobber,clobber")])
@@ -495,7 +503,7 @@ (define_insn "*movsf"
    || register_operand (operands[1], SFmode)
    || operands[1] == CONST0_RTX (SFmode)"
   {
-    return output_movsisf (insn, operands, NULL_RTX, NULL);
+    return output_movsisf (insn, operands, NULL);
   }
   [(set_attr "length" "4,4,8,9,4,10")
    (set_attr "cc" "none,set_zn,clobber,clobber,clobber,clobber")])
@@ -520,7 +528,7 @@ (define_insn "*reload_insf"
   {
     return output_reload_insisf (insn, operands, operands[2], NULL);
   }
-  [(set_attr "length" "8")
+  [(set_attr "adjust_len" "reload_in32")
    (set_attr "cc" "clobber")])
 
 ;;=========================================================================
Index: config/avr/avr-protos.h
===================================================================
--- config/avr/avr-protos.h	(revision 178999)
+++ config/avr/avr-protos.h	(working copy)
@@ -56,7 +56,7 @@ extern const char *out_movhi_r_mr (rtx i
 extern const char *out_movhi_mr_r (rtx insn, rtx op[], int *l);
 extern const char *out_movsi_r_mr (rtx insn, rtx op[], int *l);
 extern const char *out_movsi_mr_r (rtx insn, rtx op[], int *l);
-extern const char *output_movsisf (rtx insn, rtx operands[], rtx clobber, int *l);
+extern const char *output_movsisf (rtx insn, rtx operands[], int *l);
 extern const char *out_tstsi (rtx insn, rtx src, int *l);
 extern const char *out_tsthi (rtx insn, rtx src, int *l);
 extern const char *ret_cond_branch (rtx x, int len, int reverse);
Index: config/avr/avr.c
===================================================================
--- config/avr/avr.c	(revision 178999)
+++ config/avr/avr.c	(working copy)
@@ -2673,7 +2673,7 @@ out_movsi_mr_r (rtx insn, rtx op[], int
 }
 
 const char *
-output_movsisf (rtx insn, rtx operands[], rtx clobber_reg, int *l)
+output_movsisf (rtx insn, rtx operands[], int *l)
 {
   int dummy;
   rtx dest = operands[0];
@@ -2719,7 +2719,7 @@ output_movsisf (rtx insn, rtx operands[]
       else if (CONST_INT_P (src)
                || CONST_DOUBLE_P (src))
         {
-          return output_reload_insisf (insn, operands, clobber_reg, real_l);
+          return output_reload_insisf (insn, operands, NULL_RTX, real_l);
         }
       else if (CONSTANT_P (src))
 	{
@@ -4616,8 +4616,56 @@ avr_rotate_bytes (rtx operands[])
 int
 adjust_insn_length (rtx insn, int len)
 {
-  rtx patt = PATTERN (insn);
-  rtx set;
+  rtx patt, set;
+  enum attr_adjust_len adjust_len;
+
+  /* Some complex insns don't need length adjustment and therefore
+     the length need not/must not be adjusted for these insns.
+     It is easier to state this in an insn attribute "adjust_len" than
+     to clutter up code here...  */
+  
+  if (-1 == recog_memoized (insn))
+    {
+      return len;
+    }
+
+  /* Read from insn attribute "adjust_len" if/how length is to be adjusted.  */
+
+  adjust_len = get_attr_adjust_len (insn);
+
+  if (adjust_len != ADJUST_LEN_YES)
+    {
+      rtx *op = recog_data.operand;
+      
+      if (adjust_len == ADJUST_LEN_NO)
+        {
+          /* Nothing to adjust: The length from attribute "length" is fine.  */
+          
+          return len;
+        }
+
+      /* Extract insn's operands.  */
+      
+      extract_insn_cached (insn);
+
+      /* Dispatch to right function.  */
+      
+      switch (adjust_len)
+        {
+        case ADJUST_LEN_RELOAD_IN32:
+          output_reload_insisf (insn, op, op[2], &len);
+          break;
+          
+        default:
+          gcc_unreachable();
+        }
+      
+      return len;
+    } /* adjust_length != ADJUST_LEN_YES */
+
+  /* adjust_len == "yes": Analyse insn by hand.  */
+  
+  patt = PATTERN (insn);
 
   if (GET_CODE (patt) == SET)
     {
@@ -4637,7 +4685,7 @@ adjust_insn_length (rtx insn, int len)
 	      break;
 	    case SImode:
 	    case SFmode:
-	      output_movsisf (insn, op, NULL_RTX, &len);
+	      output_movsisf (insn, op, &len);
 	      break;
 	    default:
 	      break;
@@ -4708,7 +4756,8 @@ adjust_insn_length (rtx insn, int len)
 	      break;
 	    case SImode:
 	    case SFmode:
-	      output_reload_insisf (insn, op, XEXP (op[2], 0), &len);
+	      /* Handled by ADJUST_LEN_RELOAD_INSISF above.  */
+	      gcc_unreachable();
 	      break;
 	    default:
 	      break;
@@ -6698,21 +6747,17 @@ output_reload_inhi (rtx insn ATTRIBUTE_U
 }
 
 
-/* Reload a SI or SF compile time constant (OP[1]) into a GPR (OP[0]).
-   CLOBBER_REG is a QI clobber reg needed to move vast majority of consts
-   into a NO_LD_REGS.  If CLOBBER_REG is NULL_RTX we either don't need a
-   clobber reg or have to cook one up.
-
-   LEN == NULL: Output instructions.
-   
-   LEN != NULL: Output nothing.  Increment *LEN by number of words occupied
-                by the insns printed.
-
-   Return "".  */
+/* A helper for `output_reload_insisf'.  */
+/* Set 32-bit register OP[0] to compile-time constant OP[1].
+   CLOBBER_REG is a QI clobber register or NULL_RTX.
+   LEN == NULL: output instructions.
+   LEN != NULL: set *LEN to the length of the instruction sequence
+                (in words) printed with LEN = NULL.
+   If CLEAR_P is true, OP[0] had been cleard to Zero already.
+   If CLEAR_P is false, nothing is known about OP[0].  */
 
-const char *
-output_reload_insisf (rtx insn ATTRIBUTE_UNUSED,
-                      rtx *op, rtx clobber_reg, int *len)
+static void
+output_reload_insisf_1 (rtx *op, rtx clobber_reg, int *len, bool clear_p)
 {
   rtx src = op[1];
   rtx dest = op[0];
@@ -6787,7 +6832,12 @@ output_reload_insisf (rtx insn ATTRIBUTE
 
           if (INTVAL (lo16) == INTVAL (hi16))
             {
-              avr_asm_len ("movw %C0,%A0", &op[0], len, 1);
+              if (0 != INTVAL (lo16)
+                  || !clear_p)
+                {
+                  avr_asm_len ("movw %C0,%A0", &op[0], len, 1);
+                }
+              
               break;
             }
         }
@@ -6797,7 +6847,9 @@ output_reload_insisf (rtx insn ATTRIBUTE
       
       if (ival[n] == 0)
         {
-          avr_asm_len ("clr %0", &xdest[n], len, 1);
+          if (!clear_p)
+            avr_asm_len ("clr %0", &xdest[n], len, 1);
+          
           continue;
         }
 
@@ -6837,8 +6889,18 @@ output_reload_insisf (rtx insn ATTRIBUTE
       
       if (-1 == ival[n])
         {
-          avr_asm_len ("clr %0" CR_TAB
-                       "dec %0", &xdest[n], len, 2);
+          if (!clear_p)
+            avr_asm_len ("clr %0", &xdest[n], len, 1);
+          
+          avr_asm_len ("dec %0", &xdest[n], len, 1);
+          continue;
+        }
+      else if (1 == ival[n])
+        {
+          if (!clear_p)
+            avr_asm_len ("clr %0", &xdest[n], len, 1);
+          
+          avr_asm_len ("inc %0", &xdest[n], len, 1);
           continue;
         }
 
@@ -6848,13 +6910,6 @@ output_reload_insisf (rtx insn ATTRIBUTE
       if (NULL_RTX == clobber_reg
           && single_one_operand (xval, QImode))
         {
-          if (1 == ival[n])
-            {
-              avr_asm_len ("clr %0" CR_TAB
-                           "inc %0", &xdest[n], len, 2);
-              continue;
-            }
-          
           xop[0] = xdest[n];
           xop[1] = GEN_INT (exact_log2 (ival[n] & GET_MODE_MASK (QImode)));
 
@@ -6866,8 +6921,10 @@ output_reload_insisf (rtx insn ATTRIBUTE
               avr_asm_len ("set", xop, len, 1);
             }
 
-          avr_asm_len ("clr %0" CR_TAB
-                       "bld %0,%1", xop, len, 2);
+          if (!clear_p)
+            avr_asm_len ("clr %0", xop, len, 1);
+          
+          avr_asm_len ("bld %0,%1", xop, len, 1);
           continue;
         }
 
@@ -6890,7 +6947,68 @@ output_reload_insisf (rtx insn ATTRIBUTE
     {
       avr_asm_len ("mov %0,__tmp_reg__", &clobber_reg, len, 1);
     }
-  
+}
+
+
+/* Reload a SI or SF compile time constant OP[1] into the register OP[0].
+   CLOBBER_REG is a QI clobber reg needed to move vast majority of consts
+   into a NO_LD_REGS register.  If CLOBBER_REG is NULL_RTX we either don't
+   need a clobber reg or have to cook one up.
+
+   LEN == NULL: Output instructions.
+   
+   LEN != NULL: Output nothing.  Increment *LEN by number of words occupied
+                by the insns printed.
+
+   Return "".  */
+
+const char *
+output_reload_insisf (rtx insn ATTRIBUTE_UNUSED,
+                      rtx *op, rtx clobber_reg, int *len)
+{
+  gcc_assert (REG_P (op[0])
+              && CONSTANT_P (op[1]));
+
+  if (AVR_HAVE_MOVW
+      && !test_hard_reg_class (LD_REGS, op[0]))
+    {
+      int len_clr, len_noclr;
+      
+      /* In some cases it is better to clear the destination beforehand, e.g.
+
+             CLR R2   CLR R3   MOVW R4,R2   INC R2
+
+         is shorther than
+
+             CLR R2   INC R2   CLR  R3      CLR R4   CLR R5
+
+         We find it too tedious to work that out in the print function.
+         Instead, we call the print function twice to get the lengths of
+         both methods and use the shortest one.  */
+         
+      output_reload_insisf_1 (op, clobber_reg, &len_clr, true);
+      output_reload_insisf_1 (op, clobber_reg, &len_noclr, false);
+      
+      if (len_noclr - len_clr == 4)
+        {
+          /* Default needs 4 CLR instructions: clear register beforehand.  */
+          
+          avr_asm_len ("clr %A0" CR_TAB
+                       "clr %B0" CR_TAB
+                       "movw %C0,%A0", &op[0], len, 3);
+          
+          output_reload_insisf_1 (op, clobber_reg, len, true);
+          
+          if (len)
+            *len += 3;
+
+          return "";
+        }
+    }
+
+  /* Default: destination not pre-cleared.  */
+
+  output_reload_insisf_1 (op, clobber_reg, len, false);
   return "";
 }
 
