OSDN Git Service

* calls.c, function.c: Always define PREFERRED_STACK_BOUNDARY
[pf3gnuchains/gcc-fork.git] / gcc / config / avr / avr.c
index fbb96cf..cb222b2 100644 (file)
@@ -1,5 +1,5 @@
 /* Subroutines for insn-output.c for ATMEL AVR micro controllers
-   Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
    Contributed by Denis Chertykov (denisc@overta.ru)
 
    This file is part of GNU CC.
@@ -27,7 +27,6 @@
 #include "real.h"
 #include "insn-config.h"
 #include "conditions.h"
-#include "insn-flags.h"
 #include "output.h"
 #include "insn-attr.h"
 #include "flags.h"
@@ -39,6 +38,8 @@
 #include "function.h"
 #include "recog.h"
 #include "tm_p.h"
+#include "target.h"
+#include "target-def.h"
 
 /* Maximal allowed offset for an address in the LD command */
 #define MAX_LD_OFFSET(MODE) (64 - (signed)GET_MODE_SIZE (MODE))
@@ -47,9 +48,20 @@ static int    avr_naked_function_p PARAMS ((tree));
 static int    interrupt_function_p PARAMS ((tree));
 static int    signal_function_p    PARAMS ((tree));
 static int    sequent_regs_live    PARAMS ((void));
-static char * ptrreg_to_str        PARAMS ((int));
-static char * cond_string          PARAMS ((enum rtx_code));
-
+static const char * ptrreg_to_str  PARAMS ((int));
+static const char * cond_string    PARAMS ((enum rtx_code));
+static int    avr_num_arg_regs     PARAMS ((enum machine_mode, tree));
+static int    out_adj_frame_ptr    PARAMS ((FILE *, int));
+static int    out_set_stack_ptr    PARAMS ((FILE *, int, int));
+static RTX_CODE compare_condition  PARAMS ((rtx insn));
+static int    compare_sign_p       PARAMS ((rtx insn));
+static int    reg_was_0            PARAMS ((rtx insn, rtx op));
+static int    io_address_p         PARAMS ((rtx x, int size));
+void          debug_hard_reg_set   PARAMS ((HARD_REG_SET set));
+static int    avr_valid_type_attribute PARAMS ((tree, tree, tree, tree));
+static int    avr_valid_decl_attribute PARAMS ((tree, tree, tree, tree));
+static void   avr_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));
+static void   avr_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
 
 /* Allocate registers from r25 to r8 for parameters for function calls */
 #define FIRST_CUM_REG 26
@@ -60,8 +72,12 @@ rtx tmp_reg_rtx;
 /* Zeroed register RTX (gen_rtx (REG,QImode,ZERO_REGNO)) */
 rtx zero_reg_rtx;
 
+/* RTX for register which will be used for loading immediate values to
+   r0-r15 registers.  */
+rtx ldi_reg_rtx;
+
 /* AVR register names {"r0", "r1", ..., "r31"} */
-char * avr_regnames[] = REGISTER_NAMES;
+const char * avr_regnames[] = REGISTER_NAMES;
 
 /* This holds the last insn address.  */
 static int last_insn_address = 0;
@@ -79,57 +95,133 @@ static int commands_in_epilogues;
 static int prologue_size;
 static int epilogue_size;
 
-/* Initial stack value specified by the `-minit-stack=' option */
-const char *avr_ram_end = NULL;
+/* Size of all jump tables in the current function, in words.  */
+static int jump_tables_size;
 
-/* Numeric representation */
-static const char *initial_stack;
+/* Initial stack value specified by the `-minit-stack=' option */
+const char *avr_init_stack = "__stack";
 
 /* Default MCU name */
-const char *avr_mcu_name = "at90s8515";
-
-/* Default MCU */
-struct mcu_type_s *avr_mcu_type;
-
-/* MCU names, initial stack value, flag 'mega' */
-static struct mcu_type_s mcu_types[] =
-{{"at90s2313", 224-1, 0},
- {"at90s2323", 224-1, 0},
- {"at90s2333", 224-1, 0},
- {"attiny22",  224-1, 0},
- {"at90s2343", 224-1, 0},
- {"at90s4433", 224-1, 0},
- {"at90s4414", 0x15f, 0},
- {"at90s4434", 0x15f, 0},
- {"at90s8515", 0x25f, 0},
- {"at90s8535", 0x25f, 0},
- {"atmega603", 0x0fff,1},
- {"atmega103", 0x0fff,1},
- {NULL,0,0}};
-
-/* Setup MCU */
+const char *avr_mcu_name = "avr2";
+
+/* More than 8K of program memory: use "call" and "jmp".  */
+int avr_mega_p = 0;
+
+/* Enhanced core: use "movw", "mul", ...  */
+int avr_enhanced_p = 0;
+
+enum avr_arch {
+  AVR1 = 1,
+  AVR2,
+  AVR3,
+  AVR4,
+  AVR5
+};
 
+struct mcu_type_s {
+  const char *name;
+  enum avr_arch arch;
+};
+
+/* List of all known AVR MCU types - if updated, it has to be kept
+   in sync in several places (FIXME: is there a better way?):
+    - here
+    - avr.h (CPP_SPEC, LINK_SPEC, CRT_BINUTILS_SPECS)
+    - t-avr (MULTILIB_MATCHES)
+    - gas/config/tc-avr.c
+    - avr-libc  */
+
+static const struct mcu_type_s avr_mcu_types[] = {
+    /* Classic, <= 8K.  */
+  { "avr2",      AVR2 },
+  { "at90s2313", AVR2 },
+  { "at90s2323", AVR2 },
+  { "attiny22",  AVR2 },
+  { "at90s2333", AVR2 },
+  { "at90s2343", AVR2 },
+  { "at90s4414", AVR2 },
+  { "at90s4433", AVR2 },
+  { "at90s4434", AVR2 },
+  { "at90s8515", AVR2 },
+  { "at90c8534", AVR2 },
+  { "at90s8535", AVR2 },
+    /* Classic, > 8K.  */
+  { "avr3",      AVR3 },
+  { "atmega103", AVR3 },
+  { "atmega603", AVR3 },
+    /* Enhanced, <= 8K.  */
+  { "avr4",      AVR4 },
+  { "atmega83",  AVR4 },
+  { "atmega85",  AVR4 },
+    /* Enhanced, > 8K.  */
+  { "avr5",      AVR5 },
+  { "atmega161", AVR5 },
+  { "atmega163", AVR5 },
+  { "atmega32",  AVR5 },
+  { "at94k",     AVR5 },
+    /* Assembler only.  */
+  { "avr1",      AVR1 },
+  { "at90s1200", AVR1 },
+  { "attiny10",  AVR1 },
+  { "attiny11",  AVR1 },
+  { "attiny12",  AVR1 },
+  { "attiny15",  AVR1 },
+  { "attiny28",  AVR1 },
+  { NULL, 0 }
+};
+
+int avr_case_values_threshold = 30000;
+\f
+/* Initialize the GCC target structure.  */
+#undef TARGET_ASM_FUNCTION_PROLOGUE
+#define TARGET_ASM_FUNCTION_PROLOGUE avr_output_function_prologue
+#undef TARGET_ASM_FUNCTION_EPILOGUE
+#define TARGET_ASM_FUNCTION_EPILOGUE avr_output_function_epilogue
+#undef TARGET_VALID_DECL_ATTRIBUTE
+#define TARGET_VALID_DECL_ATTRIBUTE avr_valid_decl_attribute
+
+#undef TARGET_VALID_TYPE_ATTRIBUTE
+#define TARGET_VALID_TYPE_ATTRIBUTE avr_valid_type_attribute
+
+struct gcc_target targetm = TARGET_INITIALIZER;
+\f
 void
-avr_override_options (void)
+avr_override_options ()
 {
-  for (avr_mcu_type = mcu_types; avr_mcu_type->name; ++avr_mcu_type)
-    if (strcmp (avr_mcu_type->name, avr_mcu_name) == 0)
+  const struct mcu_type_s *t;
+
+  for (t = avr_mcu_types; t->name; t++)
+    if (strcmp (t->name, avr_mcu_name) == 0)
       break;
-  if (!avr_mcu_type->name)
+
+  if (!t->name)
+    {
+      fprintf (stderr, "Unknown MCU `%s' specified\nKnown MCU names:\n",
+              avr_mcu_name);
+      for (t = avr_mcu_types; t->name; t++)
+       fprintf (stderr,"   %s\n", t->name);
+    }
+
+  switch (t->arch)
     {
-      int i;
-      fprintf (stderr,
-              "Wrong mcu `%s' specified\n"
-              "Allowed mcu's:\n", avr_mcu_name);
-      for (i = 0; mcu_types[i].name; ++i)
-       fprintf (stderr,"   %s\n", mcu_types[i].name);
-      fatal ("select right mcu name");
+    case AVR1:
+    default:
+      error ("MCU `%s' not supported", avr_mcu_name);
+      /* ... fall through ... */
+    case AVR2: avr_enhanced_p = 0; avr_mega_p = 0; break;
+    case AVR3: avr_enhanced_p = 0; avr_mega_p = 1; break;
+    case AVR4: avr_enhanced_p = 1; avr_mega_p = 0; break;
+    case AVR5: avr_enhanced_p = 1; avr_mega_p = 1; break;
     }
+
+  if (optimize && !TARGET_NO_TABLEJUMP)
+    avr_case_values_threshold = (!AVR_MEGA || TARGET_CALL_PROLOGUES) ? 8 : 17;
 }
 
+
 /* Initialize TMP_REG_RTX and ZERO_REG_RTX */
 void
-avr_init_once (void)
+avr_init_once ()
 {
   tmp_reg_rtx = xmalloc (sizeof (struct rtx_def) + 1 * sizeof (rtunion));
   memset (tmp_reg_rtx, 0, sizeof (struct rtx_def) + 1 * sizeof (rtunion));
@@ -142,6 +234,12 @@ avr_init_once (void)
   PUT_CODE (zero_reg_rtx, REG);
   PUT_MODE (zero_reg_rtx, QImode);
   XINT (zero_reg_rtx, 0) = ZERO_REGNO;
+
+  ldi_reg_rtx = xmalloc (sizeof (struct rtx_def) + 1 * sizeof (rtunion));
+  memset (ldi_reg_rtx, 0, sizeof (struct rtx_def) + 1 * sizeof (rtunion));
+  PUT_CODE (ldi_reg_rtx, REG);
+  PUT_MODE (ldi_reg_rtx, QImode);
+  XINT (ldi_reg_rtx, 0) = LDI_REG_REGNO;
 }
 
 /*  return register class from register number */
@@ -251,9 +349,9 @@ signal_function_p (func)
 /* Compute offset between arg_pointer and frame_pointer */
 
 int
-initial_elimination_offset (from,to)
-     int from ATTRIBUTE_UNUSED;
-     int to ATTRIBUTE_UNUSED;
+initial_elimination_offset (from, to)
+     int from;
+     int to;
 {
   int reg;
   if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
@@ -332,10 +430,124 @@ sequent_regs_live ()
 }
 
 
+/* Output to FILE the asm instructions to adjust the frame pointer by
+   ADJ (r29:r28 -= ADJ;) which can be positive (prologue) or negative
+   (epilogue).  Returns the number of instructions generated.  */
+
+static int
+out_adj_frame_ptr (file, adj)
+     FILE *file;
+     int adj;
+{
+  int size = 0;
+
+  if (adj)
+    {
+      if (TARGET_TINY_STACK)
+       {
+         if (adj < -63 || adj > 63)
+           warning ("large frame pointer change (%d) with -mtiny-stack", adj);
+
+         /* The high byte (r29) doesn't change - prefer "subi" (1 cycle)
+            over "sbiw" (2 cycles, same size).  */
+
+         fprintf (file, (AS2 (subi, r28, %d) CR_TAB), adj);
+         size++;
+       }
+      else if (adj < -63 || adj > 63)
+       {
+         fprintf (file, (AS2 (subi, r28, lo8(%d)) CR_TAB
+                         AS2 (sbci, r29, hi8(%d)) CR_TAB),
+                  adj, adj);
+         size += 2;
+       }
+      else if (adj < 0)
+       {
+         fprintf (file, (AS2 (adiw, r28, %d) CR_TAB), -adj);
+         size++;
+       }
+      else
+       {
+         fprintf (file, (AS2 (sbiw, r28, %d) CR_TAB), adj);
+         size++;
+       }
+    }
+  return size;
+}
+
+
+/* Output to FILE the asm instructions to copy r29:r28 to SPH:SPL,
+   handling various cases of interrupt enable flag state BEFORE and AFTER
+   (0=disabled, 1=enabled, -1=unknown/unchanged) and target_flags.
+   Returns the number of instructions generated.  */
+
+static int
+out_set_stack_ptr (file, before, after)
+     FILE *file;
+     int before;
+     int after;
+{
+  int do_sph, do_cli, do_save, do_sei, lock_sph, size;
+
+  /* The logic here is so that -mno-interrupts actually means
+     "it is safe to write SPH in one instruction, then SPL in the
+     next instruction, without disabling interrupts first".
+     The after != -1 case (interrupt/signal) is not affected.  */
+
+  do_sph = !TARGET_TINY_STACK;
+  lock_sph = do_sph && !TARGET_NO_INTERRUPTS;
+  do_cli = (before != 0 && (after == 0 || lock_sph));
+  do_save = (do_cli && before == -1 && after == -1);
+  do_sei = ((do_cli || before != 1) && after == 1);
+  size = 1;
+
+  if (do_save)
+    {
+      fprintf (file, AS2 (in, __tmp_reg__, __SREG__) CR_TAB);
+      size++;
+    }
+
+  if (do_cli)
+    {
+      fprintf (file, "cli" CR_TAB);
+      size++;
+    }
+
+  /* Do SPH first - maybe this will disable interrupts for one instruction
+     someday (a suggestion has been sent to avr@atmel.com for consideration
+     in future devices - that would make -mno-interrupts always safe).  */
+  if (do_sph)
+    {
+      fprintf (file, AS2 (out, __SP_H__, r29) CR_TAB);
+      size++;
+    }
+
+  /* Set/restore the I flag now - interrupts will be really enabled only
+     after the next instruction.  This is not clearly documented, but
+     believed to be true for all AVR devices.  */
+  if (do_save)
+    {
+      fprintf (file, AS2 (out, __SREG__, __tmp_reg__) CR_TAB);
+      size++;
+    }
+  else if (do_sei)
+    {
+      fprintf (file, "sei" CR_TAB);
+      size++;
+    }
+
+  fprintf (file, AS2 (out, __SP_L__, r28) "\n");
+
+  return size;
+}
+
+
 /* Output function prologue */
 
-void
-function_prologue (FILE *file, int size)
+static void
+avr_output_function_prologue (file, size)
+     FILE *file;
+     HOST_WIDE_INT size;
 {
   int reg;
   int interrupt_func_p;
@@ -354,12 +566,13 @@ function_prologue (FILE *file, int size)
   interrupt_func_p = interrupt_function_p (current_function_decl);
   signal_func_p = signal_function_p (current_function_decl);
   leaf_func_p = leaf_function_p ();
-  main_p = ! strcmp ("main", current_function_name);
+  main_p = MAIN_NAME_P (DECL_NAME (current_function_decl));
   live_seq = sequent_regs_live ();
   minimize = (TARGET_CALL_PROLOGUES
              && !interrupt_func_p && !signal_func_p && live_seq);
 
   last_insn_address = 0;
+  jump_tables_size = 0;
   prologue_size = 0;
   fprintf (file, "/* prologue: frame size=%d */\n", size);
   
@@ -381,19 +594,19 @@ function_prologue (FILE *file, int size)
   if (main_p)
     {
       fprintf (file, ("\t" 
-                     AS2 (ldi, r28, lo8(%s - %d)) CR_TAB
-                     AS2 (ldi, r29, hi8(%s - %d)) CR_TAB
-                     AS2 (out,__SP_L__,r28)       CR_TAB
-                     AS2 (out,__SP_H__,r29) "\n"),
-              initial_stack, size, initial_stack, size);
+                     AS2 (ldi,r28,lo8(%s - %d)) CR_TAB
+                     AS2 (ldi,r29,hi8(%s - %d)) CR_TAB
+                     AS2 (out,__SP_H__,r29)     CR_TAB
+                     AS2 (out,__SP_L__,r28) "\n"),
+              avr_init_stack, size, avr_init_stack, size);
       
       prologue_size += 4;
     }
   else if (minimize && (frame_pointer_needed || live_seq > 6)) 
     {
       fprintf (file, ("\t"
-                     AS2 (ldi, r26, %d) CR_TAB
-                     AS2 (ldi, r27, %d) CR_TAB), size & 0xff, size / 0x100);
+                     AS2 (ldi, r26, lo8(%d)) CR_TAB
+                     AS2 (ldi, r27, hi8(%d)) CR_TAB), size, size);
 
       fprintf (file, (AS2 (ldi, r30, pm_lo8(.L_%s_body)) CR_TAB
                      AS2 (ldi, r31, pm_hi8(.L_%s_body)) CR_TAB)
@@ -444,44 +657,20 @@ function_prologue (FILE *file, int size)
            prologue_size += 4;
            if (size)
              {
-               if (size > 63)
-                 {
-                   fprintf (file, ("\t"
-                                   AS2 (subi,r28,%d) CR_TAB
-                                   AS2 (sbci,r29,%d) CR_TAB)
-                            , size & 0xff, size / 0x100);
-                   prologue_size += 2;
-                 }
-               else
-                 {
-                   fprintf (file, "\t" AS2 (sbiw,r28,%d) CR_TAB, size);
-                   ++prologue_size;
-                 }
+               fputs ("\t", file);
+               prologue_size += out_adj_frame_ptr (file, size);
+
                if (interrupt_func_p)
                  {
-                   fprintf (file,
-                            "cli" CR_TAB
-                            AS2 (out,__SP_L__,r28) CR_TAB
-                            "sei" CR_TAB
-                            AS2 (out,__SP_H__,r29) "\n");
-                   prologue_size += 4;
+                   prologue_size += out_set_stack_ptr (file, 1, 1);
                  }
-               else if (signal_func_p || TARGET_NO_INTERRUPTS)
+               else if (signal_func_p)
                  {
-                   fprintf (file,
-                            AS2 (out,__SP_L__,r28) CR_TAB
-                            AS2 (out,__SP_H__,r29) "\n");
-                   prologue_size += 2;
+                   prologue_size += out_set_stack_ptr (file, 0, 0);
                  }
                else
                  {
-                   fprintf (file,
-                            AS2 (in,__tmp_reg__,__SREG__) CR_TAB
-                            "cli" CR_TAB
-                            AS2 (out,__SP_L__,r28) CR_TAB
-                            AS2 (out,__SREG__,__tmp_reg__) CR_TAB
-                            AS2 (out,__SP_H__,r29) "\n");
-                   prologue_size += 5;
+                   prologue_size += out_set_stack_ptr (file, -1, -1);
                  }
              }
          }
@@ -492,8 +681,10 @@ function_prologue (FILE *file, int size)
 
 /* Output function epilogue */
 
-void
-function_epilogue (FILE *file, int size)
+static void
+avr_output_function_epilogue (file, size)
+     FILE *file;
+     HOST_WIDE_INT size;
 {
   int reg;
   int interrupt_func_p;
@@ -513,9 +704,10 @@ function_epilogue (FILE *file, int size)
   interrupt_func_p = interrupt_function_p (current_function_decl);
   signal_func_p = signal_function_p (current_function_decl);
   leaf_func_p = leaf_function_p ();
-  main_p = ! strcmp ("main", current_function_name);
-  function_size = (insn_addresses[INSN_UID (get_last_insn ())]
-                  - insn_addresses[INSN_UID (get_insns ())]);
+  main_p = MAIN_NAME_P (DECL_NAME (current_function_decl));
+  function_size = (INSN_ADDRESSES (INSN_UID (get_last_insn ()))
+                  - INSN_ADDRESSES (INSN_UID (get_insns ())));
+  function_size += jump_tables_size;
   live_seq = sequent_regs_live ();
   minimize = (TARGET_CALL_PROLOGUES
              && !interrupt_func_p && !signal_func_p && live_seq);
@@ -533,20 +725,7 @@ function_epilogue (FILE *file, int size)
       ++epilogue_size;
       if (frame_pointer_needed)
        {
-         if (size)
-           {
-             if (size > 63)
-               {
-                 fprintf (file, AS2 (subi,r28,lo8(-%d)) CR_TAB, size);
-                 fprintf (file, AS2 (sbci,r29,hi8(-%d)) CR_TAB, size);
-                 epilogue_size += 2;
-               }
-             else
-               {
-                 fprintf (file, AS2 (adiw,r28,%d) CR_TAB, size);
-                 ++epilogue_size;
-               }
-           }
+         epilogue_size += out_adj_frame_ptr (file, -size);
        }
       else
        {
@@ -574,41 +753,16 @@ function_epilogue (FILE *file, int size)
        {
          if (size)
            {
-             if (size > 63)
-               {
-                 fprintf (file, "\t" AS2 (subi,r28,lo8(-%d)) CR_TAB, size);
-                 fprintf (file, AS2 (sbci,r29,hi8(-%d)) CR_TAB, size);
-                 epilogue_size += 2;
-               }
-             else
-               {
-                 fprintf (file, "\t" AS2 (adiw,r28,%d) CR_TAB, size);
-                 ++epilogue_size;
-               }
+             fputs ("\t", file);
+             epilogue_size += out_adj_frame_ptr (file, -size);
+
              if (interrupt_func_p | signal_func_p)
                {
-                 fprintf (file,
-                          "cli" CR_TAB
-                          AS2 (out,__SP_L__,r28) CR_TAB
-                          AS2 (out,__SP_H__,r29) "\n");
-                 epilogue_size += 3;
-               }
-             else if (TARGET_NO_INTERRUPTS)
-               {
-                 fprintf (file,
-                          AS2 (out,__SP_L__,r28) CR_TAB
-                          AS2 (out,__SP_H__,r29) "\n");
-                 epilogue_size += 2;
+                 epilogue_size += out_set_stack_ptr (file, -1, 0);
                }
              else
                {
-                 fprintf (file,
-                          AS2 (in,__tmp_reg__,__SREG__) CR_TAB
-                          "cli" CR_TAB
-                          AS2 (out,__SP_L__,r28) CR_TAB
-                          AS2 (out,__SREG__,__tmp_reg__) CR_TAB
-                          AS2 (out,__SP_H__,r29) "\n");
-                 epilogue_size += 5;
+                 epilogue_size += out_set_stack_ptr (file, -1, -1);
                }
            }
          fprintf (file, "\t"
@@ -667,7 +821,8 @@ legitimate_address_p (mode, x, strict)
      rtx x;
      int strict;
 {
-  int r = 0;
+  enum reg_class r = NO_REGS;
+  
   if (TARGET_ALL_DEBUG)
     {
       fprintf (stderr, "mode: (%s) %s %s %s %s:",
@@ -689,9 +844,9 @@ legitimate_address_p (mode, x, strict)
     }
   if (REG_P (x) && (strict ? REG_OK_FOR_BASE_STRICT_P (x)
                     : REG_OK_FOR_BASE_NOSTRICT_P (x)))
-    r = 'R';
+    r = POINTER_REGS;
   else if (CONSTANT_ADDRESS_P (x))
-    r = 'S';
+    r = ALL_REGS;
   else if (GET_CODE (x) == PLUS
            && REG_P (XEXP (x, 0))
           && GET_CODE (XEXP (x, 1)) == CONST_INT
@@ -701,27 +856,28 @@ legitimate_address_p (mode, x, strict)
       if (fit)
        {
          if (! strict
-             || REGNO (XEXP (x,0)) == REG_Y || REGNO (XEXP (x,0)) == REG_Z)
-             r = 'Q';
+             || REGNO (XEXP (x,0)) == REG_Y
+             || REGNO (XEXP (x,0)) == REG_Z)
+           r = BASE_POINTER_REGS;
          if (XEXP (x,0) == frame_pointer_rtx
              || XEXP (x,0) == arg_pointer_rtx)
-           r = 'Q';
+           r = BASE_POINTER_REGS;
        }
       else if (frame_pointer_needed && XEXP (x,0) == frame_pointer_rtx)
-       r = 'U';
+       r = POINTER_Y_REGS;
     }
   else if ((GET_CODE (x) == PRE_DEC || GET_CODE (x) == POST_INC)
            && REG_P (XEXP (x, 0))
            && (strict ? REG_OK_FOR_BASE_STRICT_P (XEXP (x, 0))
                : REG_OK_FOR_BASE_NOSTRICT_P (XEXP (x, 0))))
     {
-      r = 'T';
+      r = POINTER_REGS;
     }
   if (TARGET_ALL_DEBUG)
     {
       fprintf (stderr, "   ret = %c\n", r);
     }
-  return r;
+  return r == NO_REGS ? 0 : (int)r;
 }
 
 /* Attempts to replace X with a valid
@@ -763,7 +919,7 @@ legitimize_address (x, oldx, mode)
 
 /* Return a pointer register name as a string */
 
-static char *
+static const char *
 ptrreg_to_str (regno)
      int regno;
 {
@@ -773,7 +929,7 @@ ptrreg_to_str (regno)
     case REG_Y: return "Y";
     case REG_Z: return "Z";
     default:
-      fatal ("register r%d isn't a pointer\n", regno);
+      abort ();
     }
   return NULL;
 }
@@ -781,7 +937,7 @@ ptrreg_to_str (regno)
 /* Return the condition name as a string.
    Used in conditional jump constructing  */
 
-static char *
+static const char *
 cond_string (code)
      enum rtx_code code;
 {
@@ -796,10 +952,6 @@ cond_string (code)
        return "pl";
       else
        return "ge";
-    case GT:
-      fatal ("Internal compiler bug: command `bgt'");
-    case LE:
-      fatal ("Internal compiler bug: command `ble'");
     case LT:
       if (cc_prev_status.flags & CC_OVERFLOW_UNUSABLE)
        return "mi";
@@ -807,10 +959,6 @@ cond_string (code)
        return "lt";
     case GEU:
       return "sh";
-    case GTU:
-      fatal ("Internal compiler bug: command `bgtu'");
-    case LEU:
-      fatal ("Internal compiler bug: command `bleu'");
     case LTU:
       return "lo";
     default:
@@ -866,10 +1014,15 @@ print_operand (file, x, code)
   if (code >= 'A' && code <= 'D')
     abcd = code - 'A';
 
-  if (REG_P (x))
+  if (code == '~')
+    {
+      if (!AVR_MEGA)
+       fputc ('r', file);
+    }
+  else if (REG_P (x))
     {
       if (x == zero_reg_rtx)
-       fprintf (file,"__zero_reg__");
+       fprintf (file, "__zero_reg__");
       else
        fprintf (file, reg_names[true_regnum (x) + abcd]);
     }
@@ -878,19 +1031,20 @@ print_operand (file, x, code)
   else if (GET_CODE (x) == MEM)
     {
       rtx addr = XEXP (x,0);
-      if (code == 'K')
-       {
-         if (CONSTANT_P (addr))
-           putc ('s', file);
-         else if (GET_CODE (addr) == PLUS)
-           putc ('d', file);
-       }
-      else if (CONSTANT_P (addr) && abcd)
+
+      if (CONSTANT_P (addr) && abcd)
        {
          fputc ('(', file);
          output_address (addr);
          fprintf (file, ")+%d", abcd);
        }
+      else if (code == 'o')
+       {
+         if (GET_CODE (addr) != PLUS)
+           fatal_insn ("Bad address, not (reg+disp):", addr);
+
+         print_operand (file, XEXP (addr, 1), 0);
+       }
       else if (GET_CODE (addr) == PLUS)
        {
          print_operand_address (file, XEXP (addr,0));
@@ -911,7 +1065,7 @@ print_operand (file, x, code)
        fatal_insn ("Internal compiler bug. Unknown mode:", x);
       REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
       REAL_VALUE_TO_TARGET_SINGLE (rv, val);
-      asm_fprintf (file, "0x%x", val);
+      asm_fprintf (file, "0x%lx", val);
     }
   else if (code == 'j')
     asm_fprintf (file, cond_string (GET_CODE (x)));
@@ -921,7 +1075,7 @@ print_operand (file, x, code)
     print_operand_address (file, x);
 }
 
-/* Recognise operand OP of mode MODE used in call instructions */
+/* Recognize operand OP of mode MODE used in call instructions */
 
 int
 call_insn_operand (op, mode)
@@ -1032,13 +1186,13 @@ class_max_nregs (class, mode)
    3 - absolute jump (only for ATmega[16]03).  */
 
 int
-avr_jump_mode (x,insn)
+avr_jump_mode (x, insn)
      rtx x;                     /* jump operand */
      rtx insn;                  /* jump insn */
 {
-  int dest_addr = insn_addresses[INSN_UID (GET_MODE (x) == LABEL_REF
-                                           ? XEXP (x, 0) : x)];
-  int cur_addr = insn_addresses[INSN_UID (insn)];
+  int dest_addr = INSN_ADDRESSES (INSN_UID (GET_MODE (x) == LABEL_REF
+                                           ? XEXP (x, 0) : x));
+  int cur_addr = INSN_ADDRESSES (INSN_UID (insn));
   int jump_distance = cur_addr - dest_addr;
   
   if (-63 <= jump_distance && jump_distance <= 62)
@@ -1051,14 +1205,19 @@ avr_jump_mode (x,insn)
   return 2;
 }
 
-/* return a AVR condition jump commands.
- LEN is a number returned by avr_jump_mode function.  */
+/* return an AVR condition jump commands.
+   X is a comparison RTX.
+   LEN is a number returned by avr_jump_mode function.
+   if REVERSE nonzero then condition code in X must be reversed.  */
 
-char *
-ret_cond_branch (cond,len)
-     RTX_CODE cond;
+const char *
+ret_cond_branch (x, len, reverse)
+     rtx x;
      int len;
+     int reverse;
 {
+  RTX_CODE cond = reverse ? reverse_condition (GET_CODE (x)) : GET_CODE (x);
+  
   switch (cond)
     {
     case GT:
@@ -1119,17 +1278,34 @@ ret_cond_branch (cond,len)
                AS1 (brsh,_PC_+4) CR_TAB
               AS1 (jmp,%0)));
     default:
-      switch (len)
-        {
-        case 1:
-          return AS1 (br%j1,%0);
-        case 2:
-          return (AS1 (br%k1,_PC_+2) CR_TAB
-                  AS1 (rjmp,%0));
-        default:
-          return (AS1 (br%k1,_PC_+4) CR_TAB
-                  AS1 (jmp,%0));
-        }
+      if (reverse)
+       {
+         switch (len)
+           {
+           case 1:
+             return AS1 (br%k1,%0);
+           case 2:
+             return (AS1 (br%j1,_PC_+2) CR_TAB
+                     AS1 (rjmp,%0));
+           default:
+             return (AS1 (br%j1,_PC_+4) CR_TAB
+                     AS1 (jmp,%0));
+           }
+       }
+       else
+         {
+           switch (len)
+             {
+             case 1:
+               return AS1 (br%j1,%0);
+             case 2:
+               return (AS1 (br%k1,_PC_+2) CR_TAB
+                       AS1 (rjmp,%0));
+             default:
+               return (AS1 (br%k1,_PC_+4) CR_TAB
+                       AS1 (jmp,%0));
+             }
+         }
     }
   return "";
 }
@@ -1159,11 +1335,12 @@ final_prescan_insn (insn, operand, num_operands)
 
   if (TARGET_INSN_SIZE_DUMP || TARGET_ALL_DEBUG)
     {
-      fprintf (asm_out_file, "/*DEBUG: 0x%x\t\t%d\t%d */\n", insn_addresses[uid],
-               insn_addresses[uid] - last_insn_address,
-              rtx_cost (PATTERN (insn),INSN));
+      fprintf (asm_out_file, "/*DEBUG: 0x%x\t\t%d\t%d */\n",
+              INSN_ADDRESSES (uid),
+               INSN_ADDRESSES (uid) - last_insn_address,
+              rtx_cost (PATTERN (insn), INSN));
     }
-  last_insn_address = insn_addresses[uid];
+  last_insn_address = INSN_ADDRESSES (uid);
 
   if (TARGET_RTL_DUMP)
     {
@@ -1173,8 +1350,7 @@ final_prescan_insn (insn, operand, num_operands)
     }
 }
 
-/* return 1 if undefined,
-   1 if always true or always false  */
+/* Return 0 if undefined, 1 if always true or always false.  */
 
 int
 avr_simplify_comparision_p (mode, operator, x)
@@ -1230,6 +1406,26 @@ init_cumulative_args (cum, fntype, libname, indirect)
     }
 }
 
+/* Returns the number of registers to allocate for a function argument.  */
+
+static int
+avr_num_arg_regs (mode, type)
+     enum machine_mode mode;
+     tree type;
+{
+  int size;
+
+  if (mode == BLKmode)
+    size = int_size_in_bytes (type);
+  else
+    size = GET_MODE_SIZE (mode);
+
+  /* Align all function arguments to start in even-numbered registers.
+     Odd-sized arguments leave holes above them.  */
+
+  return (size + 1) & ~1;
+}
+
 /* Controls whether a function argument is passed
    in a register, and which register. */
 
@@ -1240,12 +1436,11 @@ function_arg (cum, mode, type, named)
      tree type;
      int named ATTRIBUTE_UNUSED;
 {
-  int bytes;
-
-  bytes = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
+  int bytes = avr_num_arg_regs (mode, type);
 
   if (cum->nregs && bytes <= cum->nregs)
     return gen_rtx (REG, mode, cum->regno - bytes);
+
   return NULL_RTX;
 }
 
@@ -1259,9 +1454,8 @@ function_arg_advance (cum, mode, type, named)
      tree type;                 /* type of the argument or 0 if lib support */
      int named ATTRIBUTE_UNUSED; /* whether or not the argument was named */
 {
-  int bytes;
+  int bytes = avr_num_arg_regs (mode, type);
 
-  bytes = (mode == BLKmode ? int_size_in_bytes (type) : GET_MODE_SIZE (mode));
   cum->nregs -= bytes;
   cum->regno -= bytes;
 
@@ -1270,234 +1464,552 @@ function_arg_advance (cum, mode, type, named)
       cum->nregs = 0;
       cum->regno = FIRST_CUM_REG;
     }
-
-  return;
 }
 
 /***********************************************************************
   Functions for outputting various mov's for a various modes
 ************************************************************************/
-char *
-out_movqi_r_mr (insn, op, l)
+const char *
+output_movqi (insn, operands, l)
      rtx insn;
-     rtx op[];
-     int *l; /* instruction length */
+     rtx operands[];
+     int *l;
 {
-  /* We handle CONSTANT_ADDRESS_P case in adjust_insn_length */
-  if (l) *l=1;
-  if (GET_CODE (op[1]) == MEM)
+  int dummy;
+  rtx dest = operands[0];
+  rtx src = operands[1];
+  int *real_l = l;
+  
+  if (!l)
+    l = &dummy;
+
+  *l = 1;
+  
+  if (register_operand (dest, QImode))
     {
-      rtx x = XEXP (op[1],0);
-      if (GET_CODE (x) == PLUS
-         && REG_P (XEXP (x,0))
-         && GET_CODE (XEXP (x,1)) == CONST_INT)
+      if (register_operand (src, QImode)) /* mov r,r */
+       {
+         if (test_hard_reg_class (STACK_REG, dest))
+           return AS2 (out,%0,%1);
+         else if (test_hard_reg_class (STACK_REG, src))
+           return AS2 (in,%0,%1);
+         
+         return AS2 (mov,%0,%1);
+       }
+      else if (CONSTANT_P (src))
        {
-         if((INTVAL (XEXP (x,1)) - GET_MODE_SIZE (GET_MODE (op[1]))) >= 63)
+         if (test_hard_reg_class (LD_REGS, dest)) /* ldi d,i */
+           return AS2 (ldi,%0,lo8(%1));
+         
+         if (GET_CODE (src) == CONST_INT)
            {
-             int disp = INTVAL (XEXP (x,1));
-             if (REGNO (XEXP (x,0)) != REG_Y)
-               fatal_insn ("Incorrect insn:",insn);
-             if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (op[1])))
+             if (src == const0_rtx) /* mov r,L */
+               return AS1 (clr,%0);
+             else if (src == const1_rtx)
                {
-                 if (l)
-                   *l = 3;
-                 else
-                   {
-                     op[4] = GEN_INT (disp - 63);
-                     return (AS2 (adiw, r28, %4) CR_TAB
-                             AS2 (ldd, %0,Y+63)  CR_TAB
-                             AS2 (sbiw, r28, %4));
-                   }
+                 if (reg_was_0 (insn, dest))
+                   return AS1 (inc,%0 ; reg_was_0);
+
+                 *l = 2;
+                 return (AS1 (clr,%0) CR_TAB
+                         AS1 (inc,%0));
                }
-             else
+             else if (src == constm1_rtx)
                {
-                 op[4] = XEXP (x,1);
-                 if (l)
-                   *l = 5;
-                 else
-                   return (AS2 (subi, r28, lo8(-%4))  CR_TAB
-                           AS2 (sbci, r29, hi8(-%4)) CR_TAB
-                           AS2 (ld, %0,Y)              CR_TAB
-                           AS2 (subi, r28, lo8(%4))   CR_TAB
-                           AS2 (sbci, r29, hi8(%4)));
+                 /* Immediate constants -1 to any register */
+                 if (reg_was_0 (insn, dest))
+                   return AS1 (dec,%0 ; reg_was_0);
+
+                 *l = 2;
+                 return (AS1 (clr,%0) CR_TAB
+                         AS1 (dec,%0));
                }
-           }
-         else if (REGNO (XEXP (x,0)) == REG_X)
-           {
-             /* This is a paranoid case LEGITIMIZE_RELOAD_ADDRESS must exclude
-                it but I have this situation with extremal optimizing options
-             */
-             if (l)
-               *l=3;
              else
                {
-                 output_asm_insn (AS2 (adiw, r26, %0),&XEXP (x,1));
-                 output_asm_insn (AS2 (ld ,%0,X),op);
-                 if (!reg_overlap_mentioned_p (op[0],XEXP (x,0)))
-                   output_asm_insn (AS2 (sbiw, r26, %0),&XEXP (x,1));
+                 int bit_nr = exact_log2 (INTVAL (src));
+
+                 if (bit_nr >= 0)
+                   {
+                     if (reg_was_0 (insn, dest))
+                       {
+                         *l = 2;
+                         if (!real_l)
+                           output_asm_insn ("set ; reg_was_0", operands);
+                       }
+                     else
+                       {
+                         *l = 3;
+                         if (!real_l)
+                           output_asm_insn ((AS1 (clr,%0) CR_TAB
+                                             "set"), operands);
+                       }
+                     if (!real_l)
+                       avr_output_bld (operands, bit_nr);
+
+                     return "";
+                   }
                }
-             return "";
            }
+         
+         /* Last resort, larger than loading from memory.  */
+         *l = 4;
+         return (AS2 (mov,__tmp_reg__,r31) CR_TAB
+                 AS2 (ldi,r31,lo8(%1))     CR_TAB
+                 AS2 (mov,%0,r31)          CR_TAB
+                 AS2 (mov,r31,__tmp_reg__));
        }
+      else if (GET_CODE (src) == MEM)
+       return out_movqi_r_mr (insn, operands, real_l); /* mov r,m */
+    }
+  else if (GET_CODE (dest) == MEM)
+    {
+      const char *template;
+
+      if (src == const0_rtx)
+       operands[1] = zero_reg_rtx;
+
+      template = out_movqi_mr_r (insn, operands, real_l);
+
+      if (!real_l)
+       output_asm_insn (template, operands);
+
+      operands[1] = src;
     }
-  return AS2 (ld%K1,%0,%1);
+  return "";
 }
 
-char *
-out_movhi_r_mr (insn, op, l)
+
+const char *
+output_movhi (insn, operands, l)
      rtx insn;
-     rtx op[];
-     int *l; /* instruction length */
+     rtx operands[];
+     int *l;
 {
-  int reg_dest = true_regnum (op[0]);
-  int reg_base = true_regnum (XEXP (op[1],0));
-  int len_p = 1,tmp;
-  int *real_l=l;
-
+  int dummy;
+  rtx dest = operands[0];
+  rtx src = operands[1];
+  int *real_l = l;
+  
   if (!l)
-    l = &tmp, len_p = 0;
-
-  if (reg_base > 0)
-    {
-      if (reg_dest == reg_base)         /* R = (R) */
-        return *l=3, (AS2 (ld,__tmp_reg__,%1+) CR_TAB
-                      AS2 (ld,%B0,%1) CR_TAB
-                      AS2 (mov,%A0,__tmp_reg__));
-      else if (reg_base == REG_X)        /* (R26) */
-        {
-          if (reg_unused_after (insn, XEXP (op[1],0)))
-            return *l=2, (AS2 (ld,%A0,X+) CR_TAB
-                          AS2 (ld,%B0,X));
-          else
-            return *l=3, (AS2 (ld,%A0,X+) CR_TAB
-                          AS2 (ld,%B0,X) CR_TAB
-                          AS2 (sbiw,r26,1));
-        }
-      else                      /* (R)  */
-        return  *l=2, (AS2 (ld,%A0,%1)    CR_TAB
-                       AS2 (ldd,%B0,%1+1));
-    }
-  else if (GET_CODE (XEXP (op[1],0)) == PLUS) /* (R + i) */
+    l = &dummy;
+  
+  if (register_operand (dest, HImode))
     {
-      int disp = INTVAL(XEXP (XEXP (op[1],0), 1));
-      int reg_base = true_regnum (XEXP (XEXP (op[1],0), 0));
-      
-      if (disp > MAX_LD_OFFSET (GET_MODE (op[1])))
+      if (register_operand (src, HImode)) /* mov r,r */
        {
-         rtx x = XEXP (op[1],0);
-         if (REGNO (XEXP (x,0)) != REG_Y)
-           fatal_insn ("Incorrect insn:",insn);
-         if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (op[1])))
+         if (test_hard_reg_class (STACK_REG, dest))
            {
-             op[4] = GEN_INT (disp - 62);
-             return *l=4, (AS2 (adiw, r28, %4) CR_TAB
-                           AS2 (ldd, %A0,Y+62)       CR_TAB
-                           AS2 (ldd, %B0,Y+63)     CR_TAB
-                           AS2 (sbiw, r28, %4));
+             if (TARGET_TINY_STACK)
+               {
+                 *l = 1;
+                 return AS2 (out,__SP_L__,%A1);
+               }
+             else if (TARGET_NO_INTERRUPTS)
+               {
+                 *l = 2;
+                 return (AS2 (out,__SP_H__,%B1) CR_TAB
+                         AS2 (out,__SP_L__,%A1));
+               }
+
+             *l = 5;
+             return (AS2 (in,__tmp_reg__,__SREG__)  CR_TAB
+                     "cli"                          CR_TAB
+                     AS2 (out,__SP_H__,%B1)         CR_TAB
+                     AS2 (out,__SREG__,__tmp_reg__) CR_TAB
+                     AS2 (out,__SP_L__,%A1));
+           }
+         else if (test_hard_reg_class (STACK_REG, src))
+           {
+             *l = 2;   
+             return (AS2 (in,%A0,__SP_L__) CR_TAB
+                     AS2 (in,%B0,__SP_H__));
+           }
+
+         if (AVR_ENHANCED)
+           {
+             *l = 1;
+             return (AS2 (movw,%0,%1));
+           }
+
+         if (true_regnum (dest) > true_regnum (src))
+           {
+             *l = 2;
+             return (AS2 (mov,%B0,%B1) CR_TAB
+                     AS2 (mov,%A0,%A1));
            }
          else
            {
-             op[4] = XEXP (x,1);
-             return *l=6, (AS2 (subi, r28, lo8(-%4))  CR_TAB
-                           AS2 (sbci, r29, hi8(-%4)) CR_TAB
-                           AS2 (ld, %A0,Y)             CR_TAB
-                           AS2 (ldd, %B0,Y+1)          CR_TAB
-                           AS2 (subi, r28, lo8(%4))   CR_TAB
-                           AS2 (sbci, r29, hi8(%4)));
+             *l = 2;
+             return (AS2 (mov,%A0,%A1) CR_TAB
+                     AS2 (mov,%B0,%B1));
            }
        }
-      if (reg_base == REG_X)
+      else if (CONSTANT_P (src))
        {
-         /* This is a paranoid case. LEGITIMIZE_RELOAD_ADDRESS must exclude
-            it but I have this situation with extremal optimization options
-          */
-         rtx ops[1];
-         ops[0] = XEXP (XEXP (op[1],0), 1);
-         if (real_l)
-           *l = 4;
-         else if (reg_base == reg_dest)
-           {
-             output_asm_insn (AS2 (adiw, r26, %0), ops);
-             output_asm_insn (AS2 (ld , __tmp_reg__, X+), op);
-             output_asm_insn (AS2 (ld , %B0, X), op);
-             output_asm_insn (AS2 (mov, %A0, __tmp_reg__),op);
+         if (test_hard_reg_class (LD_REGS, dest)) /* ldi d,i */
+           {
+             if (byte_immediate_operand (src, HImode)
+                 && reg_was_0 (insn, dest))
+               {
+                 *l = 1;
+                 return (AS2 (ldi,%A0,lo8(%1) ; reg_was_0));
+               }
+
+             *l = 2;
+             return (AS2 (ldi,%A0,lo8(%1)) CR_TAB
+                     AS2 (ldi,%B0,hi8(%1)));
            }
-         else
+         
+         if (GET_CODE (src) == CONST_INT)
            {
-             output_asm_insn (AS2 (adiw, r26, %0), ops);
-             output_asm_insn (AS2 (ld , %A0, X+), op);
-             output_asm_insn (AS2 (ld , %B0, X), op);
-             if (INTVAL (ops[0]) == 63)
+             if (src == const0_rtx) /* mov r,L */
+               {
+                 *l = 2;
+                 return (AS1 (clr,%A0) CR_TAB
+                         AS1 (clr,%B0));
+               }
+             else if (src == const1_rtx)
                {
-                 output_asm_insn (AS2 (subi, r26, %0+1), ops);
-                 output_asm_insn (AS2 (sbci, r26, 0), ops);
+                 if (reg_was_0 (insn, dest))
+                   {
+                     *l = 1;
+                     return AS1 (inc,%0 ; reg_was_0);
+                   }
+
+                 *l = 3;
+                 return (AS1 (clr,%A0) CR_TAB
+                         AS1 (clr,%B0) CR_TAB
+                         AS1 (inc,%A0));
+               }
+             else if (src == constm1_rtx)
+               {
+                 /* Immediate constants -1 to any register */
+                 if (reg_was_0 (insn, dest))
+                   {
+                     *l = 2;
+                     return (AS1 (dec,%A0 ; reg_was_0) CR_TAB
+                             AS1 (dec,%B0));
+                   }
+
+                 *l = 3;
+                 return (AS1 (clr,%0)  CR_TAB
+                         AS1 (dec,%A0) CR_TAB
+                         AS2 (mov,%B0,%A0));
                }
              else
-               output_asm_insn (AS2 (sbiw, r26, %0+1), ops);
+               {
+                 int bit_nr = exact_log2 (INTVAL (src));
+
+                 if (bit_nr >= 0)
+                   {
+                     if (reg_was_0 (insn, dest))
+                       {
+                         *l = 2;
+                         if (!real_l)
+                           output_asm_insn ("set ; reg_was_0", operands);
+                       }
+                     else
+                       {
+                         *l = 4;
+                         if (!real_l)
+                           output_asm_insn ((AS1 (clr,%A0) CR_TAB
+                                             AS1 (clr,%B0) CR_TAB
+                                             "set"), operands);
+                       }
+                     if (!real_l)
+                       avr_output_bld (operands, bit_nr);
+
+                     return "";
+                   }
+               }
+
+             if ((INTVAL (src) & 0xff) == 0)
+               {
+                 *l = 5;
+                 return (AS2 (mov,__tmp_reg__,r31) CR_TAB
+                         AS1 (clr,%A0)             CR_TAB
+                         AS2 (ldi,r31,hi8(%1))     CR_TAB
+                         AS2 (mov,%B0,r31)         CR_TAB
+                         AS2 (mov,r31,__tmp_reg__));
+               }
+             else if ((INTVAL (src) & 0xff00) == 0)
+               {
+                 *l = 5;
+                 return (AS2 (mov,__tmp_reg__,r31) CR_TAB
+                         AS2 (ldi,r31,lo8(%1))     CR_TAB
+                         AS2 (mov,%A0,r31)         CR_TAB
+                         AS1 (clr,%B0)             CR_TAB
+                         AS2 (mov,r31,__tmp_reg__));
+               }
            }
-         return "";
+         
+         /* Last resort, equal to loading from memory.  */
+         *l = 6;
+         return (AS2 (mov,__tmp_reg__,r31) CR_TAB
+                 AS2 (ldi,r31,lo8(%1))     CR_TAB
+                 AS2 (mov,%A0,r31)         CR_TAB
+                 AS2 (ldi,r31,hi8(%1))     CR_TAB
+                 AS2 (mov,%B0,r31)         CR_TAB
+                 AS2 (mov,r31,__tmp_reg__));
        }
-      
-      if (reg_base == reg_dest)        
-       return *l=3, (AS2 (ldd,__tmp_reg__,%A1)    CR_TAB
-                     AS2 (ldd,%B0,%B1)   CR_TAB
-                     AS2 (mov,%A0,__tmp_reg__));
-      else
-       return *l=2, (AS2 (ldd,%A0,%A1)    CR_TAB
-                     AS2 (ldd,%B0,%B1));
-    }
-  else if (GET_CODE (XEXP (op[1],0)) == PRE_DEC) /* (--R) */
-    {
-      if (reg_overlap_mentioned_p (op[0], XEXP (XEXP (op[1],0),0)))
-       fatal_insn ("Incorrect insn:", insn);
-      
-      return *l=2, (AS2 (ld,%B0,%1) CR_TAB
-                   AS2 (ld,%A0,%1));
+      else if (GET_CODE (src) == MEM)
+       return out_movhi_r_mr (insn, operands, real_l); /* mov r,m */
     }
-  else if (GET_CODE (XEXP (op[1],0)) == POST_INC) /* (R++) */
+  else if (GET_CODE (dest) == MEM)
     {
-      if (reg_overlap_mentioned_p (op[0], XEXP (XEXP (op[1],0),0)))
-       fatal_insn ("Incorrect insn:", insn);
-      
-      return *l=2, (AS2 (ld,%A0,%1)  CR_TAB
-                   AS2 (ld,%B0,%1));
+      const char *template;
+
+      if (src == const0_rtx)
+       operands[1] = zero_reg_rtx;
+
+      template = out_movhi_mr_r (insn, operands, real_l);
+
+      if (!real_l)
+       output_asm_insn (template, operands);
+
+      operands[1] = src;
+      return "";
     }
-  else if (CONSTANT_ADDRESS_P (XEXP (op[1],0)))
-        return *l=4, (AS2 (lds,%A0,%A1) CR_TAB
-                     AS2 (lds,%B0,%B1));
-  fatal_insn ("Unknown move insn:",insn);
+  fatal_insn ("Invalid insn:", insn);
   return "";
 }
 
-char *
-out_movsi_r_mr (insn,op,l)
+const char *
+out_movqi_r_mr (insn, op, l)
      rtx insn;
      rtx op[];
      int *l; /* instruction length */
 {
-  int reg_dest=true_regnum (op[0]);
-  int reg_base=true_regnum (XEXP (op[1],0));
-  int tmp;
+  rtx dest = op[0];
+  rtx src = op[1];
+  rtx x = XEXP (src, 0);
+  int dummy;
+  
   if (!l)
-    l=&tmp;
-  if (reg_base > 0)
+    l = &dummy;
+  
+  if (CONSTANT_ADDRESS_P (x))
     {
-      if (reg_base == REG_X)        /* (R26) */
+      if (io_address_p (x, 1))
+       {
+         *l = 1;
+         return AS2 (in,%0,%1-0x20);
+       }
+      *l = 2;
+      return AS2 (lds,%0,%1);
+    }
+  /* memory access by reg+disp */
+  else if (GET_CODE (x) == PLUS
+      && REG_P (XEXP (x,0))
+      && GET_CODE (XEXP (x,1)) == CONST_INT)
+    {
+      if ((INTVAL (XEXP (x,1)) - GET_MODE_SIZE (GET_MODE (src))) >= 63)
+       {
+         int disp = INTVAL (XEXP (x,1));
+         if (REGNO (XEXP (x,0)) != REG_Y)
+           fatal_insn ("Incorrect insn:",insn);
+
+         if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (src)))
+           return *l = 3, (AS2 (adiw,r28,%o1-63) CR_TAB
+                           AS2 (ldd,%0,Y+63)     CR_TAB
+                           AS2 (sbiw,r28,%o1-63));
+
+         return *l = 5, (AS2 (subi,r28,lo8(-%o1)) CR_TAB
+                         AS2 (sbci,r29,hi8(-%o1)) CR_TAB
+                         AS2 (ld,%0,Y)            CR_TAB
+                         AS2 (subi,r28,lo8(%o1))  CR_TAB
+                         AS2 (sbci,r29,hi8(%o1)));
+       }
+      else if (REGNO (XEXP (x,0)) == REG_X)
+       {
+         /* This is a paranoid case LEGITIMIZE_RELOAD_ADDRESS must exclude
+            it but I have this situation with extremal optimizing options.  */
+         if (reg_overlap_mentioned_p (dest, XEXP (x,0))
+             || reg_unused_after (insn, XEXP (x,0)))
+           return *l = 2, (AS2 (adiw,r26,%o1) CR_TAB
+                           AS2 (ld,%0,X));
+
+         return *l = 3, (AS2 (adiw,r26,%o1) CR_TAB
+                         AS2 (ld,%0,X)      CR_TAB
+                         AS2 (sbiw,r26,%o1));
+       }
+      *l = 1;
+      return AS2 (ldd,%0,%1);
+    }
+  *l = 1;
+  return AS2 (ld,%0,%1);
+}
+
+const char *
+out_movhi_r_mr (insn, op, l)
+     rtx insn;
+     rtx op[];
+     int *l; /* instruction length */
+{
+  rtx dest = op[0];
+  rtx src = op[1];
+  rtx base = XEXP (src, 0);
+  int reg_dest = true_regnum (dest);
+  int reg_base = true_regnum (base);
+  int tmp;
+
+  if (!l)
+    l = &tmp;
+
+  if (reg_base > 0)
+    {
+      if (reg_dest == reg_base)         /* R = (R) */
+       {
+         *l = 3;
+         return (AS2 (ld,__tmp_reg__,%1+) CR_TAB
+                 AS2 (ld,%B0,%1) CR_TAB
+                 AS2 (mov,%A0,__tmp_reg__));
+       }
+      else if (reg_base == REG_X)        /* (R26) */
+        {
+          if (reg_unused_after (insn, base))
+           {
+             *l = 2;
+             return (AS2 (ld,%A0,X+) CR_TAB
+                     AS2 (ld,%B0,X));
+           }
+         *l  = 3;
+         return (AS2 (ld,%A0,X+) CR_TAB
+                 AS2 (ld,%B0,X) CR_TAB
+                 AS2 (sbiw,r26,1));
+        }
+      else                      /* (R)  */
+       {
+         *l = 2;
+         return (AS2 (ld,%A0,%1)    CR_TAB
+                 AS2 (ldd,%B0,%1+1));
+       }
+    }
+  else if (GET_CODE (base) == PLUS) /* (R + i) */
+    {
+      int disp = INTVAL (XEXP (base, 1));
+      int reg_base = true_regnum (XEXP (base, 0));
+      
+      if (disp > MAX_LD_OFFSET (GET_MODE (src)))
+       {
+         if (REGNO (XEXP (base, 0)) != REG_Y)
+           fatal_insn ("Incorrect insn:",insn);
+         
+         if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (src)))
+           return *l = 4, (AS2 (adiw,r28,%o1-62) CR_TAB
+                           AS2 (ldd,%A0,Y+62)    CR_TAB
+                           AS2 (ldd,%B0,Y+63)    CR_TAB
+                           AS2 (sbiw,r28,%o1-62));
+
+         return *l = 6, (AS2 (subi,r28,lo8(-%o1)) CR_TAB
+                         AS2 (sbci,r29,hi8(-%o1)) CR_TAB
+                         AS2 (ld,%A0,Y)           CR_TAB
+                         AS2 (ldd,%B0,Y+1)        CR_TAB
+                         AS2 (subi,r28,lo8(%o1))  CR_TAB
+                         AS2 (sbci,r29,hi8(%o1)));
+       }
+      if (reg_base == REG_X)
+       {
+         /* This is a paranoid case. LEGITIMIZE_RELOAD_ADDRESS must exclude
+            it but I have this situation with extremal
+            optimization options.  */
+         
+         *l = 4;
+         if (reg_base == reg_dest)
+           return (AS2 (adiw,r26,%o1)      CR_TAB
+                   AS2 (ld,__tmp_reg__,X+) CR_TAB
+                   AS2 (ld,%B0,X)          CR_TAB
+                   AS2 (mov,%A0,__tmp_reg__));
+
+         return (AS2 (adiw,r26,%o1) CR_TAB
+                 AS2 (ld,%A0,X+)    CR_TAB
+                 AS2 (ld,%B0,X)     CR_TAB
+                 AS2 (sbiw,r26,%o1+1));
+       }
+
+      if (reg_base == reg_dest)
+       {
+         *l = 3;
+         return (AS2 (ldd,__tmp_reg__,%A1) CR_TAB
+                 AS2 (ldd,%B0,%B1)         CR_TAB
+                 AS2 (mov,%A0,__tmp_reg__));
+       }
+      
+      *l = 2;
+      return (AS2 (ldd,%A0,%A1) CR_TAB
+             AS2 (ldd,%B0,%B1));
+    }
+  else if (GET_CODE (base) == PRE_DEC) /* (--R) */
+    {
+      if (reg_overlap_mentioned_p (dest, XEXP (base, 0)))
+       fatal_insn ("Incorrect insn:", insn);
+
+      *l = 2;
+      return (AS2 (ld,%B0,%1) CR_TAB
+             AS2 (ld,%A0,%1));
+    }
+  else if (GET_CODE (base) == POST_INC) /* (R++) */
+    {
+      if (reg_overlap_mentioned_p (dest, XEXP (base, 0)))
+       fatal_insn ("Incorrect insn:", insn);
+
+      *l = 2;
+      return (AS2 (ld,%A0,%1)  CR_TAB
+             AS2 (ld,%B0,%1));
+    }
+  else if (CONSTANT_ADDRESS_P (base))
+    {
+      if (io_address_p (base, 2))
+       {
+         *l = 2;
+         return (AS2 (in,%A0,%A1-0x20) CR_TAB
+                 AS2 (in,%B0,%B1-0x20));
+       }
+      *l = 4;
+      return (AS2 (lds,%A0,%A1) CR_TAB
+             AS2 (lds,%B0,%B1));
+    }
+  
+  fatal_insn ("Unknown move insn:",insn);
+  return "";
+}
+
+const char *
+out_movsi_r_mr (insn, op, l)
+     rtx insn;
+     rtx op[];
+     int *l; /* instruction length */
+{
+  rtx dest = op[0];
+  rtx src = op[1];
+  rtx base = XEXP (src, 0);
+  int reg_dest = true_regnum (dest);
+  int reg_base = true_regnum (base);
+  int tmp;
+
+  if (!l)
+    l = &tmp;
+  
+  if (reg_base > 0)
+    {
+      if (reg_base == REG_X)        /* (R26) */
         {
           if (reg_dest == REG_X)
-            return *l=6, (AS2 (adiw,r26,3) CR_TAB
-                          AS2 (ld,%D0,X)  CR_TAB
-                          AS2 (ld,%C0,-X) CR_TAB
-                          AS2 (ld,__tmp_reg__,-X)  CR_TAB
-                          AS2 (ld,%A0,-X)  CR_TAB
-                          AS2 (mov,%B0,__tmp_reg__));
+           /* "ld r26,-X" is undefined */
+           return *l=7, (AS2 (adiw,r26,3)        CR_TAB
+                         AS2 (ld,r29,X)          CR_TAB
+                         AS2 (ld,r28,-X)         CR_TAB
+                         AS2 (ld,__tmp_reg__,-X) CR_TAB
+                         AS2 (sbiw,r26,1)        CR_TAB
+                         AS2 (ld,r26,X)          CR_TAB
+                         AS2 (mov,r27,__tmp_reg__));
           else if (reg_dest == REG_X - 2)
             return *l=5, (AS2 (ld,%A0,X+)  CR_TAB
                           AS2 (ld,%B0,X+) CR_TAB
                           AS2 (ld,__tmp_reg__,X+)  CR_TAB
                           AS2 (ld,%D0,X)  CR_TAB
                           AS2 (mov,%C0,__tmp_reg__));
-          else if (reg_unused_after (insn,XEXP (op[1],0)))
+          else if (reg_unused_after (insn, base))
             return  *l=4, (AS2 (ld,%A0,X+)  CR_TAB
                            AS2 (ld,%B0,X+) CR_TAB
                            AS2 (ld,%C0,X+) CR_TAB
@@ -1530,40 +2042,65 @@ out_movsi_r_mr (insn,op,l)
                           AS2 (ldd,%D0,%1+3));
         }
     }
-  else if (GET_CODE (XEXP (op[1],0)) == PLUS) /* (R + i) */
+  else if (GET_CODE (base) == PLUS) /* (R + i) */
     {
-      int disp = INTVAL(XEXP (XEXP (op[1],0), 1));
+      int disp = INTVAL (XEXP (base, 1));
       
-      if (disp > MAX_LD_OFFSET (GET_MODE (op[1])))
+      if (disp > MAX_LD_OFFSET (GET_MODE (src)))
        {
-         rtx x = XEXP (op[1],0);
-         if (REGNO (XEXP (x,0)) != REG_Y)
+         if (REGNO (XEXP (base, 0)) != REG_Y)
            fatal_insn ("Incorrect insn:",insn);
-         if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (op[1])))
-           {
-             op[4] = GEN_INT (disp - 60);
-             return *l=6,(AS2 (adiw, r28, %4) CR_TAB
-                          AS2 (ldd, %A0,Y+60)       CR_TAB
-                          AS2 (ldd, %B0,Y+61)     CR_TAB
-                          AS2 (ldd, %C0,Y+62)     CR_TAB
-                          AS2 (ldd, %D0,Y+63)     CR_TAB
-                          AS2 (sbiw, r28, %4));
-           }
-         else
+
+         if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (src)))
+           return *l = 6, (AS2 (adiw,r28,%o1-60) CR_TAB
+                           AS2 (ldd,%A0,Y+60)    CR_TAB
+                           AS2 (ldd,%B0,Y+61)    CR_TAB
+                           AS2 (ldd,%C0,Y+62)    CR_TAB
+                           AS2 (ldd,%D0,Y+63)    CR_TAB
+                           AS2 (sbiw,r28,%o1-60));
+
+         return *l = 8, (AS2 (subi,r28,lo8(-%o1)) CR_TAB
+                         AS2 (sbci,r29,hi8(-%o1)) CR_TAB
+                         AS2 (ld,%A0,Y)           CR_TAB
+                         AS2 (ldd,%B0,Y+1)        CR_TAB
+                         AS2 (ldd,%C0,Y+2)        CR_TAB
+                         AS2 (ldd,%D0,Y+3)        CR_TAB
+                         AS2 (subi,r28,lo8(%o1))  CR_TAB
+                         AS2 (sbci,r29,hi8(%o1)));
+       }
+
+      reg_base = true_regnum (XEXP (base, 0));
+      if (reg_base == REG_X)
+       {
+         /* R = (X + d) */
+         if (reg_dest == REG_X)
            {
-             op[4] = XEXP (x,1);
-             return *l=8,(AS2 (subi, r28, lo8(-%4))  CR_TAB
-                          AS2 (sbci, r29, hi8(-%4)) CR_TAB
-                          AS2 (ld, %A0,Y)             CR_TAB
-                          AS2 (ldd, %B0,Y+1)          CR_TAB
-                          AS2 (ldd, %C0,Y+2)          CR_TAB
-                          AS2 (ldd, %D0,Y+3)          CR_TAB
-                          AS2 (subi, r28, lo8(%4))   CR_TAB
-                          AS2 (sbci, r29, hi8(%4)));
+             *l = 7;
+             /* "ld r26,-X" is undefined */
+             return (AS2 (adiw,r26,%o1+3)    CR_TAB
+                     AS2 (ld,r29,X)          CR_TAB
+                     AS2 (ld,r28,-X)         CR_TAB
+                     AS2 (ld,__tmp_reg__,-X) CR_TAB
+                     AS2 (sbiw,r26,1)        CR_TAB
+                     AS2 (ld,r26,X)          CR_TAB
+                     AS2 (mov,r27,__tmp_reg__));
            }
+         *l = 6;
+         if (reg_dest == REG_X - 2)
+           return (AS2 (adiw,r26,%o1)      CR_TAB
+                   AS2 (ld,r24,X+)         CR_TAB
+                   AS2 (ld,r25,X+)         CR_TAB
+                   AS2 (ld,__tmp_reg__,X+) CR_TAB
+                   AS2 (ld,r27,X)          CR_TAB
+                   AS2 (mov,r26,__tmp_reg__));
+
+         return (AS2 (adiw,r26,%o1) CR_TAB
+                 AS2 (ld,%A0,X+)    CR_TAB
+                 AS2 (ld,%B0,X+)    CR_TAB
+                 AS2 (ld,%C0,X+)    CR_TAB
+                 AS2 (ld,%D0,X)     CR_TAB
+                 AS2 (sbiw,r26,%o1+3));
        }
-
-      reg_base = true_regnum (XEXP (XEXP (op[1],0), 0));
       if (reg_dest == reg_base)
         return *l=5, (AS2 (ldd,%D0,%D1) CR_TAB
                       AS2 (ldd,%C0,%C1) CR_TAB
@@ -1581,17 +2118,17 @@ out_movsi_r_mr (insn,op,l)
                     AS2 (ldd,%C0,%C1) CR_TAB
                     AS2 (ldd,%D0,%D1));
     }
-  else if (GET_CODE (XEXP (op[1],0)) == PRE_DEC) /* (--R) */
+  else if (GET_CODE (base) == PRE_DEC) /* (--R) */
     return *l=4, (AS2 (ld,%D0,%1) CR_TAB
                  AS2 (ld,%C0,%1) CR_TAB
                  AS2 (ld,%B0,%1) CR_TAB
                  AS2 (ld,%A0,%1));
-  else if (GET_CODE (XEXP (op[1],0)) == POST_INC) /* (R++) */
+  else if (GET_CODE (base) == POST_INC) /* (R++) */
     return *l=4, (AS2 (ld,%A0,%1) CR_TAB
                  AS2 (ld,%B0,%1) CR_TAB
                  AS2 (ld,%C0,%1) CR_TAB
                  AS2 (ld,%D0,%1));
-  else if (CONSTANT_ADDRESS_P (XEXP (op[1],0)))
+  else if (CONSTANT_ADDRESS_P (base))
       return *l=8, (AS2 (lds,%A0,%A1) CR_TAB
                    AS2 (lds,%B0,%B1) CR_TAB
                    AS2 (lds,%C0,%C1) CR_TAB
@@ -1601,18 +2138,23 @@ out_movsi_r_mr (insn,op,l)
   return "";
 }
 
-char *
-out_movsi_mr_r (insn,op,l)
+const char *
+out_movsi_mr_r (insn, op, l)
      rtx insn;
      rtx op[];
      int *l;
 {
-  int reg_base = true_regnum (XEXP (op[0],0));
-  int reg_dest = true_regnum (op[1]);
+  rtx dest = op[0];
+  rtx src = op[1];
+  rtx base = XEXP (dest, 0);
+  int reg_base = true_regnum (base);
+  int reg_src = true_regnum (src);
   int tmp;
+  
   if (!l)
     l = &tmp;
-  if (CONSTANT_ADDRESS_P (XEXP (op[0],0)))
+  
+  if (CONSTANT_ADDRESS_P (base))
     return *l=8,(AS2 (sts,%A0,%A1) CR_TAB
                 AS2 (sts,%B0,%B1) CR_TAB
                 AS2 (sts,%C0,%C1) CR_TAB
@@ -1621,25 +2163,28 @@ out_movsi_mr_r (insn,op,l)
     {
       if (reg_base == REG_X)                /* (R26) */
         {
-          if (reg_dest == REG_X)
+          if (reg_src == REG_X)
             {
-              if (reg_unused_after (insn,XEXP (op[0],0)))
-                return *l=5, (AS2 (mov,__tmp_reg__,%B1) CR_TAB
-                              AS2 (st,%0+,%A1) CR_TAB
-                              AS2 (st,%0+,__tmp_reg__)  CR_TAB
-                              AS2 (st,%0+,%C1) CR_TAB
-                              AS2 (st,%0,%D1));
+             /* "st X+,r26" is undefined */
+              if (reg_unused_after (insn, base))
+               return *l=6, (AS2 (mov,__tmp_reg__,r27) CR_TAB
+                             AS2 (st,X,r26)            CR_TAB
+                             AS2 (adiw,r26,1)          CR_TAB
+                             AS2 (st,X+,__tmp_reg__)   CR_TAB
+                             AS2 (st,X+,r28)           CR_TAB
+                             AS2 (st,X,r29));
               else
-                return *l=6, (AS2 (mov,__tmp_reg__,%B1) CR_TAB
-                              AS2 (st,%0+,%A1) CR_TAB
-                              AS2 (st,%0+,__tmp_reg__)  CR_TAB
-                              AS2 (st,%0+,%C1) CR_TAB
-                              AS2 (st,%0,%D1)  CR_TAB
-                              AS2 (sbiw,r26,3));
+                return *l=7, (AS2 (mov,__tmp_reg__,r27) CR_TAB
+                             AS2 (st,X,r26)            CR_TAB
+                             AS2 (adiw,r26,1)          CR_TAB
+                             AS2 (st,X+,__tmp_reg__)   CR_TAB
+                             AS2 (st,X+,r28)           CR_TAB
+                             AS2 (st,X,r29)            CR_TAB
+                             AS2 (sbiw,r26,3));
             }
-          else if (reg_base == reg_dest+2)
+          else if (reg_base == reg_src + 2)
             {
-              if (reg_unused_after (insn,XEXP (op[0],0)))
+              if (reg_unused_after (insn, base))
                 return *l=7, (AS2 (mov,__zero_reg__,%C1) CR_TAB
                               AS2 (mov,__tmp_reg__,%D1) CR_TAB
                               AS2 (st,%0+,%A1) CR_TAB
@@ -1669,48 +2214,80 @@ out_movsi_mr_r (insn,op,l)
                      AS2 (std,%0+2,%C1) CR_TAB
                      AS2 (std,%0+3,%D1));
     }
-  else if (GET_CODE (XEXP (op[0],0)) == PLUS) /* (R + i) */
+  else if (GET_CODE (base) == PLUS) /* (R + i) */
     {
-      int disp = INTVAL(XEXP (XEXP (op[0],0), 1));
-      if (disp > MAX_LD_OFFSET (GET_MODE (op[0])))
+      int disp = INTVAL (XEXP (base, 1));
+      reg_base = REGNO (XEXP (base, 0));
+      if (disp > MAX_LD_OFFSET (GET_MODE (dest)))
        {
-         rtx x = XEXP (op[0],0);
-         if (REGNO (XEXP (x,0)) != REG_Y)
+         if (reg_base != REG_Y)
            fatal_insn ("Incorrect insn:",insn);
-         if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (op[0])))
+
+         if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest)))
+           return *l = 6, (AS2 (adiw,r28,%o0-60) CR_TAB
+                           AS2 (std,Y+60,%A1)    CR_TAB
+                           AS2 (std,Y+61,%B1)    CR_TAB
+                           AS2 (std,Y+62,%C1)    CR_TAB
+                           AS2 (std,Y+63,%D1)    CR_TAB
+                           AS2 (sbiw,r28,%o0-60));
+
+         return *l = 8, (AS2 (subi,r28,lo8(-%o0)) CR_TAB
+                         AS2 (sbci,r29,hi8(-%o0)) CR_TAB
+                         AS2 (st,Y,%A1)           CR_TAB
+                         AS2 (std,Y+1,%B1)        CR_TAB
+                         AS2 (std,Y+2,%C1)        CR_TAB
+                         AS2 (std,Y+3,%D1)        CR_TAB
+                         AS2 (subi,r28,lo8(%o0))  CR_TAB
+                         AS2 (sbci,r29,hi8(%o0)));
+       }
+      if (reg_base == REG_X)
+       {
+         /* (X + d) = R */
+         if (reg_src == REG_X)
            {
-             op[4] = GEN_INT (disp - 60);
-             return *l=6,(AS2 (adiw, r28, %4) CR_TAB
-                          AS2 (std, Y+60,%A1)       CR_TAB
-                          AS2 (std, Y+61,%B1)     CR_TAB
-                          AS2 (std, Y+62,%C1)     CR_TAB
-                          AS2 (std, Y+63,%D1)     CR_TAB
-                          AS2 (sbiw, r28, %4));
+             *l = 9;
+             return (AS2 (mov,__tmp_reg__,r26)  CR_TAB
+                     AS2 (mov,__zero_reg__,r27) CR_TAB
+                     AS2 (adiw,r26,%o0)         CR_TAB
+                     AS2 (st,X+,__tmp_reg__)    CR_TAB
+                     AS2 (st,X+,__zero_reg__)   CR_TAB
+                     AS2 (st,X+,r28)            CR_TAB
+                     AS2 (st,X,r29)             CR_TAB
+                     AS1 (clr,__zero_reg__)     CR_TAB
+                     AS2 (sbiw,r26,%o0+3));
            }
-         else
+         else if (reg_src == REG_X - 2)
            {
-             op[4] = XEXP (x,1);
-             return *l=8,(AS2 (subi, r28, lo8(-%4))  CR_TAB
-                          AS2 (sbci, r29, hi8(-%4)) CR_TAB
-                          AS2 (st, Y,%A1)             CR_TAB
-                          AS2 (std, Y+1,%B1)          CR_TAB
-                          AS2 (std, Y+2,%C1)          CR_TAB
-                          AS2 (std, Y+3,%D1)          CR_TAB
-                          AS2 (subi, r28, lo8(%4))   CR_TAB
-                          AS2 (sbci, r29, hi8(%4)));
+             *l = 9;
+             return (AS2 (mov,__tmp_reg__,r26)  CR_TAB
+                     AS2 (mov,__zero_reg__,r27) CR_TAB
+                     AS2 (adiw,r26,%o0)         CR_TAB
+                     AS2 (st,X+,r24)            CR_TAB
+                     AS2 (st,X+,r25)            CR_TAB
+                     AS2 (st,X+,__tmp_reg__)    CR_TAB
+                     AS2 (st,X,__zero_reg__)    CR_TAB
+                     AS1 (clr,__zero_reg__)     CR_TAB
+                     AS2 (sbiw,r26,%o0+3));
            }
+         *l = 6;
+         return (AS2 (adiw,r26,%o0) CR_TAB
+                 AS2 (st,X+,%A1)    CR_TAB
+                 AS2 (st,X+,%B1)    CR_TAB
+                 AS2 (st,X+,%C1)    CR_TAB
+                 AS2 (st,X,%D1)     CR_TAB
+                 AS2 (sbiw,r26,%o0+3));
        }
       return *l=4, (AS2 (std,%A0,%A1)    CR_TAB
                    AS2 (std,%B0,%B1) CR_TAB
                    AS2 (std,%C0,%C1) CR_TAB
                    AS2 (std,%D0,%D1));
     }
-  else if (GET_CODE (XEXP (op[0],0)) == PRE_DEC) /* (--R) */
+  else if (GET_CODE (base) == PRE_DEC) /* (--R) */
     return *l=4, (AS2 (st,%0,%D1) CR_TAB
                  AS2 (st,%0,%C1) CR_TAB
                  AS2 (st,%0,%B1) CR_TAB
                  AS2 (st,%0,%A1));
-  else if (GET_CODE (XEXP (op[0],0)) == POST_INC) /* (R++) */
+  else if (GET_CODE (base) == POST_INC) /* (R++) */
     return *l=4, (AS2 (st,%0,%A1)  CR_TAB
                  AS2 (st,%0,%B1) CR_TAB
                  AS2 (st,%0,%C1) CR_TAB
@@ -1719,169 +2296,321 @@ out_movsi_mr_r (insn,op,l)
   return "";
 }
 
-char *
-output_movsisf(insn, operands, which_alternative)
+const char *
+output_movsisf(insn, operands, l)
      rtx insn;
      rtx operands[];
-     int which_alternative;
+     int *l;
 {
-  rtx link;
-  switch (which_alternative)
-    {
-    case 0: /* mov r,r */
-      if (true_regnum (operands[0]) > true_regnum (operands[1]))
-        return (AS2 (mov,%D0,%D1) CR_TAB
-               AS2 (mov,%C0,%C1) CR_TAB
-               AS2 (mov,%B0,%B1) CR_TAB
-               AS2 (mov,%A0,%A1));
-      else
-        return (AS2 (mov,%A0,%A1) CR_TAB
-               AS2 (mov,%B0,%B1) CR_TAB
-               AS2 (mov,%C0,%C1) CR_TAB
-               AS2 (mov,%D0,%D1));
-    case 1:  /* mov r,L */
-      return (AS1 (clr,%A0) CR_TAB
-             AS1 (clr,%B0) CR_TAB
-             AS1 (clr,%C0) CR_TAB
-             AS1 (clr,%D0));
-    case 2: /* mov r,d */
-      if (GET_MODE (operands[0]) == SImode
-         && operands[1] == const1_rtx
-         && (link = find_reg_note (insn, REG_WAS_0, 0))
-         /* Make sure the insn that stored the 0 is still present.  */
-         && ! INSN_DELETED_P (XEXP (link, 0))
-         && GET_CODE (XEXP (link, 0)) != NOTE
-         /* Make sure cross jumping didn't happen here.  */
-         && no_labels_between_p (XEXP (link, 0), insn)
-         /* Make sure the reg hasn't been clobbered.  */
-         && ! reg_set_between_p (operands[0], XEXP (link, 0), insn))
-      /* Fastest way to change a 0 to a 1.  */
-        return AS1 (inc,%A0 ; reg_was_0);
-      return (AS2 (ldi,%A0,lo8(%1))  CR_TAB
-             AS2 (ldi,%B0,hi8(%1)) CR_TAB
-             AS2 (ldi,%C0,hlo8(%1)) CR_TAB
-             AS2 (ldi,%D0,hhi8(%1)));
-    case 3: /* mov r,m*/
-    case 5:
-      return out_movsi_r_mr (insn, operands, NULL);
-    case 4: /* mov m,r*/
-    case 6:
-      {
-       rtx save1=NULL;
-       if (operands[1] == const0_rtx)
-         {
-           save1 = operands[1];
-           operands[1] = zero_reg_rtx;
-         }
-       output_asm_insn (out_movsi_mr_r (insn,operands,NULL), operands);
-       if (save1)
-         operands[1] = save1;
-      }
+  int dummy;
+  rtx dest = operands[0];
+  rtx src = operands[1];
+  int *real_l = l;
+  
+  if (!l)
+    l = &dummy;
+  
+  if (register_operand (dest, VOIDmode))
+    {
+      if (register_operand (src, VOIDmode)) /* mov r,r */
+       {
+         if (true_regnum (dest) > true_regnum (src))
+           {
+             if (AVR_ENHANCED)
+               {
+                 *l = 2;
+                 return (AS2 (movw,%C0,%C1) CR_TAB
+                         AS2 (movw,%A0,%A1));
+               }
+             *l = 4;
+             return (AS2 (mov,%D0,%D1) CR_TAB
+                     AS2 (mov,%C0,%C1) CR_TAB
+                     AS2 (mov,%B0,%B1) CR_TAB
+                     AS2 (mov,%A0,%A1));
+           }
+         else
+           {
+             if (AVR_ENHANCED)
+               {
+                 *l = 2;
+                 return (AS2 (movw,%A0,%A1) CR_TAB
+                         AS2 (movw,%C0,%C1));
+               }
+             *l = 4;
+             return (AS2 (mov,%A0,%A1) CR_TAB
+                     AS2 (mov,%B0,%B1) CR_TAB
+                     AS2 (mov,%C0,%C1) CR_TAB
+                     AS2 (mov,%D0,%D1));
+           }
+       }
+      else if (CONSTANT_P (src))
+       {
+         if (test_hard_reg_class (LD_REGS, dest)) /* ldi d,i */
+           {
+             if (byte_immediate_operand (src, SImode)
+                 && reg_was_0 (insn, dest))
+               {
+                 *l = 1;
+                 return (AS2 (ldi,%A0,lo8(%1) ; reg_was_0));
+               }
+
+             *l = 4;
+             return (AS2 (ldi,%A0,lo8(%1))  CR_TAB
+                     AS2 (ldi,%B0,hi8(%1))  CR_TAB
+                     AS2 (ldi,%C0,hlo8(%1)) CR_TAB
+                     AS2 (ldi,%D0,hhi8(%1)));
+           }
+         
+         if (GET_CODE (src) == CONST_INT)
+           {
+             const char *clr_op0 =
+               AVR_ENHANCED ? (AS1 (clr,%A0) CR_TAB
+                               AS1 (clr,%B0) CR_TAB
+                               AS2 (movw,%C0,%A0))
+                            : (AS1 (clr,%A0) CR_TAB
+                               AS1 (clr,%B0) CR_TAB
+                               AS1 (clr,%C0) CR_TAB
+                               AS1 (clr,%D0));
+
+             if (src == const0_rtx) /* mov r,L */
+               {
+                 *l = AVR_ENHANCED ? 3 : 4;
+                 return clr_op0;
+               }
+             else if (src == const1_rtx)
+               {
+                 if (reg_was_0 (insn, dest))
+                   {
+                     *l = 1;
+                     return AS1 (inc,%A0 ; reg_was_0);
+                   }
+                 if (!real_l)
+                   output_asm_insn (clr_op0, operands);
+                 *l = AVR_ENHANCED ? 4 : 5;
+                 return AS1 (inc,%A0);
+               }
+             else if (src == constm1_rtx)
+               {
+                 /* Immediate constants -1 to any register */
+                 if (reg_was_0 (insn, dest))
+                   {
+                     if (AVR_ENHANCED)
+                       {
+                         *l = 3;
+                         return (AS1 (dec,%A0) CR_TAB
+                                 AS1 (dec,%B0) CR_TAB
+                                 AS2 (movw,%C0,%A0));
+                       }
+                     *l = 4;
+                     return (AS1 (dec,%D0 ; reg_was_0) CR_TAB
+                             AS1 (dec,%C0)             CR_TAB
+                             AS1 (dec,%B0)             CR_TAB
+                             AS1 (dec,%A0));
+                   }
+                 if (AVR_ENHANCED)
+                   {
+                     *l = 4;
+                     return (AS1 (clr,%A0)     CR_TAB
+                             AS1 (dec,%A0)     CR_TAB
+                             AS2 (mov,%B0,%A0) CR_TAB
+                             AS2 (movw,%C0,%A0));
+                   }
+                 *l = 5;
+                 return (AS1 (clr,%A0)     CR_TAB
+                         AS1 (dec,%A0)     CR_TAB
+                         AS2 (mov,%B0,%A0) CR_TAB
+                         AS2 (mov,%C0,%A0) CR_TAB
+                         AS2 (mov,%D0,%A0));
+               }
+             else
+               {
+                 int bit_nr = exact_log2 (INTVAL (src));
+
+                 if (bit_nr >= 0)
+                   {
+                     if (reg_was_0 (insn, dest))
+                       {
+                         *l = 2;
+                         if (!real_l)
+                           output_asm_insn ("set ; reg_was_0", operands);
+                       }
+                     else
+                       {
+                         *l = AVR_ENHANCED ? 5 : 6;
+                         if (!real_l)
+                           {
+                             output_asm_insn (clr_op0, operands);
+                             output_asm_insn ("set", operands);
+                           }
+                       }
+                     if (!real_l)
+                       avr_output_bld (operands, bit_nr);
+
+                     return "";
+                   }
+               }
+           }
+         
+         /* Last resort, better than loading from memory.  */
+         *l = 10;
+         return (AS2 (mov,__tmp_reg__,r31) CR_TAB
+                 AS2 (ldi,r31,lo8(%1))     CR_TAB
+                 AS2 (mov,%A0,r31)         CR_TAB
+                 AS2 (ldi,r31,hi8(%1))     CR_TAB
+                 AS2 (mov,%B0,r31)         CR_TAB
+                 AS2 (ldi,r31,hlo8(%1))    CR_TAB
+                 AS2 (mov,%C0,r31)         CR_TAB
+                 AS2 (ldi,r31,hhi8(%1))    CR_TAB
+                 AS2 (mov,%D0,r31)         CR_TAB
+                 AS2 (mov,r31,__tmp_reg__));
+       }
+      else if (GET_CODE (src) == MEM)
+       return out_movsi_r_mr (insn, operands, real_l); /* mov r,m */
+    }
+  else if (GET_CODE (dest) == MEM)
+    {
+      const char *template;
+
+      if (src == const0_rtx)
+         operands[1] = zero_reg_rtx;
+
+      template = out_movsi_mr_r (insn, operands, real_l);
+
+      if (!real_l)
+       output_asm_insn (template, operands);
+
+      operands[1] = src;
+      return "";
     }
+  fatal_insn ("Invalid insn:", insn);
   return "";
 }
 
-char *
+const char *
 out_movqi_mr_r (insn, op, l)
      rtx insn;
      rtx op[];
      int *l; /* instruction length */
 {
-  if (l) *l=1;
+  rtx dest = op[0];
+  rtx src = op[1];
+  rtx x = XEXP (dest, 0);
+  int dummy;
 
-  if (GET_CODE (op[0]) == MEM)
+  if (!l)
+    l = &dummy;
+  
+  if (CONSTANT_ADDRESS_P (x))
     {
-      rtx x = XEXP (op[0],0);
-      if (GET_CODE (x) == PLUS
-         && REG_P (XEXP (x,0))
-         && GET_CODE (XEXP (x,1)) == CONST_INT)
+      if (io_address_p (x, 1))
+       {
+         *l = 1;
+         return AS2 (out,%0-0x20,%1);
+       }
+      *l = 2;
+      return AS2 (sts,%0,%1);
+    }
+  /* memory access by reg+disp */
+  else if (GET_CODE (x) == PLUS        
+      && REG_P (XEXP (x,0))
+      && GET_CODE (XEXP (x,1)) == CONST_INT)
+    {
+      if ((INTVAL (XEXP (x,1)) - GET_MODE_SIZE (GET_MODE (dest))) >= 63)
        {
-         if ((INTVAL (XEXP (x,1)) - GET_MODE_SIZE (GET_MODE (op[0]))) >= 63)
+         int disp = INTVAL (XEXP (x,1));
+         if (REGNO (XEXP (x,0)) != REG_Y)
+           fatal_insn ("Incorrect insn:",insn);
+
+         if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest)))
+           return *l = 3, (AS2 (adiw,r28,%o0-63) CR_TAB
+                           AS2 (std,Y+63,%1)     CR_TAB
+                           AS2 (sbiw,r28,%o0-63));
+
+         return *l = 5, (AS2 (subi,r28,lo8(-%o0)) CR_TAB
+                         AS2 (sbci,r29,hi8(-%o0)) CR_TAB
+                         AS2 (st,Y,%1)            CR_TAB
+                         AS2 (subi,r28,lo8(%o0))  CR_TAB
+                         AS2 (sbci,r29,hi8(%o0)));
+       }
+      else if (REGNO (XEXP (x,0)) == REG_X)
+       {
+         if (reg_overlap_mentioned_p (src, XEXP (x, 0)))
            {
-             int disp = INTVAL (XEXP (x,1));
-             if (REGNO (XEXP (x,0)) != REG_Y)
-               fatal_insn ("Incorrect insn:",insn);
-             if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (op[0])))
-               {
-                 if (l)
-                   *l = 3;
-                 else
-                   {
-                     op[4] = GEN_INT (disp - 63);
-                     return (AS2 (adiw, r28, %4) CR_TAB
-                             AS2 (std, Y+63,%1)        CR_TAB
-                             AS2 (sbiw, r28, %4));
-                   }
-               }
-             else
-               {
-                 op[4] = XEXP (x,1);
-                 if (l)
-                   *l = 5;
-                 else
-                   return (AS2 (subi, r28, lo8(-%4))  CR_TAB
-                           AS2 (sbci, r29, hi8(-%4)) CR_TAB
-                           AS2 (st, Y,%1)              CR_TAB
-                           AS2 (subi, r28, lo8(%4))   CR_TAB
-                           AS2 (sbci, r29, hi8(%4)));
-               }
+             if (reg_unused_after (insn, XEXP (x,0)))
+               return *l = 3, (AS2 (mov,__tmp_reg__,%1) CR_TAB
+                               AS2 (adiw,r26,%o0)       CR_TAB
+                               AS2 (st,X,__tmp_reg__));
+
+             return *l = 4, (AS2 (mov,__tmp_reg__,%1) CR_TAB
+                             AS2 (adiw,r26,%o0)       CR_TAB
+                             AS2 (st,X,__tmp_reg__)   CR_TAB
+                             AS2 (sbiw,r26,%o0));
            }
-         else if (REGNO (XEXP (x,0)) == REG_X)
+         else
            {
-             if (l)
-               *l=4;
-             else
-               {
-                 int overlap_p = reg_overlap_mentioned_p (op[1],XEXP (x,0));
-                 if (!overlap_p)
-                   output_asm_insn (AS2 (mov, __tmp_reg__, %1),op);
-                 output_asm_insn (AS2 (adiw, r26,%0),&XEXP (x,1));
-                 if (overlap_p)
-                   output_asm_insn (AS2 (st ,X,__tmp_reg__),op);
-                 else
-                   output_asm_insn (AS2 (st ,X,%1),op);
-                 output_asm_insn (AS2 (sbiw ,r26,%0),&XEXP (x,1));
-               }
-             return "";
+             if (reg_unused_after (insn, XEXP (x,0)))
+               return *l = 2, (AS2 (adiw,r26,%o0) CR_TAB
+                               AS2 (st,X,%1));
+
+             return *l = 3, (AS2 (adiw,r26,%o0) CR_TAB
+                             AS2 (st,X,%1)      CR_TAB
+                             AS2 (sbiw,r26,%o0));
            }
        }
+      *l = 1;
+      return AS2 (std,%0,%1);
     }
-  return AS2 (st%K0, %0,%1);
+  *l = 1;
+  return AS2 (st,%0,%1);
 }
 
-char *
-out_movhi_mr_r (insn,op,l)
+const char *
+out_movhi_mr_r (insn, op, l)
      rtx insn;
      rtx op[];
      int *l;
 {
-  int reg_base = true_regnum (XEXP (op[0],0));
-  int reg_dest = true_regnum (op[1]);
+  rtx dest = op[0];
+  rtx src = op[1];
+  rtx base = XEXP (dest, 0);
+  int reg_base = true_regnum (base);
+  int reg_src = true_regnum (src);
   int tmp;
   if (!l)
     l = &tmp;
-  if (CONSTANT_ADDRESS_P (XEXP (op[0],0)))
-    return *l=4,(AS2 (sts,%A0,%A1) CR_TAB
-                AS2 (sts,%B0,%B1));
+  if (CONSTANT_ADDRESS_P (base))
+    {
+      if (io_address_p (base, 2))
+       {
+         *l = 2;
+         return (AS2 (out,%B0-0x20,%B1) CR_TAB
+                 AS2 (out,%A0-0x20,%A1));
+       }
+      return *l = 4, (AS2 (sts,%B0,%B1) CR_TAB
+                     AS2 (sts,%A0,%A1));
+    }
   if (reg_base > 0)
     {
       if (reg_base == REG_X)
         {
-          if (reg_dest == REG_X)
+          if (reg_src == REG_X)
             {
-              if (reg_unused_after (insn, op[1]))
-                return *l=3, (AS2 (mov,__tmp_reg__,r27) CR_TAB
-                              AS2 (st ,X+,r26) CR_TAB
-                              AS2 (st ,X,__tmp_reg__));
+             /* "st X+,r26" is undefined */
+              if (reg_unused_after (insn, src))
+               return *l=4, (AS2 (mov,__tmp_reg__,r27) CR_TAB
+                             AS2 (st,X,r26)            CR_TAB
+                             AS2 (adiw,r26,1)          CR_TAB
+                             AS2 (st,X,__tmp_reg__));
               else
-                return *l=4, (AS2 (mov,__tmp_reg__,r27) CR_TAB
-                              AS2 (st ,X+,r26) CR_TAB
-                              AS2 (st ,X,__tmp_reg__)   CR_TAB
-                              AS2 (sbiw,r26,1));
+               return *l=5, (AS2 (mov,__tmp_reg__,r27) CR_TAB
+                             AS2 (st,X,r26)            CR_TAB
+                             AS2 (adiw,r26,1)          CR_TAB
+                             AS2 (st,X,__tmp_reg__)    CR_TAB
+                             AS2 (sbiw,r26,1));
             }
           else
             {
-              if (reg_unused_after (insn, XEXP (op[0],0)))
+              if (reg_unused_after (insn, base))
                 return *l=2, (AS2 (st,X+,%A1) CR_TAB
                               AS2 (st,X,%B1));
               else
@@ -1894,40 +2623,55 @@ out_movhi_mr_r (insn,op,l)
         return  *l=2, (AS2 (st ,%0,%A1)    CR_TAB
                        AS2 (std,%0+1,%B1));
     }
-  else if (GET_CODE (XEXP (op[0],0)) == PLUS)
+  else if (GET_CODE (base) == PLUS)
     {
-      int disp = INTVAL(XEXP (XEXP (op[0],0), 1));
-      if (disp > MAX_LD_OFFSET (GET_MODE (op[0])))
+      int disp = INTVAL (XEXP (base, 1));
+      reg_base = REGNO (XEXP (base, 0));
+      if (disp > MAX_LD_OFFSET (GET_MODE (dest)))
        {
-         rtx x = XEXP (op[0],0);
-         if (REGNO (XEXP (x,0)) != REG_Y)
+         if (reg_base != REG_Y)
            fatal_insn ("Incorrect insn:",insn);
-         if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (op[0])))
-           {
-             op[4] = GEN_INT (disp - 62);
-             return *l=4,(AS2 (adiw, r28, %4) CR_TAB
-                          AS2 (std, Y+62,%A1) CR_TAB
-                          AS2 (std, Y+63,%B1) CR_TAB
-                          AS2 (sbiw, r28, %4));
-           }
-         else
+
+         if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest)))
+           return *l = 4, (AS2 (adiw,r28,%o0-62) CR_TAB
+                           AS2 (std,Y+62,%A1)    CR_TAB
+                           AS2 (std,Y+63,%B1)    CR_TAB
+                           AS2 (sbiw,r28,%o0-62));
+
+         return *l = 6, (AS2 (subi,r28,lo8(-%o0)) CR_TAB
+                         AS2 (sbci,r29,hi8(-%o0)) CR_TAB
+                         AS2 (st,Y,%A1)           CR_TAB
+                         AS2 (std,Y+1,%B1)        CR_TAB
+                         AS2 (subi,r28,lo8(%o0))  CR_TAB
+                         AS2 (sbci,r29,hi8(%o0)));
+       }
+      if (reg_base == REG_X)
+       {
+         /* (X + d) = R */
+         if (reg_src == REG_X)
            {
-             op[4] = XEXP (x,1);
-             return *l=6,(AS2 (subi, r28, lo8(-%4))  CR_TAB
-                          AS2 (sbci, r29, hi8(-%4)) CR_TAB
-                          AS2 (st, Y,%A1)           CR_TAB
-                          AS2 (std, Y+1,%B1)        CR_TAB
-                          AS2 (subi, r28, lo8(%4))  CR_TAB
-                          AS2 (sbci, r29, hi8(%4)));
+             *l = 7;
+             return (AS2 (mov,__tmp_reg__,r26)  CR_TAB
+                     AS2 (mov,__zero_reg__,r27) CR_TAB
+                     AS2 (adiw,r26,%o0)         CR_TAB
+                     AS2 (st,X+,__tmp_reg__)    CR_TAB
+                     AS2 (st,X,__zero_reg__)    CR_TAB
+                     AS1 (clr,__zero_reg__)     CR_TAB
+                     AS2 (sbiw,r26,%o0+1));
            }
+         *l = 4;
+         return (AS2 (adiw,r26,%o0) CR_TAB
+                 AS2 (st,X+,%A1)    CR_TAB
+                 AS2 (st,X,%B1)     CR_TAB
+                 AS2 (sbiw,r26,%o0+1));
        }
       return *l=2, (AS2 (std,%A0,%A1)    CR_TAB
                    AS2 (std,%B0,%B1));
-    }  
-  else if (GET_CODE (XEXP (op[0],0)) == PRE_DEC) /* (--R) */
+    }
+  else if (GET_CODE (base) == PRE_DEC) /* (--R) */
     return *l=2, (AS2 (st,%0,%B1) CR_TAB
                  AS2 (st,%0,%A1));
-  else if (GET_CODE (XEXP (op[0],0)) == POST_INC) /* (R++) */
+  else if (GET_CODE (base) == POST_INC) /* (R++) */
     return *l=2, (AS2 (st,%0,%A1)  CR_TAB
                  AS2 (st,%0,%B1));
   fatal_insn ("Unknown move insn:",insn);
@@ -1937,7 +2681,7 @@ out_movhi_mr_r (insn,op,l)
 /* Return 1 if frame pointer for current function required */
 
 int
-frame_pointer_required_p(void)
+frame_pointer_required_p ()
 {
   return (current_function_calls_alloca
          || current_function_args_info.nregs == 0
@@ -1945,64 +2689,79 @@ frame_pointer_required_p(void)
          || get_frame_size () > 0);
 }
 
-/* Return 1 if the next insn is a JUMP_INSN with condition (GT,LE,GTU,LTU)  */
+/* Returns the condition of compare insn INSN, or UNKNOWN.  */
 
-int
-compare_diff_p (insn)
+static RTX_CODE
+compare_condition (insn)
      rtx insn;
 {
   rtx next = next_real_insn (insn);
   RTX_CODE cond = UNKNOWN;
-  if (GET_CODE (next) == JUMP_INSN)
+  if (next && GET_CODE (next) == JUMP_INSN)
     {
       rtx pat = PATTERN (next);
       rtx src = SET_SRC (pat);
-      rtx t = XEXP (src,0);
+      rtx t = XEXP (src, 0);
       cond = GET_CODE (t);
     }
+  return cond;
+}
+
+/* Returns nonzero if INSN is a tst insn that only tests the sign.  */
+
+static int
+compare_sign_p (insn)
+     rtx insn;
+{
+  RTX_CODE cond = compare_condition (insn);
+  return (cond == GE || cond == LT);
+}
+
+/* Returns nonzero if the next insn is a JUMP_INSN with a condition
+   that needs to be swapped (GT, GTU, LE, LEU).  */
+
+int
+compare_diff_p (insn)
+     rtx insn;
+{
+  RTX_CODE cond = compare_condition (insn);
   return (cond == GT || cond == GTU || cond == LE || cond == LEU) ? cond : 0;
 }
 
-/* Returns nonzero if INSN is a compare insn with the EQ or NE condition */
+/* Returns nonzero if INSN is a compare insn with the EQ or NE condition */
 
 int
 compare_eq_p (insn)
      rtx insn;
 {
-  rtx next = next_real_insn (insn);
-  RTX_CODE cond = UNKNOWN;
-  if (GET_CODE (next) == JUMP_INSN)
-    {
-      rtx pat = PATTERN (next);
-      rtx src = SET_SRC (pat);
-      rtx t = XEXP (src,0);
-      cond = GET_CODE (t);
-    }
+  RTX_CODE cond = compare_condition (insn);
   return (cond == EQ || cond == NE);
 }
 
 
 /* Output test instruction for HImode */
 
-char *
-out_tsthi (insn,l)
+const char *
+out_tsthi (insn, l)
      rtx insn;
      int *l;
 {
-  if (!compare_eq_p (insn))
+  if (compare_sign_p (insn))
     {
       if (l) *l = 1;
       return AS1 (tst,%B0);
     }
-  if (TEST_HARD_REG_CLASS (ADDW_REGS, true_regnum (SET_SRC (PATTERN (insn)))))
+  if (reg_unused_after (insn, SET_SRC (PATTERN (insn)))
+      && compare_eq_p (insn))
     {
+      /* faster than sbiw if we can clobber the operand */
       if (l) *l = 1;
-      return AS2 (sbiw,%0,0);
+      return AS2 (or,%A0,%B0);
     }
-  if (compare_eq_p (insn) && reg_unused_after (insn, SET_SRC (PATTERN (insn))))
+  if (test_hard_reg_class (ADDW_REGS, SET_SRC (PATTERN (insn))))
     {
       if (l) *l = 1;
-      return AS2 (or,%A0,%B0);
+      return AS2 (sbiw,%0,0);
     }
   if (l) *l = 2;
   return (AS2 (cp,%A0,__zero_reg__) CR_TAB
@@ -2012,17 +2771,17 @@ out_tsthi (insn,l)
 
 /* Output test instruction for SImode */
 
-char *
-out_tstsi (insn,l)
+const char *
+out_tstsi (insn, l)
      rtx insn;
      int *l;
 {
-  if (!compare_eq_p (insn))
+  if (compare_sign_p (insn))
     {
       if (l) *l = 1;
       return AS1 (tst,%D0);
     }
-  if (TEST_HARD_REG_CLASS (ADDW_REGS, true_regnum (SET_SRC (PATTERN (insn)))))
+  if (test_hard_reg_class (ADDW_REGS, SET_SRC (PATTERN (insn))))
     {
       if (l) *l = 3;
       return (AS2 (sbiw,%A0,0) CR_TAB
@@ -2037,80 +2796,142 @@ out_tstsi (insn,l)
 }
 
 
-/* Generate asm equivalent for various shift's.
-   Shift count are CONST_INT or REG.  */
+/* Generate asm equivalent for various shifts.
+   Shift count is a CONST_INT, MEM or REG.
+   This only handles cases that are not already
+   carefully hand-optimized in ?sh??i3_out.  */
 
 void
-out_shift_with_cnt (template,insn,operands,len)
-     char * template;
+out_shift_with_cnt (template, insn, operands, len, t_len)
+     const char *template;
      rtx insn;
      rtx operands[];
      int *len;
+     int t_len;  /* Length of template.  */
 {
   rtx op[10];
-  char str[300];
+  char str[500];
   int second_label = 1;
-  
+  int saved_in_tmp = 0;
+  int use_zero_reg = 0;
+
   op[0] = operands[0];
   op[1] = operands[1];
   op[2] = operands[2];
   op[3] = operands[3];
   str[0] = 0;
-    
-  if (CONSTANT_P (operands[2]))
+
+  if (len)
+    *len = 1;
+
+  if (GET_CODE (operands[2]) == CONST_INT)
     {
-      if (len)
-       ++*len;
+      int scratch = (GET_CODE (PATTERN (insn)) == PARALLEL);
+      int count = INTVAL (operands[2]);
+      int max_len = 10;  /* If larger than this, always use a loop.  */
+
+      if (count < 8 && !scratch)
+       use_zero_reg = 1;
+
+      if (optimize_size)
+       max_len = t_len + (scratch ? 3 : (use_zero_reg ? 4 : 5));
+
+      if (t_len * count <= max_len)
+       {
+         /* Output shifts inline with no loop - faster.  */
+         if (len)
+           *len = t_len * count;
+         else
+           {
+             while (count-- > 0)
+               output_asm_insn (template, op);
+           }
+
+         return;
+       }
+
+      if (scratch)
+       {
+         if (!len)
+           strcat (str, AS2 (ldi,%3,%2));
+       }
+      else if (use_zero_reg)
+       {
+         /* Hack to save one word: use __zero_reg__ as loop counter.
+            Set one bit, then shift in a loop until it is 0 again.  */
+
+         op[3] = zero_reg_rtx;
+         if (len)
+           *len = 2;
+         else
+           strcat (str, ("set" CR_TAB
+                         AS2 (bld,%3,%2-1)));
+       }
       else
-       strcat (str, "ldi %3,lo8((%2)-1)");
+       {
+         /* No scratch register available, use one from LD_REGS (saved in
+            __tmp_reg__) that doesn't overlap with registers to shift.  */
+
+         op[3] = gen_rtx (REG, QImode,
+                          ((true_regnum (operands[0]) - 1) & 15) + 16);
+         op[4] = tmp_reg_rtx;
+         saved_in_tmp = 1;
+
+         if (len)
+           *len = 3;  /* Includes "mov %3,%4" after the loop.  */
+         else
+           strcat (str, (AS2 (mov,%4,%3) CR_TAB
+                         AS2 (ldi,%3,%2)));
+       }
+
       second_label = 0;
     }
   else if (GET_CODE (operands[2]) == MEM)
     {
-      int mov_len;
       rtx op_mov[10];
       
       op[3] = op_mov[0] = tmp_reg_rtx;
       op_mov[1] = op[2];
-      
-      if (!len)
-       {
-         output_asm_insn (out_movqi_r_mr (insn, op_mov, NULL), op_mov);
-         strcat (str, AS1 (rjmp,2f));
-       }
+
+      if (len)
+       out_movqi_r_mr (insn, op_mov, len);
       else
-       {
-         out_movqi_r_mr (insn, op_mov, &mov_len);
-         *len = mov_len + 1;
-       }
+       output_asm_insn (out_movqi_r_mr (insn, op_mov, NULL), op_mov);
     }
-  else if (register_operand (operands[2],QImode))
+  else if (register_operand (operands[2], QImode))
     {
       if (reg_unused_after (insn, operands[2]))
        op[3] = op[2];
       else
        {
          op[3] = tmp_reg_rtx;
-         if (len)
-           ++*len;
-         else
-           strcat (str, "mov %3,%2" CR_TAB);
+         if (!len)
+           strcat (str, (AS2 (mov,%3,%2) CR_TAB));
        }
-      
+    }
+  else
+    fatal_insn ("Bad shift insn:", insn);
+
+  if (second_label)
+    {
       if (len)
        ++*len;
       else
        strcat (str, AS1 (rjmp,2f));
-      
     }
-  if (!len)
+
+  if (len)
+    *len += t_len + 2;  /* template + dec + brXX */
+  else
     {
-      strcat (str,"\n1:\t");
+      strcat (str, "\n1:\t");
       strcat (str, template);
       strcat (str, second_label ? "\n2:\t" : "\n\t");
-      strcat (str,
-             AS1 (dec,%3) CR_TAB
-             AS1 (brpl,1b));
+      strcat (str, use_zero_reg ? AS1 (lsr,%3) : AS1 (dec,%3));
+      strcat (str, CR_TAB);
+      strcat (str, second_label ? AS1 (brpl,1b) : AS1 (brne,1b));
+      if (saved_in_tmp)
+       strcat (str, (CR_TAB AS2 (mov,%3,%4)));
       output_asm_insn (str, op);
     }
 }
@@ -2118,8 +2939,8 @@ out_shift_with_cnt (template,insn,operands,len)
 
 /* 8bit shift left ((char)x << i)   */
 
-char *
-ashlqi3_out (insn,operands,len)
+const char *
+ashlqi3_out (insn, operands, len)
      rtx insn;
      rtx operands[];
      int *len;                 /* insn length (may be NULL) */
@@ -2153,7 +2974,7 @@ ashlqi3_out (insn,operands,len)
                  AS1 (lsl,%0));
 
        case 4:
-         if (TEST_HARD_REG_CLASS (LD_REGS, true_regnum (operands[0])))
+         if (test_hard_reg_class (LD_REGS, operands[0]))
            {
              *len = 2;
              return (AS1 (swap,%0) CR_TAB
@@ -2166,7 +2987,7 @@ ashlqi3_out (insn,operands,len)
                  AS1 (lsl,%0));
 
        case 5:
-         if (TEST_HARD_REG_CLASS (LD_REGS, true_regnum (operands[0])))
+         if (test_hard_reg_class (LD_REGS, operands[0]))
            {
              *len = 3;
              return (AS1 (swap,%0) CR_TAB
@@ -2181,7 +3002,7 @@ ashlqi3_out (insn,operands,len)
                  AS1 (lsl,%0));
 
        case 6:
-         if (TEST_HARD_REG_CLASS (LD_REGS, true_regnum (operands[0])))
+         if (test_hard_reg_class (LD_REGS, operands[0]))
            {
              *len = 4;
              return (AS1 (swap,%0) CR_TAB
@@ -2207,45 +3028,109 @@ ashlqi3_out (insn,operands,len)
   else if (CONSTANT_P (operands[2]))
     fatal_insn ("Internal compiler bug.\nIncorrect shift:", insn);
 
-  if (len)
-    *len = 3;
   out_shift_with_cnt (AS1 (lsl,%0),
-                     insn, operands, len);
+                     insn, operands, len, 1);
   return "";
 }
 
 
 /* 16bit shift left ((short)x << i)   */
 
-char *
-ashlhi3_out (insn,operands,len)
+const char *
+ashlhi3_out (insn, operands, len)
      rtx insn;
      rtx operands[];
      int *len;
 {
   if (GET_CODE (operands[2]) == CONST_INT)
     {
+      int scratch = (GET_CODE (PATTERN (insn)) == PARALLEL);
+      int ldi_ok = test_hard_reg_class (LD_REGS, operands[0]);
       int k;
-      int *t=len;
+      int *t = len;
 
       if (!len)
        len = &k;
       
       switch (INTVAL (operands[2]))
        {
-       default: len = t; break;
-         
-       case 1:
-         *len = 2;
-         return (AS1 (lsl,%A0) CR_TAB
-                 AS1 (rol,%B0));
+       case 4:
+         if (optimize_size && scratch)
+           break;  /* 5 */
+         if (ldi_ok)
+           {
+             *len = 6;
+             return (AS1 (swap,%A0)      CR_TAB
+                     AS1 (swap,%B0)      CR_TAB
+                     AS2 (andi,%B0,0xf0) CR_TAB
+                     AS2 (eor,%B0,%A0)   CR_TAB
+                     AS2 (andi,%A0,0xf0) CR_TAB
+                     AS2 (eor,%B0,%A0));
+           }
+         if (scratch)
+           {
+             *len = 7;
+             return (AS1 (swap,%A0)    CR_TAB
+                     AS1 (swap,%B0)    CR_TAB
+                     AS2 (ldi,%3,0xf0) CR_TAB
+                     AS2 (and,%B0,%3)  CR_TAB
+                     AS2 (eor,%B0,%A0) CR_TAB
+                     AS2 (and,%A0,%3)  CR_TAB
+                     AS2 (eor,%B0,%A0));
+           }
+         break;  /* optimize_size ? 6 : 8 */
 
-       case 2:
-         *len = 4;
-         return (AS1 (lsl,%A0) CR_TAB
-                 AS1 (rol,%B0) CR_TAB
-                 AS1 (lsl,%0)  CR_TAB
-                 AS1 (rol,%B0));
+       case 5:
+         if (optimize_size)
+           break;  /* scratch ? 5 : 6 */
+         if (ldi_ok)
+           {
+             *len = 8;
+             return (AS1 (lsl,%A0)       CR_TAB
+                     AS1 (rol,%B0)       CR_TAB
+                     AS1 (swap,%A0)      CR_TAB
+                     AS1 (swap,%B0)      CR_TAB
+                     AS2 (andi,%B0,0xf0) CR_TAB
+                     AS2 (eor,%B0,%A0)   CR_TAB
+                     AS2 (andi,%A0,0xf0) CR_TAB
+                     AS2 (eor,%B0,%A0));
+           }
+         if (scratch)
+           {
+             *len = 9;
+             return (AS1 (lsl,%A0)     CR_TAB
+                     AS1 (rol,%B0)     CR_TAB
+                     AS1 (swap,%A0)    CR_TAB
+                     AS1 (swap,%B0)    CR_TAB
+                     AS2 (ldi,%3,0xf0) CR_TAB
+                     AS2 (and,%B0,%3)  CR_TAB
+                     AS2 (eor,%B0,%A0) CR_TAB
+                     AS2 (and,%A0,%3)  CR_TAB
+                     AS2 (eor,%B0,%A0));
+           }
+         break;  /* 10 */
+
+       case 6:
+         if (optimize_size)
+           break;  /* scratch ? 5 : 6 */
+         *len = 9;
+         return (AS1 (clr,__tmp_reg__) CR_TAB
+                 AS1 (lsr,%B0)         CR_TAB
+                 AS1 (ror,%A0)         CR_TAB
+                 AS1 (ror,__tmp_reg__) CR_TAB
+                 AS1 (lsr,%B0)         CR_TAB
+                 AS1 (ror,%A0)         CR_TAB
+                 AS1 (ror,__tmp_reg__) CR_TAB
+                 AS2 (mov,%B0,%A0)     CR_TAB
+                 AS2 (mov,%A0,__tmp_reg__));
+
+       case 7:
+         *len = 5;
+         return (AS1 (lsr,%B0)     CR_TAB
+                 AS2 (mov,%B0,%A0) CR_TAB
+                 AS1 (clr,%A0)     CR_TAB
+                 AS1 (ror,%B0)     CR_TAB
+                 AS1 (ror,%A0));
 
        case 8:
          if (true_regnum (operands[0]) + 1 == true_regnum (operands[1]))
@@ -2253,21 +3138,162 @@ ashlhi3_out (insn,operands,len)
          else
            return *len = 2, (AS2 (mov,%B0,%A1) CR_TAB
                              AS1 (clr,%A0));
+
+       case 9:
+         *len = 3;
+         return (AS2 (mov,%B0,%A0) CR_TAB
+                 AS1 (clr,%A0)     CR_TAB
+                 AS1 (lsl,%B0));
+
+       case 10:
+         *len = 4;
+         return (AS2 (mov,%B0,%A0) CR_TAB
+                 AS1 (clr,%A0)     CR_TAB
+                 AS1 (lsl,%B0)     CR_TAB
+                 AS1 (lsl,%B0));
+
+       case 11:
+         *len = 5;
+         return (AS2 (mov,%B0,%A0) CR_TAB
+                 AS1 (clr,%A0)     CR_TAB
+                 AS1 (lsl,%B0)     CR_TAB
+                 AS1 (lsl,%B0)     CR_TAB
+                 AS1 (lsl,%B0));
+
+       case 12:
+         if (ldi_ok)
+           {
+             *len = 4;
+             return (AS2 (mov,%B0,%A0) CR_TAB
+                     AS1 (clr,%A0)     CR_TAB
+                     AS1 (swap,%B0)    CR_TAB
+                     AS2 (andi,%B0,0xf0));
+           }
+         if (scratch)
+           {
+             *len = 5;
+             return (AS2 (mov,%B0,%A0) CR_TAB
+                     AS1 (clr,%A0)     CR_TAB
+                     AS1 (swap,%B0)    CR_TAB
+                     AS2 (ldi,%3,0xf0) CR_TAB
+                     AS2 (and,%B0,%3));
+           }
+         *len = 6;
+         return (AS2 (mov,%B0,%A0) CR_TAB
+                 AS1 (clr,%A0)     CR_TAB
+                 AS1 (lsl,%B0)     CR_TAB
+                 AS1 (lsl,%B0)     CR_TAB
+                 AS1 (lsl,%B0)     CR_TAB
+                 AS1 (lsl,%B0));
+
+       case 13:
+         if (ldi_ok)
+           {
+             *len = 5;
+             return (AS2 (mov,%B0,%A0) CR_TAB
+                     AS1 (clr,%A0)     CR_TAB
+                     AS1 (swap,%B0)    CR_TAB
+                     AS1 (lsl,%B0)     CR_TAB
+                     AS2 (andi,%B0,0xe0));
+           }
+         if (AVR_ENHANCED && scratch)
+           {
+             *len = 5;
+             return (AS2 (ldi,%3,0x20) CR_TAB
+                     AS2 (mul,%A0,%3)  CR_TAB
+                     AS2 (mov,%B0,r0)  CR_TAB
+                     AS1 (clr,%A0)     CR_TAB
+                     AS1 (clr,__zero_reg__));
+           }
+         if (optimize_size && scratch)
+           break;  /* 5 */
+         if (scratch)
+           {
+             *len = 6;
+             return (AS2 (mov,%B0,%A0) CR_TAB
+                     AS1 (clr,%A0)     CR_TAB
+                     AS1 (swap,%B0)    CR_TAB
+                     AS1 (lsl,%B0)     CR_TAB
+                     AS2 (ldi,%3,0xe0) CR_TAB
+                     AS2 (and,%B0,%3));
+           }
+         if (AVR_ENHANCED)
+           {
+             *len = 6;
+             return ("set"            CR_TAB
+                     AS2 (bld,r1,5)   CR_TAB
+                     AS2 (mul,%A0,r1) CR_TAB
+                     AS2 (mov,%B0,r0) CR_TAB
+                     AS1 (clr,%A0)    CR_TAB
+                     AS1 (clr,__zero_reg__));
+           }
+         *len = 7;
+         return (AS2 (mov,%B0,%A0) CR_TAB
+                 AS1 (clr,%A0)     CR_TAB
+                 AS1 (lsl,%B0)     CR_TAB
+                 AS1 (lsl,%B0)     CR_TAB
+                 AS1 (lsl,%B0)     CR_TAB
+                 AS1 (lsl,%B0)     CR_TAB
+                 AS1 (lsl,%B0));
+
+       case 14:
+         if (AVR_ENHANCED && ldi_ok)
+           {
+             *len = 5;
+             return (AS2 (ldi,%B0,0x40) CR_TAB
+                     AS2 (mul,%A0,%B0)  CR_TAB
+                     AS2 (mov,%B0,r0)   CR_TAB
+                     AS1 (clr,%A0)      CR_TAB
+                     AS1 (clr,__zero_reg__));
+           }
+         if (AVR_ENHANCED && scratch)
+           {
+             *len = 5;
+             return (AS2 (ldi,%3,0x40) CR_TAB
+                     AS2 (mul,%A0,%3)  CR_TAB
+                     AS2 (mov,%B0,r0)  CR_TAB
+                     AS1 (clr,%A0)     CR_TAB
+                     AS1 (clr,__zero_reg__));
+           }
+         if (optimize_size && ldi_ok)
+           {
+             *len = 5;
+             return (AS2 (mov,%B0,%A0) CR_TAB
+                     AS2 (ldi,%A0,6) "\n1:\t"
+                     AS1 (lsl,%B0)     CR_TAB
+                     AS1 (dec,%A0)     CR_TAB
+                     AS1 (brne,1b));
+           }
+         if (optimize_size && scratch)
+           break;  /* 5 */
+         *len = 6;
+         return (AS1 (clr,%B0) CR_TAB
+                 AS1 (lsr,%A0) CR_TAB
+                 AS1 (ror,%B0) CR_TAB
+                 AS1 (lsr,%A0) CR_TAB
+                 AS1 (ror,%B0) CR_TAB
+                 AS1 (clr,%A0));
+
+       case 15:
+         *len = 4;
+         return (AS1 (clr,%B0) CR_TAB
+                 AS1 (lsr,%A0) CR_TAB
+                 AS1 (ror,%B0) CR_TAB
+                 AS1 (clr,%A0));
        }
+      len = t;
     }
-  if (len)
-    *len = 4;
-  out_shift_with_cnt (AS1 (lsl,%0)  CR_TAB
-                     AS1 (rol,%B0),
-                     insn, operands, len);
+  out_shift_with_cnt ((AS1 (lsl,%A0) CR_TAB
+                      AS1 (rol,%B0)),
+                      insn, operands, len, 2);
   return "";
 }
 
 
 /* 32bit shift left ((long)x << i)   */
 
-char *
-ashlsi3_out (insn,operands,len)
+const char *
+ashlsi3_out (insn, operands, len)
      rtx insn;
      rtx operands[];
      int *len;
@@ -2275,22 +3301,13 @@ ashlsi3_out (insn,operands,len)
   if (GET_CODE (operands[2]) == CONST_INT)
     {
       int k;
-      int *t=len;
+      int *t = len;
       
       if (!len)
        len = &k;
       
       switch (INTVAL (operands[2]))
        {
-       default: len = t; break;
-         
-       case 1:
-         *len = 4;
-         return (AS1 (lsl,%A0) CR_TAB
-                 AS1 (rol,%B0) CR_TAB
-                 AS1 (rol,%C0) CR_TAB
-                 AS1 (rol,%D0));
-
        case 8:
          {
            int reg0 = true_regnum (operands[0]);
@@ -2318,6 +3335,13 @@ ashlsi3_out (insn,operands,len)
            int reg0 = true_regnum (operands[0]);
            int reg1 = true_regnum (operands[1]);
            *len = 4;
+           if (AVR_ENHANCED && (reg0 + 2 != reg1))
+             {
+               *len = 3;
+               return (AS2 (movw,%C0,%A1) CR_TAB
+                       AS1 (clr,%B0)      CR_TAB
+                       AS1 (clr,%A0));
+             }
            if (reg0 + 1 >= reg1)
              return (AS2 (mov,%D0,%B1)  CR_TAB
                      AS2 (mov,%C0,%A1)  CR_TAB
@@ -2350,22 +3374,30 @@ ashlsi3_out (insn,operands,len)
                      AS1 (clr,%B0)      CR_TAB
                      AS1 (clr,%A0));
            }
+
+       case 31:
+         *len = 6;
+         return (AS1 (clr,%D0) CR_TAB
+                 AS1 (lsr,%A0) CR_TAB
+                 AS1 (ror,%D0) CR_TAB
+                 AS1 (clr,%C0) CR_TAB
+                 AS1 (clr,%B0) CR_TAB
+                 AS1 (clr,%A0));
        }
+      len = t;
     }
-  if (len)
-    *len = 6;
-  out_shift_with_cnt (AS1 (lsl,%0)  CR_TAB
-                     AS1 (rol,%B0) CR_TAB
-                     AS1 (rol,%C0) CR_TAB
-                     AS1 (rol,%D0),
-                     insn, operands, len);
+  out_shift_with_cnt ((AS1 (lsl,%A0) CR_TAB
+                      AS1 (rol,%B0) CR_TAB
+                      AS1 (rol,%C0) CR_TAB
+                      AS1 (rol,%D0)),
+                      insn, operands, len, 4);
   return "";
 }
 
 /* 8bit arithmetic shift right  ((signed char)x >> i) */
 
-char *
-ashrqi3_out (insn,operands,len)
+const char *
+ashrqi3_out (insn, operands, len)
      rtx insn;
      rtx operands[];
      int *len; /* insn length */
@@ -2426,24 +3458,24 @@ ashrqi3_out (insn,operands,len)
   else if (CONSTANT_P (operands[2]))
     fatal_insn ("Internal compiler bug.\nIncorrect shift:", insn);
 
-  if (len)
-    *len = 3;
   out_shift_with_cnt (AS1 (asr,%0),
-                     insn, operands, len);
+                     insn, operands, len, 1);
   return "";
 }
 
 
 /* 16bit arithmetic shift right  ((signed short)x >> i) */
 
-char *
-ashrhi3_out (insn,operands,len)
+const char *
+ashrhi3_out (insn, operands, len)
      rtx insn;
      rtx operands[];
      int *len;
 {
   if (GET_CODE (operands[2]) == CONST_INT)
     {
+      int scratch = (GET_CODE (PATTERN (insn)) == PARALLEL);
+      int ldi_ok = test_hard_reg_class (LD_REGS, operands[0]);
       int k;
       int *t = len;
       
@@ -2452,50 +3484,155 @@ ashrhi3_out (insn,operands,len)
 
       switch (INTVAL (operands[2]))
        {
-       default: len = t; break;
-         
-       case 1:
-         *len=2;
-         return (AS1 (asr,%B0) CR_TAB
-                 AS1 (ror,%A0));
+       case 4:
+       case 5:
+         /* XXX try to optimize this too? */
+         break;
 
-       case 2:
-         *len=4;
-         return (AS1 (asr,%B0)  CR_TAB
-                 AS1 (ror,%A0) CR_TAB
-                 AS1 (asr,%B0)  CR_TAB
-                 AS1 (ror,%A0));
+       case 6:
+         if (optimize_size)
+           break;  /* scratch ? 5 : 6 */
+         *len = 8;
+         return (AS2 (mov,__tmp_reg__,%A0) CR_TAB
+                 AS2 (mov,%A0,%B0)         CR_TAB
+                 AS1 (lsl,__tmp_reg__)     CR_TAB
+                 AS1 (rol,%A0)             CR_TAB
+                 AS2 (sbc,%B0,%B0)         CR_TAB
+                 AS1 (lsl,__tmp_reg__)     CR_TAB
+                 AS1 (rol,%A0)             CR_TAB
+                 AS1 (rol,%B0));
+
+       case 7:
+         *len = 4;
+         return (AS1 (lsl,%A0)     CR_TAB
+                 AS2 (mov,%A0,%B0) CR_TAB
+                 AS1 (rol,%A0)     CR_TAB
+                 AS2 (sbc,%B0,%B0));
 
        case 8:
-         if (true_regnum (operands[0]) != true_regnum (operands[1]) + 1)
+         {
+           int reg0 = true_regnum (operands[0]);
+           int reg1 = true_regnum (operands[1]);
+
+           if (reg0 == reg1)
+             return *len = 3, (AS2 (mov,%A0,%B0) CR_TAB
+                               AS1 (lsl,%B0)     CR_TAB
+                               AS2 (sbc,%B0,%B0));
+           else if (reg0 == reg1 + 1)
+             return *len = 3, (AS1 (clr,%B0)    CR_TAB
+                               AS2 (sbrc,%A0,7) CR_TAB
+                               AS1 (dec,%B0));
+
            return *len = 4, (AS2 (mov,%A0,%B1) CR_TAB
                              AS1 (clr,%B0)     CR_TAB
                              AS2 (sbrc,%A0,7)  CR_TAB
                              AS1 (dec,%B0));
-         else
-           return *len = 3, (AS1 (clr,%B0)     CR_TAB
-                             AS2 (sbrc,%A0,7)  CR_TAB
-                             AS1 (dec,%B0));
+         }
+
+       case 9:
+         *len = 4;
+         return (AS2 (mov,%A0,%B0) CR_TAB
+                 AS1 (lsl,%B0)      CR_TAB
+                 AS2 (sbc,%B0,%B0) CR_TAB
+                 AS1 (asr,%A0));
+
+       case 10:
+         *len = 5;
+         return (AS2 (mov,%A0,%B0) CR_TAB
+                 AS1 (lsl,%B0)     CR_TAB
+                 AS2 (sbc,%B0,%B0) CR_TAB
+                 AS1 (asr,%A0)     CR_TAB
+                 AS1 (asr,%A0));
+
+       case 11:
+         if (AVR_ENHANCED && ldi_ok)
+           {
+             *len = 5;
+             return (AS2 (ldi,%A0,0x20) CR_TAB
+                     AS2 (muls,%B0,%A0) CR_TAB
+                     AS2 (mov,%A0,r1)   CR_TAB
+                     AS2 (sbc,%B0,%B0)  CR_TAB
+                     AS1 (clr,__zero_reg__));
+           }
+         if (optimize_size && scratch)
+           break;  /* 5 */
+         *len = 6;
+         return (AS2 (mov,%A0,%B0) CR_TAB
+                 AS1 (lsl,%B0)     CR_TAB
+                 AS2 (sbc,%B0,%B0) CR_TAB
+                 AS1 (asr,%A0)     CR_TAB
+                 AS1 (asr,%A0)     CR_TAB
+                 AS1 (asr,%A0));
+
+       case 12:
+         if (AVR_ENHANCED && ldi_ok)
+           {
+             *len = 5;
+             return (AS2 (ldi,%A0,0x10) CR_TAB
+                     AS2 (muls,%B0,%A0) CR_TAB
+                     AS2 (mov,%A0,r1)   CR_TAB
+                     AS2 (sbc,%B0,%B0)  CR_TAB
+                     AS1 (clr,__zero_reg__));
+           }
+         if (optimize_size && scratch)
+           break;  /* 5 */
+         *len = 7;
+         return (AS2 (mov,%A0,%B0) CR_TAB
+                 AS1 (lsl,%B0)     CR_TAB
+                 AS2 (sbc,%B0,%B0) CR_TAB
+                 AS1 (asr,%A0)     CR_TAB
+                 AS1 (asr,%A0)     CR_TAB
+                 AS1 (asr,%A0)     CR_TAB
+                 AS1 (asr,%A0));
+
+       case 13:
+         if (AVR_ENHANCED && ldi_ok)
+           {
+             *len = 5;
+             return (AS2 (ldi,%A0,0x08) CR_TAB
+                     AS2 (muls,%B0,%A0) CR_TAB
+                     AS2 (mov,%A0,r1)   CR_TAB
+                     AS2 (sbc,%B0,%B0)  CR_TAB
+                     AS1 (clr,__zero_reg__));
+           }
+         if (optimize_size)
+           break;  /* scratch ? 5 : 7 */
+         *len = 8;
+         return (AS2 (mov,%A0,%B0) CR_TAB
+                 AS1 (lsl,%B0)     CR_TAB
+                 AS2 (sbc,%B0,%B0) CR_TAB
+                 AS1 (asr,%A0)     CR_TAB
+                 AS1 (asr,%A0)     CR_TAB
+                 AS1 (asr,%A0)     CR_TAB
+                 AS1 (asr,%A0)     CR_TAB
+                 AS1 (asr,%A0));
+
+       case 14:
+         *len = 5;
+         return (AS1 (lsl,%B0)     CR_TAB
+                 AS2 (sbc,%A0,%A0) CR_TAB
+                 AS1 (lsl,%B0)     CR_TAB
+                 AS2 (mov,%B0,%A0) CR_TAB
+                 AS1 (rol,%A0));
 
        case 15:
          return *len = 3, (AS1 (lsl,%B0)     CR_TAB
                            AS2 (sbc,%A0,%A0) CR_TAB
                            AS2 (mov,%B0,%A0));
        }
+      len = t;
     }
-  if (len)
-    *len = 4;
-  out_shift_with_cnt (AS1 (asr,%B0) CR_TAB
-                     AS1 (ror,%A0),
-                     insn, operands, len);
+  out_shift_with_cnt ((AS1 (asr,%B0) CR_TAB
+                      AS1 (ror,%A0)),
+                      insn, operands, len, 2);
   return "";
 }
 
 
 /* 32bit arithmetic shift right  ((signed long)x >> i) */
 
-char *
-ashrsi3_out (insn,operands,len)
+const char *
+ashrsi3_out (insn, operands, len)
      rtx insn;
      rtx operands[];
      int *len;
@@ -2510,15 +3647,6 @@ ashrsi3_out (insn,operands,len)
       
       switch (INTVAL (operands[2]))
        {
-       default: len = t; break;
-
-       case 1:
-         *len=4;
-         return (AS1 (asr,%D0)  CR_TAB
-                 AS1 (ror,%C0)  CR_TAB
-                 AS1 (ror,%B0)  CR_TAB
-                 AS1 (ror,%A0));
-
        case 8:
          {
            int reg0 = true_regnum (operands[0]);
@@ -2552,6 +3680,15 @@ ashrsi3_out (insn,operands,len)
            int reg0 = true_regnum (operands[0]);
            int reg1 = true_regnum (operands[1]);
            *len=6;
+           if (AVR_ENHANCED && (reg0 != reg1 + 2))
+             {
+               *len = 5;
+               return (AS2 (movw,%A0,%C1) CR_TAB
+                       AS1 (clr,%D0)      CR_TAB
+                       AS2 (sbrc,%B0,7)   CR_TAB
+                       AS1 (com,%D0)      CR_TAB
+                       AS2 (mov,%C0,%D0));
+             }
            if (reg0 <= reg1 + 1)
              return (AS2 (mov,%A0,%C1) CR_TAB
                      AS2 (mov,%B0,%D1) CR_TAB
@@ -2587,22 +3724,34 @@ ashrsi3_out (insn,operands,len)
                              AS1 (com,%D0)     CR_TAB
                              AS2 (mov,%B0,%D0) CR_TAB
                              AS2 (mov,%C0,%D0));
+
+       case 31:
+         if (AVR_ENHANCED)
+           return *len = 4, (AS1 (lsl,%D0)     CR_TAB
+                             AS2 (sbc,%A0,%A0) CR_TAB
+                             AS2 (mov,%B0,%A0) CR_TAB
+                             AS2 (movw,%C0,%A0));
+         else
+           return *len = 5, (AS1 (lsl,%D0)     CR_TAB
+                             AS2 (sbc,%A0,%A0) CR_TAB
+                             AS2 (mov,%B0,%A0) CR_TAB
+                             AS2 (mov,%C0,%A0) CR_TAB
+                             AS2 (mov,%D0,%A0));
        }
+      len = t;
     }
-  if (len)
-    *len = 6;
-  out_shift_with_cnt (AS1 (asr,%D0) CR_TAB
-                     AS1 (ror,%C0) CR_TAB
-                     AS1 (ror,%B0) CR_TAB
-                     AS1 (ror,%A0),
-                     insn, operands, len);
+  out_shift_with_cnt ((AS1 (asr,%D0) CR_TAB
+                      AS1 (ror,%C0) CR_TAB
+                      AS1 (ror,%B0) CR_TAB
+                      AS1 (ror,%A0)),
+                      insn, operands, len, 4);
   return "";
 }
 
 /* 8bit logic shift right ((unsigned char)x >> i) */
 
-char *
-lshrqi3_out (insn,operands,len)
+const char *
+lshrqi3_out (insn, operands, len)
      rtx insn;
      rtx operands[];
      int *len;
@@ -2635,7 +3784,7 @@ lshrqi3_out (insn,operands,len)
                  AS1 (lsr,%0));
          
        case 4:
-         if (TEST_HARD_REG_CLASS (LD_REGS, true_regnum (operands[0])))
+         if (test_hard_reg_class (LD_REGS, operands[0]))
            {
              *len=2;
              return (AS1 (swap,%0) CR_TAB
@@ -2648,7 +3797,7 @@ lshrqi3_out (insn,operands,len)
                  AS1 (lsr,%0));
          
        case 5:
-         if (TEST_HARD_REG_CLASS (LD_REGS, true_regnum (operands[0])))
+         if (test_hard_reg_class (LD_REGS, operands[0]))
            {
              *len = 3;
              return (AS1 (swap,%0) CR_TAB
@@ -2663,7 +3812,7 @@ lshrqi3_out (insn,operands,len)
                  AS1 (lsr,%0));
          
        case 6:
-         if (TEST_HARD_REG_CLASS (LD_REGS, true_regnum (operands[0])))
+         if (test_hard_reg_class (LD_REGS, operands[0]))
            {
              *len = 4;
              return (AS1 (swap,%0) CR_TAB
@@ -2689,72 +3838,270 @@ lshrqi3_out (insn,operands,len)
   else if (CONSTANT_P (operands[2]))
     fatal_insn ("Internal compiler bug.\nIncorrect shift:", insn);
   
-  if (len)
-    *len = 3;
   out_shift_with_cnt (AS1 (lsr,%0),
-                     insn, operands, len);
+                     insn, operands, len, 1);
   return "";
 }
 
 /* 16bit logic shift right ((unsigned short)x >> i) */
 
-char *
-lshrhi3_out (insn,operands,len)
+const char *
+lshrhi3_out (insn, operands, len)
      rtx insn;
      rtx operands[];
      int *len;
 {
   if (GET_CODE (operands[2]) == CONST_INT)
     {
+      int scratch = (GET_CODE (PATTERN (insn)) == PARALLEL);
+      int ldi_ok = test_hard_reg_class (LD_REGS, operands[0]);
       int k;
       int *t = len;
-      
+
       if (!len)
        len = &k;
       
       switch (INTVAL (operands[2]))
        {
-       default: len = t; break;
-         
-       case 1:
-         *len = 2;
-         return (AS1 (lsr,%B0) CR_TAB
-                 AS1 (ror,%A0));
-         
-       case 2:
-         *len = 4;
-         return (AS1 (lsr,%B0)  CR_TAB
-                 AS1 (ror,%A0)  CR_TAB
-                 AS1 (lsr,%B0)  CR_TAB
-                 AS1 (ror,%A0));
-         
+       case 4:
+         if (optimize_size && scratch)
+           break;  /* 5 */
+         if (ldi_ok)
+           {
+             *len = 6;
+             return (AS1 (swap,%B0)      CR_TAB
+                     AS1 (swap,%A0)      CR_TAB
+                     AS2 (andi,%A0,0x0f) CR_TAB
+                     AS2 (eor,%A0,%B0)   CR_TAB
+                     AS2 (andi,%B0,0x0f) CR_TAB
+                     AS2 (eor,%A0,%B0));
+           }
+         if (scratch)
+           {
+             *len = 7;
+             return (AS1 (swap,%B0)    CR_TAB
+                     AS1 (swap,%A0)    CR_TAB
+                     AS2 (ldi,%3,0x0f) CR_TAB
+                     AS2 (and,%A0,%3)  CR_TAB
+                     AS2 (eor,%A0,%B0) CR_TAB
+                     AS2 (and,%B0,%3)  CR_TAB
+                     AS2 (eor,%A0,%B0));
+           }
+         break;  /* optimize_size ? 6 : 8 */
+
+       case 5:
+         if (optimize_size)
+           break;  /* scratch ? 5 : 6 */
+         if (ldi_ok)
+           {
+             *len = 8;
+             return (AS1 (lsr,%B0)       CR_TAB
+                     AS1 (ror,%A0)       CR_TAB
+                     AS1 (swap,%B0)      CR_TAB
+                     AS1 (swap,%A0)      CR_TAB
+                     AS2 (andi,%A0,0x0f) CR_TAB
+                     AS2 (eor,%A0,%B0)   CR_TAB
+                     AS2 (andi,%B0,0x0f) CR_TAB
+                     AS2 (eor,%A0,%B0));
+           }
+         if (scratch)
+           {
+             *len = 9;
+             return (AS1 (lsr,%B0)     CR_TAB
+                     AS1 (ror,%A0)     CR_TAB
+                     AS1 (swap,%B0)    CR_TAB
+                     AS1 (swap,%A0)    CR_TAB
+                     AS2 (ldi,%3,0x0f) CR_TAB
+                     AS2 (and,%A0,%3)  CR_TAB
+                     AS2 (eor,%A0,%B0) CR_TAB
+                     AS2 (and,%B0,%3)  CR_TAB
+                     AS2 (eor,%A0,%B0));
+           }
+         break;  /* 10 */
+
+       case 6:
+         if (optimize_size)
+           break;  /* scratch ? 5 : 6 */
+         *len = 9;
+         return (AS1 (clr,__tmp_reg__) CR_TAB
+                 AS1 (lsl,%A0)         CR_TAB
+                 AS1 (rol,%B0)         CR_TAB
+                 AS1 (rol,__tmp_reg__) CR_TAB
+                 AS1 (lsl,%A0)         CR_TAB
+                 AS1 (rol,%B0)         CR_TAB
+                 AS1 (rol,__tmp_reg__) CR_TAB
+                 AS2 (mov,%A0,%B0)     CR_TAB
+                 AS2 (mov,%B0,__tmp_reg__));
+
+       case 7:
+         *len = 5;
+         return (AS1 (lsl,%A0)     CR_TAB
+                 AS2 (mov,%A0,%B0) CR_TAB
+                 AS1 (rol,%A0)     CR_TAB
+                 AS2 (sbc,%B0,%B0) CR_TAB
+                 AS1 (neg,%B0));
+
        case 8:
          if (true_regnum (operands[0]) != true_regnum (operands[1]) + 1)
            return *len = 2, (AS2 (mov,%A0,%B1) CR_TAB
                              AS1 (clr,%B0));
          else
            return *len = 1, AS1 (clr,%B0);
-         
+
+       case 9:
+         *len = 3;
+         return (AS2 (mov,%A0,%B0) CR_TAB
+                 AS1 (clr,%B0)     CR_TAB
+                 AS1 (lsr,%A0));
+
+       case 10:
+         *len = 4;
+         return (AS2 (mov,%A0,%B0) CR_TAB
+                 AS1 (clr,%B0)     CR_TAB
+                 AS1 (lsr,%A0)     CR_TAB
+                 AS1 (lsr,%A0));
+
+       case 11:
+         *len = 5;
+         return (AS2 (mov,%A0,%B0) CR_TAB
+                 AS1 (clr,%B0)     CR_TAB
+                 AS1 (lsr,%A0)     CR_TAB
+                 AS1 (lsr,%A0)     CR_TAB
+                 AS1 (lsr,%A0));
+
+       case 12:
+         if (ldi_ok)
+           {
+             *len = 4;
+             return (AS2 (mov,%A0,%B0) CR_TAB
+                     AS1 (clr,%B0)     CR_TAB
+                     AS1 (swap,%A0)    CR_TAB
+                     AS2 (andi,%A0,0x0f));
+           }
+         if (scratch)
+           {
+             *len = 5;
+             return (AS2 (mov,%A0,%B0) CR_TAB
+                     AS1 (clr,%B0)     CR_TAB
+                     AS1 (swap,%A0)    CR_TAB
+                     AS2 (ldi,%3,0x0f) CR_TAB
+                     AS2 (and,%A0,%3));
+           }
+         *len = 6;
+         return (AS2 (mov,%A0,%B0) CR_TAB
+                 AS1 (clr,%B0)     CR_TAB
+                 AS1 (lsr,%A0)     CR_TAB
+                 AS1 (lsr,%A0)     CR_TAB
+                 AS1 (lsr,%A0)     CR_TAB
+                 AS1 (lsr,%A0));
+
+       case 13:
+         if (ldi_ok)
+           {
+             *len = 5;
+             return (AS2 (mov,%A0,%B0) CR_TAB
+                     AS1 (clr,%B0)     CR_TAB
+                     AS1 (swap,%A0)    CR_TAB
+                     AS1 (lsr,%A0)     CR_TAB
+                     AS2 (andi,%A0,0x07));
+           }
+         if (AVR_ENHANCED && scratch)
+           {
+             *len = 5;
+             return (AS2 (ldi,%3,0x08) CR_TAB
+                     AS2 (mul,%B0,%3)  CR_TAB
+                     AS2 (mov,%A0,r1)  CR_TAB
+                     AS1 (clr,%B0)     CR_TAB
+                     AS1 (clr,__zero_reg__));
+           }
+         if (optimize_size && scratch)
+           break;  /* 5 */
+         if (scratch)
+           {
+             *len = 6;
+             return (AS2 (mov,%A0,%B0) CR_TAB
+                     AS1 (clr,%B0)     CR_TAB
+                     AS1 (swap,%A0)    CR_TAB
+                     AS1 (lsr,%A0)     CR_TAB
+                     AS2 (ldi,%3,0x07) CR_TAB
+                     AS2 (and,%A0,%3));
+           }
+         if (AVR_ENHANCED)
+           {
+             *len = 6;
+             return ("set"            CR_TAB
+                     AS2 (bld,r1,3)   CR_TAB
+                     AS2 (mul,%B0,r1) CR_TAB
+                     AS2 (mov,%A0,r1) CR_TAB
+                     AS1 (clr,%B0)    CR_TAB
+                     AS1 (clr,__zero_reg__));
+           }
+         *len = 7;
+         return (AS2 (mov,%A0,%B0) CR_TAB
+                 AS1 (clr,%B0)     CR_TAB
+                 AS1 (lsr,%A0)     CR_TAB
+                 AS1 (lsr,%A0)     CR_TAB
+                 AS1 (lsr,%A0)     CR_TAB
+                 AS1 (lsr,%A0)     CR_TAB
+                 AS1 (lsr,%A0));
+
+       case 14:
+         if (AVR_ENHANCED && ldi_ok)
+           {
+             *len = 5;
+             return (AS2 (ldi,%A0,0x04) CR_TAB
+                     AS2 (mul,%B0,%A0)  CR_TAB
+                     AS2 (mov,%A0,r1)   CR_TAB
+                     AS1 (clr,%B0)      CR_TAB
+                     AS1 (clr,__zero_reg__));
+           }
+         if (AVR_ENHANCED && scratch)
+           {
+             *len = 5;
+             return (AS2 (ldi,%3,0x04) CR_TAB
+                     AS2 (mul,%B0,%3)  CR_TAB
+                     AS2 (mov,%A0,r1)  CR_TAB
+                     AS1 (clr,%B0)     CR_TAB
+                     AS1 (clr,__zero_reg__));
+           }
+         if (optimize_size && ldi_ok)
+           {
+             *len = 5;
+             return (AS2 (mov,%A0,%B0) CR_TAB
+                     AS2 (ldi,%B0,6) "\n1:\t"
+                     AS1 (lsr,%A0)     CR_TAB
+                     AS1 (dec,%B0)     CR_TAB
+                     AS1 (brne,1b));
+           }
+         if (optimize_size && scratch)
+           break;  /* 5 */
+         *len = 6;
+         return (AS1 (clr,%A0) CR_TAB
+                 AS1 (lsl,%B0) CR_TAB
+                 AS1 (rol,%A0) CR_TAB
+                 AS1 (lsl,%B0) CR_TAB
+                 AS1 (rol,%A0) CR_TAB
+                 AS1 (clr,%B0));
+
        case 15:
          *len = 4;
-         return (AS1 (lsl,%B0)     CR_TAB
-                 AS2 (sbc,%A0,%A0) CR_TAB
-                 AS1 (neg,%A0)     CR_TAB
+         return (AS1 (clr,%A0) CR_TAB
+                 AS1 (lsl,%B0) CR_TAB
+                 AS1 (rol,%A0) CR_TAB
                  AS1 (clr,%B0));
        }
+      len = t;
     }
-  if (len)
-    *len = 4;
-  out_shift_with_cnt (AS1 (lsr,%B0) CR_TAB
-                     AS1 (ror,%A0),
-                     insn, operands, len);
+  out_shift_with_cnt ((AS1 (lsr,%B0) CR_TAB
+                      AS1 (ror,%A0)),
+                      insn, operands, len, 2);
   return "";
 }
 
 /* 32bit logic shift right ((unsigned int)x >> i) */
 
-char *
-lshrsi3_out (insn,operands,len)
+const char *
+lshrsi3_out (insn, operands, len)
      rtx insn;
      rtx operands[];
      int *len;
@@ -2769,15 +4116,6 @@ lshrsi3_out (insn,operands,len)
       
       switch (INTVAL (operands[2]))
        {
-       default: len = t; break;
-         
-       case 1:
-         *len = 4;
-         return (AS1 (lsr,%D0)  CR_TAB
-                 AS1 (ror,%C0) CR_TAB
-                 AS1 (ror,%B0) CR_TAB
-                 AS1 (ror,%A0));
-         
        case 8:
          {
            int reg0 = true_regnum (operands[0]);
@@ -2802,6 +4140,13 @@ lshrsi3_out (insn,operands,len)
            int reg0 = true_regnum (operands[0]);
            int reg1 = true_regnum (operands[1]);
            *len = 4;
+           if (AVR_ENHANCED && (reg0 != reg1 + 2))
+             {
+               *len = 3;
+               return (AS2 (movw,%A0,%C1) CR_TAB
+                       AS1 (clr,%C0)      CR_TAB
+                       AS1 (clr,%D0));
+             }
            if (reg0 <= reg1 + 1)
              return (AS2 (mov,%A0,%C1) CR_TAB
                      AS2 (mov,%B0,%D1) CR_TAB
@@ -2827,15 +4172,23 @@ lshrsi3_out (insn,operands,len)
            return *len = 3, (AS1 (clr,%B0)     CR_TAB
                              AS1 (clr,%C0)     CR_TAB
                              AS1 (clr,%D0));
+
+       case 31:
+         *len = 6;
+         return (AS1 (clr,%A0)    CR_TAB
+                 AS2 (sbrc,%D0,7) CR_TAB
+                 AS1 (inc,%A0)    CR_TAB
+                 AS1 (clr,%B0)    CR_TAB
+                 AS1 (clr,%C0)    CR_TAB
+                 AS1 (clr,%D0));
        }
+      len = t;
     }
-  if (len)
-    *len = 6;
-  out_shift_with_cnt (AS1 (lsr,%D0) CR_TAB
-                     AS1 (ror,%C0) CR_TAB
-                     AS1 (ror,%B0) CR_TAB
-                     AS1 (ror,%A0),
-                     insn, operands, len);
+  out_shift_with_cnt ((AS1 (lsr,%D0) CR_TAB
+                      AS1 (ror,%C0) CR_TAB
+                      AS1 (ror,%B0) CR_TAB
+                      AS1 (ror,%A0)),
+                     insn, operands, len, 4);
   return "";
 }
 
@@ -2843,60 +4196,37 @@ lshrsi3_out (insn,operands,len)
  LEN is the initially computed length of the insn.  */
 
 int
-adjust_insn_length (insn,len)
+adjust_insn_length (insn, len)
      rtx insn;
      int len;
 {
   rtx patt = PATTERN (insn);
   rtx set;
+
   if (GET_CODE (patt) == SET)
     {
       rtx op[10];
       op[1] = SET_SRC (patt);
       op[0] = SET_DEST (patt);
-      if (REG_P (op[0]) && GET_CODE (op[1]) == MEM)
-        {
-         if (CONSTANT_ADDRESS_P (XEXP (op[1],0)))
-           switch (GET_MODE (op[0]))
-             {
-             case QImode: len = 2; break;
-             case HImode: len = 4; break;
-             case SImode:
-             case SFmode: len = 8; break;
-             default: break; 
-             }
-         else
-           switch (GET_MODE (op[0]))
-             {
-             case QImode: out_movqi_r_mr (insn,op,&len); break;
-             case HImode: out_movhi_r_mr (insn,op,&len); break;
-             case SImode:
-             case SFmode: out_movsi_r_mr (insn,op,&len); break;
-             default: break;
-             }
-        }
-      else if ((REG_P (op[1]) || const0_rtx == op[1])
-              && GET_CODE (op[0]) == MEM)
-        {
-         if (CONSTANT_ADDRESS_P (XEXP (op[0],0)))
-           switch (GET_MODE (op[0]))
-             {
-             case QImode: len = 2; break;
-             case HImode: len = 4; break;
-             case SImode:
-             case SFmode: len = 8; break;
-             default: break;
-             }
-         else if (GET_CODE (XEXP (op[0],0)) != POST_DEC)
-           switch (GET_MODE (op[0]))
-             {
-             case QImode: out_movqi_mr_r (insn,op,&len); break;
-             case HImode: out_movhi_mr_r (insn,op,&len); break;
-             case SImode:
-             case SFmode: out_movsi_mr_r (insn,op,&len); break;
-             default: break;
-             }
-        }
+      if (general_operand (op[1], VOIDmode)
+         && general_operand (op[0], VOIDmode))
+       {
+         switch (GET_MODE (op[0]))
+           {
+           case QImode:
+             output_movqi (insn, op, &len);
+             break;
+           case HImode:
+             output_movhi (insn, op, &len);
+             break;
+           case SImode:
+           case SFmode:
+             output_movsisf (insn, op, &len);
+             break;
+           default:
+             break;
+           }
+       }
       else if (op[0] == cc0_rtx && REG_P (op[1]))
        {
          switch (GET_MODE (op[1]))
@@ -2927,13 +4257,13 @@ adjust_insn_length (insn,len)
            {
              HOST_WIDE_INT mask = INTVAL (XEXP (op[1],1));
              if (GET_MODE (op[1]) == SImode)
-               len = (((mask & 0xff) == 0)
-                      + ((mask & 0xff00) == 0)
-                      + ((mask & 0xff0000UL) == 0)
-                      + ((mask & 0xff000000UL) ==0));
+               len = (((mask & 0xff) != 0)
+                      + ((mask & 0xff00) != 0)
+                      + ((mask & 0xff0000UL) != 0)
+                      + ((mask & 0xff000000UL) != 0));
              else if (GET_MODE (op[1]) == HImode)
-               len = (((mask & 0xff) == 0)
-                      + ((mask & 0xff00) == 0));
+               len = (((mask & 0xff) != 0)
+                      + ((mask & 0xff00) != 0));
            }
        }
     }
@@ -2941,9 +4271,34 @@ adjust_insn_length (insn,len)
   if (set)
     {
       rtx op[10];
+
       op[1] = SET_SRC (set);
       op[0] = SET_DEST (set);
-      if (GET_CODE (op[1]) == ASHIFT
+
+      if (GET_CODE (patt) == PARALLEL
+         && general_operand (op[1], VOIDmode)
+         && general_operand (op[0], VOIDmode))
+       {
+         if (XVECLEN (patt, 0) == 2)
+           op[2] = XVECEXP (patt, 0, 1);
+
+         switch (GET_MODE (op[0]))
+           {
+           case QImode:
+             len = 2;
+             break;
+           case HImode:
+             output_reload_inhi (insn, op, &len);
+             break;
+           case SImode:
+           case SFmode:
+             output_reload_insisf (insn, op, &len);
+             break;
+           default:
+             break;
+           }
+       }
+      else if (GET_CODE (op[1]) == ASHIFT
          || GET_CODE (op[1]) == ASHIFTRT
          || GET_CODE (op[1]) == LSHIFTRT)
        {
@@ -2995,13 +4350,7 @@ reg_unused_after (insn, reg)
      rtx insn;
      rtx reg;
 {
-  return (0
-         /* In egcs 1.1.x dead_or_set_p give buggy result after reload 
-#ifdef PRESERVE_DEATH_INFO_REGNO_P
-         || dead_or_set_p (insn,reg)
-#endif
-         */
-         
+  return (dead_or_set_p (insn, reg)
          || (REG_P(reg) && _reg_unused_after (insn, reg)));
 }
 
@@ -3114,7 +4463,7 @@ _reg_unused_after (insn, reg)
 /* Output rtx VALUE as .byte to file FILE */
 
 void
-asm_output_char(file,value)
+asm_output_char (file, value)
      FILE *file;
      rtx value;
 {
@@ -3127,11 +4476,11 @@ asm_output_char(file,value)
 /* Output VALUE as .byte to file FILE */
 
 void
-asm_output_byte (file,value)
+asm_output_byte (file, value)
      FILE *file;
      int value;
 {
-  fprintf (file, "\t.byte 0x%x\n",value & 0xff);
+  fprintf (file, "\t.byte 0x%x\n", value & 0xff);
 }
 
 
@@ -3169,7 +4518,7 @@ asm_output_float (file, n)
   
   REAL_VALUE_TO_TARGET_SINGLE (n, val);
   REAL_VALUE_TO_DECIMAL (n, "%g", dstr);
-  fprintf (file, "\t.long 0x%08lx\t/* %s */\n",val, dstr);
+  fprintf (file, "\t.long 0x%08lx\t/* %s */\n", val, dstr);
 }
 
 /* Sets section name for declaration DECL */
@@ -3180,8 +4529,8 @@ unique_section (decl, reloc)
      int reloc ATTRIBUTE_UNUSED;
 {
   int len;
-  char *name,*string;
-  char *prefix;
+  const char *name, *prefix;
+  char *string;
   name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
   /* Strip off any encoding in name.  */
   STRIP_NAME_ENCODING (name, name);
@@ -3194,7 +4543,7 @@ unique_section (decl, reloc)
        prefix = ".text";
     }
   else 
-    fatal ("Strange situation: unique section is not a FUNCTION_DECL");
+    abort ();
 
   if (flag_function_sections)
     {
@@ -3206,19 +4555,6 @@ unique_section (decl, reloc)
 }
 
 
-/* Output section name to file FILE */
-
-void
-asm_output_section_name(file, decl, name, reloc)
-     FILE *file;
-     tree decl ATTRIBUTE_UNUSED;
-     const char *name;
-     int reloc ATTRIBUTE_UNUSED;
-{
-  fprintf (file, ".section %s\n", name);
-}
-
-
 /* The routine used to output NUL terminated strings.  We use a special
    version of this for most svr4 targets because doing so makes the
    generated assembly code more compact (and thus faster to assemble)
@@ -3228,12 +4564,12 @@ asm_output_section_name(file, decl, name, reloc)
 
 void
 gas_output_limited_string(file, str)
-     FILE * file ATTRIBUTE_UNUSED;
-     char * str;
+     FILE *file;
+     const char * str;
 {
-  unsigned char *_limited_str = (unsigned char *) str;
+  const unsigned char *_limited_str = (unsigned char *) str;
   unsigned ch;
-  fprintf (file, "\t%s\t\"", STRING_ASM_OP);
+  fprintf (file, "%s\"", STRING_ASM_OP);
   for (; (ch = *_limited_str); _limited_str++)
     {
       int escape;
@@ -3264,15 +4600,15 @@ gas_output_limited_string(file, str)
 void
 gas_output_ascii(file, str, length)
      FILE * file;
-     char * str;
+     const char * str;
      size_t length;
 {
-  unsigned char *_ascii_bytes = (unsigned char *) str;
-  unsigned char *limit = _ascii_bytes + length;
+  const unsigned char *_ascii_bytes = (const unsigned char *) str;
+  const unsigned char *limit = _ascii_bytes + length;
   unsigned bytes_in_chunk = 0;
   for (; _ascii_bytes < limit; _ascii_bytes++)
     {
-      register unsigned char *p;
+      const unsigned char *p;
       if (bytes_in_chunk >= 60)
        {
          fprintf (file, "\"\n");
@@ -3287,7 +4623,7 @@ gas_output_ascii(file, str, length)
              fprintf (file, "\"\n");
              bytes_in_chunk = 0;
            }
-         gas_output_limited_string (file, _ascii_bytes);
+         gas_output_limited_string (file, (char*)_ascii_bytes);
          _ascii_bytes = p;
        }
       else
@@ -3323,15 +4659,16 @@ gas_output_ascii(file, str, length)
    because registers of CLASS are needed for spill registers.  */
 
 enum reg_class
-class_likely_spilled_p(int c)
+class_likely_spilled_p (c)
+     int c;
 {
   return (c != ALL_REGS && c != ADDW_REGS);
 }
 
 /* Only `progmem' attribute valid for type.  */
 
-int
-valid_machine_type_attribute(type, attributes, identifier, args)
+static int
+avr_valid_type_attribute (type, attributes, identifier, args)
      tree type ATTRIBUTE_UNUSED;
      tree attributes ATTRIBUTE_UNUSED;
      tree identifier;
@@ -3345,13 +4682,13 @@ valid_machine_type_attribute(type, attributes, identifier, args)
    Valid attributes:
    progmem - put data to program memory;
    signal - make a function to be hardware interrupt. After function
-   epilogue interrupts are disabled;
+   prologue interrupts are disabled;
    interrupt - make a function to be hardware interrupt. After function
-   epilogue interrupts are enabled;
+   prologue interrupts are enabled;
    naked     - don't generate function prologue/epilogue and `ret' command.  */
 
-int
-valid_machine_decl_attribute (decl, attributes, attr, args)
+static int
+avr_valid_decl_attribute (decl, attributes, attr, args)
      tree decl;
      tree attributes ATTRIBUTE_UNUSED;
      tree attr;
@@ -3365,7 +4702,7 @@ valid_machine_decl_attribute (decl, attributes, attr, args)
   if (is_attribute_p ("progmem", attr)
       && (TREE_STATIC (decl) || DECL_EXTERNAL (decl)))
     {
-      if (DECL_INITIAL (decl) == NULL_TREE)
+      if (DECL_INITIAL (decl) == NULL_TREE && !DECL_EXTERNAL (decl))
        {
          warning ("Only initialized variables can be placed into "
                   "program memory area.");
@@ -3378,7 +4715,7 @@ valid_machine_decl_attribute (decl, attributes, attr, args)
 
 
 /* Look for attribute `progmem' in DECL
-   founded - 1 otherwise 0 */
+   if found return 1, otherwise 0.  */
 
 int
 avr_progmem_p (decl)
@@ -3398,6 +4735,9 @@ avr_progmem_p (decl)
     a = TREE_TYPE(a);
   while (TREE_CODE (a) == ARRAY_TYPE);
 
+  if (a == error_mark_node)
+    return 0;
+
   if (NULL_TREE != lookup_attribute ("progmem", TYPE_ATTRIBUTES (a)))
     return 1;
   
@@ -3412,13 +4752,13 @@ encode_section_info (decl)
 {
   if (TREE_CODE (decl) == FUNCTION_DECL)
     SYMBOL_REF_FLAG (XEXP (DECL_RTL (decl), 0)) = 1;
-
-  if ((TREE_STATIC (decl) || DECL_EXTERNAL (decl))
-      && TREE_CODE (decl) == VAR_DECL
-      && avr_progmem_p (decl))
+  else if ((TREE_STATIC (decl) || DECL_EXTERNAL (decl))
+          && TREE_CODE (decl) == VAR_DECL
+          && avr_progmem_p (decl))
     {
-      char * dsec = ".progmem.data";
+      const char *dsec = ".progmem.data";
       DECL_SECTION_NAME (decl) = build_string (strlen (dsec), dsec);
+      TREE_READONLY (decl) = 1;
     }
 }   
 
@@ -3430,20 +4770,11 @@ asm_file_start (file)
      FILE *file;
 {
   output_file_directive (file, main_input_filename);
-  fprintf (file, "\t.arch %s\n", avr_mcu_type->name);
+  fprintf (file, "\t.arch %s\n", avr_mcu_name);
   fputs ("__SREG__ = 0x3f\n"
         "__SP_H__ = 0x3e\n"
         "__SP_L__ = 0x3d\n", file);
   
-  if (avr_ram_end)
-    initial_stack = avr_ram_end;
-  else
-    {
-      static char buf[30];
-      initial_stack = buf;
-      sprintf (buf, "0x%x", avr_mcu_type->stack);
-    }
-  
   fputs ("__tmp_reg__ = 0\n" 
         "__zero_reg__ = 1\n"
         "_PC_ = 2\n", file);
@@ -3477,7 +4808,7 @@ asm_file_end (file)
    next register; and so on.  */
 
 void
-order_regs_for_local_alloc (void)
+order_regs_for_local_alloc ()
 {
   unsigned int i;
   int order_0[] = {
@@ -3521,7 +4852,7 @@ order_regs_for_local_alloc (void)
   int *order = (TARGET_ORDER_1 ? order_1 :
                TARGET_ORDER_2 ? order_2 :
                order_0);
-  for (i=0; i < sizeof (order_0) / sizeof (order_0[0]); ++i)
+  for (i=0; i < ARRAY_SIZE (order_0); ++i)
       reg_alloc_order[i] = order[i];
 }
 
@@ -3590,7 +4921,8 @@ default_rtx_costs (X, code, outer_code)
 /* Calculate the cost of a memory address */
 
 int
-avr_address_cost (rtx x)
+avr_address_cost (x)
+     rtx x;
 {
   if (GET_CODE (x) == PLUS
       && GET_CODE (XEXP (x,1)) == CONST_INT
@@ -3598,14 +4930,18 @@ avr_address_cost (rtx x)
       && INTVAL (XEXP (x,1)) >= 61)
     return 18;
   if (CONSTANT_ADDRESS_P (x))
-    return 4;
+    {
+      if (io_address_p (x, 1))
+       return 2;
+      return 4;
+    }
   return 4;
 }
 
 /*  EXTRA_CONSTRAINT helper */
 
 int
-extra_constraint (x,c)
+extra_constraint (x, c)
      rtx x;
      int c;
 {
@@ -3667,7 +5003,7 @@ avr_normalize_condition (condition)
     case LEU:
       return LTU;
     default:
-      fatal ("Wrong condition: %s", GET_RTX_NAME (condition));
+      abort ();
     }
 }
 
@@ -3678,20 +5014,17 @@ machine_dependent_reorg (first_insn)
      rtx first_insn;
 {
   rtx insn, pattern;
-  CC_STATUS_INIT;
   
   for (insn = first_insn; insn; insn = NEXT_INSN (insn))
     {
-      if (! (insn == 0 || GET_CODE (insn) == INSN
-            || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
+      if (! (GET_CODE (insn) == INSN
+            || GET_CODE (insn) == CALL_INSN
+            || GET_CODE (insn) == JUMP_INSN)
          || !single_set (insn))
        continue;
 
       pattern = PATTERN (insn);
 
-      cc_prev_status = cc_status;
-      NOTICE_UPDATE_CC (pattern, insn);
-      
       if (GET_CODE (pattern) == PARALLEL)
        pattern = XVECEXP (pattern, 0, 0);
       if (GET_CODE (pattern) == SET
@@ -3743,16 +5076,12 @@ machine_dependent_reorg (first_insn)
              rtx src = SET_SRC (pat);
              rtx t = XEXP (src,0);
 
-             if (!(cc_prev_status.value1 != 0 && cc_status.value1 != 0
-                    && rtx_equal_p (cc_status.value1, cc_prev_status.value1)))
-                 {
-                   PUT_CODE (t, swap_condition (GET_CODE (t)));
-                   SET_SRC (pattern) = gen_rtx (NEG,
-                                                GET_MODE (SET_SRC (pattern)),
-                                                SET_SRC (pattern));
-                   INSN_CODE (next) = -1;
-                   INSN_CODE (insn) = -1;
-                 }
+             PUT_CODE (t, swap_condition (GET_CODE (t)));
+             SET_SRC (pattern) = gen_rtx (NEG,
+                                          GET_MODE (SET_SRC (pattern)),
+                                          SET_SRC (pattern));
+             INSN_CODE (next) = -1;
+             INSN_CODE (insn) = -1;
            }
        }
     }
@@ -3761,7 +5090,7 @@ machine_dependent_reorg (first_insn)
 /* Returns register number for function return value.*/
 
 int
-avr_ret_register (void)
+avr_ret_register ()
 {
   return 24;
 }
@@ -3783,11 +5112,12 @@ avr_libcall_value (mode)
    function returns a value of data type VALTYPE.  */
 
 rtx
-avr_function_value (type,func)
+avr_function_value (type, func)
      tree type;
      tree func ATTRIBUTE_UNUSED;
 {
   unsigned int offs;
+  
   if (TYPE_MODE (type) != BLKmode)
     return avr_libcall_value (TYPE_MODE (type));
   
@@ -3802,7 +5132,7 @@ avr_function_value (type,func)
   return gen_rtx (REG, BLKmode, RET_REGISTER + 2 - offs);
 }
 
-/* Returns non-zero if number MASK have only one setted bit */
+/* Returns non-zero if the number MASK has only one bit set.  */
 
 int
 mask_one_bit_p (mask)
@@ -3830,23 +5160,15 @@ mask_one_bit_p (mask)
    in class CLASS.  */
 
 enum reg_class
-preferred_reload_class(x,class)
-     rtx x;
+preferred_reload_class (x, class)
+     rtx x ATTRIBUTE_UNUSED;
      enum reg_class class;
 {
-  if (GET_CODE (x) == CONST_INT && INTVAL (x) == 0)
-    return class;
-  if (CONSTANT_P (x) && (class == NO_LD_REGS
-                        || class == ALL_REGS
-                        || class == GENERAL_REGS))
-    {
-      return LD_REGS;
-    }
   return class;
 }
 
 int
-test_hard_reg_class(class, x)
+test_hard_reg_class (class, x)
      enum reg_class class;
      rtx x;
 {
@@ -3857,7 +5179,8 @@ test_hard_reg_class(class, x)
 }
 
 void
-debug_hard_reg_set (HARD_REG_SET set)
+debug_hard_reg_set (set)
+     HARD_REG_SET set;
 {
   int i;
   for (i=0; i < FIRST_PSEUDO_REGISTER; ++i)
@@ -3878,7 +5201,215 @@ jump_over_one_insn_p (insn, dest)
   int uid = INSN_UID (GET_CODE (dest) == LABEL_REF
                      ? XEXP (dest, 0)
                      : dest);
-  int jump_addr = insn_addresses[INSN_UID (insn)];
-  int dest_addr = insn_addresses[uid];
+  int jump_addr = INSN_ADDRESSES (INSN_UID (insn));
+  int dest_addr = INSN_ADDRESSES (uid);
   return dest_addr - jump_addr == 2;
 }
+
+/* Returns 1 if a value of mode MODE can be stored starting with hard
+   register number REGNO.  On the enhanced core, anything larger than
+   1 byte must start in even numbered register for "movw" to work
+   (this way we don't have to check for odd registers everywhere).  */
+
+int
+avr_hard_regno_mode_ok (regno, mode)
+     int regno;
+     enum machine_mode mode;
+{
+  if (mode == QImode)
+    return 1;
+  /*  if (regno < 24 && !AVR_ENHANCED)
+      return 1;*/
+  return !(regno & 1);
+}
+
+/* Returns 1 if we know register operand OP was 0 before INSN.  */
+
+static int
+reg_was_0 (insn, op)
+     rtx insn;
+     rtx op;
+{
+  rtx link;
+  return (optimize > 0 && insn && op && REG_P (op)
+         && (link = find_reg_note (insn, REG_WAS_0, 0))
+         /* Make sure the insn that stored the 0 is still present.  */
+         && ! INSN_DELETED_P (XEXP (link, 0))
+         && GET_CODE (XEXP (link, 0)) != NOTE
+         /* Make sure cross jumping didn't happen here.  */
+         && no_labels_between_p (XEXP (link, 0), insn)
+         /* Make sure the reg hasn't been clobbered.  */
+         && ! reg_set_between_p (op, XEXP (link, 0), insn));
+}
+
+/* Returns 1 if X is a valid address for an I/O register of size SIZE
+   (1 or 2).  Used for lds/sts -> in/out optimization.  */
+
+static int
+io_address_p (x, size)
+     rtx x;
+     int size;
+{
+  return (optimize > 0 && GET_CODE (x) == CONST_INT
+         && INTVAL (x) >= 0x20 && INTVAL (x) <= 0x60 - size);
+}
+
+/* Returns nonzero (bit number + 1) if X, or -X, is a constant power of 2.  */
+
+int
+const_int_pow2_p (x)
+     rtx x;
+{
+  if (GET_CODE (x) == CONST_INT)
+    {
+      HOST_WIDE_INT d = INTVAL (x);
+      HOST_WIDE_INT abs_d = (d >= 0) ? d : -d;
+      return exact_log2 (abs_d) + 1;
+    }
+  return 0;
+}
+
+const char *
+output_reload_inhi (insn, operands, len)
+     rtx insn ATTRIBUTE_UNUSED;
+     rtx *operands;
+     int *len;
+{
+  int tmp;
+  if (!len)
+    len = &tmp;
+      
+  if (GET_CODE (operands[1]) == CONST_INT)
+    {
+      int val = INTVAL (operands[1]);
+      if ((val & 0xff) == 0)
+       {
+         *len = 3;
+         return (AS2 (mov,%A0,__zero_reg__) CR_TAB
+                 AS2 (ldi,%2,hi8(%1))       CR_TAB
+                 AS2 (mov,%B0,%2));
+       }
+      else if ((val & 0xff00) == 0)
+       {
+         *len = 3;
+         return (AS2 (ldi,%2,lo8(%1)) CR_TAB
+                 AS2 (mov,%A0,%2)     CR_TAB
+                 AS2 (mov,%B0,__zero_reg__));
+       }
+      else if ((val & 0xff) == ((val & 0xff00) >> 8))
+       {
+         *len = 3;
+         return (AS2 (ldi,%2,lo8(%1)) CR_TAB
+                 AS2 (mov,%A0,%2)     CR_TAB
+                 AS2 (mov,%B0,%2));
+       }
+    }
+  *len = 4;
+  return (AS2 (ldi,%2,lo8(%1)) CR_TAB
+         AS2 (mov,%A0,%2)     CR_TAB
+         AS2 (ldi,%2,hi8(%1)) CR_TAB
+         AS2 (mov,%B0,%2));
+}
+
+
+const char *
+output_reload_insisf (insn, operands, len)
+     rtx insn ATTRIBUTE_UNUSED;
+     rtx *operands;
+     int *len;
+{
+  rtx src = operands[1];
+  int cnst = (GET_CODE (src) == CONST_INT);
+
+  if (len)
+    {
+      if (cnst)
+       *len = 4 + ((INTVAL (src) & 0xff) != 0)
+               + ((INTVAL (src) & 0xff00) != 0)
+               + ((INTVAL (src) & 0xff0000) != 0)
+               + ((INTVAL (src) & 0xff000000U) != 0);
+      else
+       *len = 8;
+
+      return "";
+    }
+
+  if (cnst && ((INTVAL (src) & 0xff) == 0))
+    output_asm_insn (AS2 (mov, %A0, __zero_reg__), operands);
+  else
+    {
+      output_asm_insn (AS2 (ldi, %2, lo8(%1)), operands);
+      output_asm_insn (AS2 (mov, %A0, %2), operands);
+    }
+  if (cnst && ((INTVAL (src) & 0xff00) == 0))
+    output_asm_insn (AS2 (mov, %B0, __zero_reg__), operands);
+  else
+    {
+      output_asm_insn (AS2 (ldi, %2, hi8(%1)), operands);
+      output_asm_insn (AS2 (mov, %B0, %2), operands);
+    }
+  if (cnst && ((INTVAL (src) & 0xff0000) == 0))
+    output_asm_insn (AS2 (mov, %C0, __zero_reg__), operands);
+  else
+    {
+      output_asm_insn (AS2 (ldi, %2, hlo8(%1)), operands);
+      output_asm_insn (AS2 (mov, %C0, %2), operands);
+    }
+  if (cnst && ((INTVAL (src) & 0xff000000U) == 0))
+    output_asm_insn (AS2 (mov, %D0, __zero_reg__), operands);
+  else
+    {
+      output_asm_insn (AS2 (ldi, %2, hhi8(%1)), operands);
+      output_asm_insn (AS2 (mov, %D0, %2), operands);
+    }
+  return "";
+}
+
+void
+avr_output_bld (operands, bit_nr)
+     rtx operands[];
+     int bit_nr;
+{
+  static char s[] = "bld %A0,0";
+
+  s[5] = 'A' + (bit_nr >> 3);
+  s[8] = '0' + (bit_nr & 7);
+  output_asm_insn (s, operands);
+}
+
+void
+avr_output_addr_vec_elt (stream, value)
+     FILE *stream;
+     int value;
+{
+  if (AVR_MEGA)
+    fprintf (stream, "\t.word pm(.L%d)\n", value);
+  else
+    fprintf (stream, "\trjmp .L%d\n", value);
+
+  jump_tables_size++;
+}
+
+/* Returns 1 if SCRATCH are safe to be allocated as a scratch
+   registers (for a define_peephole2) in the current function.  */
+
+int
+avr_peep2_scratch_safe (scratch)
+     rtx scratch;
+{
+  if ((interrupt_function_p (current_function_decl)
+       || signal_function_p (current_function_decl))
+      && leaf_function_p ())
+    {
+      int first_reg = true_regnum (scratch);
+      int last_reg = first_reg + GET_MODE_SIZE (GET_MODE (scratch)) - 1;
+      int reg;
+
+      for (reg = first_reg; reg <= last_reg; reg++)
+       {
+         if (!regs_ever_live[reg])
+           return 0;
+       }
+    }
+  return 1;
+}