OSDN Git Service

2006-02-24 Anatoly Sokolov <aesok@post.ru>
[pf3gnuchains/gcc-fork.git] / gcc / config / avr / avr.c
index 07540df..436c570 100644 (file)
@@ -1,5 +1,5 @@
 /* Subroutines for insn-output.c for ATMEL AVR micro controllers
-   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004
+   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007
    Free Software Foundation, Inc.
    Contributed by Denis Chertykov (denisc@overta.ru)
 
@@ -17,8 +17,8 @@
    
    You should have received a copy of the GNU General Public License
    along with GCC; see the file COPYING.  If not, write to
-   the Free Software Foundation, 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
+   the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
 
 #include "config.h"
 #include "system.h"
@@ -68,14 +68,14 @@ static void avr_file_start (void);
 static void avr_file_end (void);
 static void avr_output_function_prologue (FILE *, HOST_WIDE_INT);
 static void avr_output_function_epilogue (FILE *, HOST_WIDE_INT);
-static void avr_unique_section (tree, int);
 static void avr_insert_attributes (tree, tree *);
+static void avr_asm_init_sections (void);
 static unsigned int avr_section_type_flags (tree, const char *, int);
 
 static void avr_reorg (void);
 static void avr_asm_out_ctor (rtx, int);
 static void avr_asm_out_dtor (rtx, int);
-static int default_rtx_costs (rtx, enum rtx_code, enum rtx_code);
+static int avr_operand_rtx_cost (rtx, enum machine_mode, enum rtx_code);
 static bool avr_rtx_costs (rtx, int, int, int *);
 static int avr_address_cost (rtx);
 static bool avr_return_in_memory (tree, tree);
@@ -111,39 +111,40 @@ static int epilogue_size;
 /* Size of all jump tables in the current function, in words.  */
 static int jump_tables_size;
 
-/* Initial stack value specified by the `-minit-stack=' option */
-const char *avr_init_stack = "__stack";
-
-/* Default MCU name */
-const char *avr_mcu_name = "avr2";
-
 /* Preprocessor macros to define depending on MCU type.  */
 const char *avr_base_arch_macro;
 const char *avr_extra_arch_macro;
 
+section *progmem_section;
+
 /* 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;
+/* Core have 'MUL*' instructions.  */
+int avr_have_mul_p = 0;
 
 /* Assembler only.  */
 int avr_asm_only_p = 0;
 
+/* Core have 'MOVW' and 'LPM Rx,Z' instructions.  */
+int avr_have_movw_lpmx_p = 0;
+
 struct base_arch_s {
   int asm_only;
-  int enhanced;
+  int have_mul;
   int mega;
+  int have_movw_lpmx;
   const char *const macro;
 };
 
 static const struct base_arch_s avr_arch_types[] = {
-  { 1, 0, 0, NULL },  /* unknown device specified */
-  { 1, 0, 0, "__AVR_ARCH__=1" },
-  { 0, 0, 0, "__AVR_ARCH__=2" },
-  { 0, 0, 1, "__AVR_ARCH__=3" },
-  { 0, 1, 0, "__AVR_ARCH__=4" },
-  { 0, 1, 1, "__AVR_ARCH__=5" }
+  { 1, 0, 0, 0,  NULL },  /* unknown device specified */
+  { 1, 0, 0, 0, "__AVR_ARCH__=1" },
+  { 0, 0, 0, 0, "__AVR_ARCH__=2" },
+  { 0, 0, 1, 0, "__AVR_ARCH__=3" },
+  { 0, 1, 0, 1, "__AVR_ARCH__=4" },
+  { 0, 1, 1, 1, "__AVR_ARCH__=5" },
+  { 0, 0, 0, 1, "__AVR_ARCH__=25"}
 };
 
 struct mcu_type_s {
@@ -176,7 +177,20 @@ static const struct mcu_type_s avr_mcu_types[] = {
   { "at90s8515", 2, "__AVR_AT90S8515__" },
   { "at90c8534", 2, "__AVR_AT90C8534__" },
   { "at90s8535", 2, "__AVR_AT90S8535__" },
-  { "at86rf401", 2, "__AVR_AT86RF401__" },
+    /* Classic + MOVW, <= 8K.  */
+  { "avr25",      6, NULL },
+  { "attiny13",   6, "__AVR_ATtiny13__" },
+  { "attiny2313", 6, "__AVR_ATtiny2313__" },
+  { "attiny24",   6, "__AVR_ATtiny24__" },
+  { "attiny44",   6, "__AVR_ATtiny44__" },
+  { "attiny84",   6, "__AVR_ATtiny84__" },
+  { "attiny25",   6, "__AVR_ATtiny25__" },
+  { "attiny45",   6, "__AVR_ATtiny45__" },
+  { "attiny85",   6, "__AVR_ATtiny85__" },
+  { "attiny261",  6, "__AVR_ATtiny261__" },
+  { "attiny461",  6, "__AVR_ATtiny461__" },
+  { "attiny861",  6, "__AVR_ATtiny861__" },
+  { "at86rf401",  6, "__AVR_AT86RF401__" },
     /* Classic, > 8K.  */
   { "avr3",      3, NULL },
   { "atmega103", 3, "__AVR_ATmega103__" },
@@ -187,19 +201,57 @@ static const struct mcu_type_s avr_mcu_types[] = {
     /* Enhanced, <= 8K.  */
   { "avr4",      4, NULL },
   { "atmega8",   4, "__AVR_ATmega8__" },
+  { "atmega48",   4, "__AVR_ATmega48__" },
+  { "atmega88",   4, "__AVR_ATmega88__" },
   { "atmega8515", 4, "__AVR_ATmega8515__" },
   { "atmega8535", 4, "__AVR_ATmega8535__" },
+  { "at90pwm1",  4, "__AVR_AT90PWM1__" },
+  { "at90pwm2",  4, "__AVR_AT90PWM2__" },
+  { "at90pwm3",  4, "__AVR_AT90PWM3__" },
+  { "at90usb82",   5, "__AVR_AT90USB82__" },
     /* Enhanced, > 8K.  */
   { "avr5",      5, NULL },
   { "atmega16",  5, "__AVR_ATmega16__" },
   { "atmega161", 5, "__AVR_ATmega161__" },
   { "atmega162", 5, "__AVR_ATmega162__" },
   { "atmega163", 5, "__AVR_ATmega163__" },
+  { "atmega164p",5, "__AVR_ATmega164P__" },
+  { "atmega165", 5, "__AVR_ATmega165__" },
+  { "atmega165p",5, "__AVR_ATmega165P__" },
+  { "atmega168", 5, "__AVR_ATmega168__" },
   { "atmega169", 5, "__AVR_ATmega169__" },
+  { "atmega169p",5, "__AVR_ATmega169P__" },
   { "atmega32",  5, "__AVR_ATmega32__" },
   { "atmega323", 5, "__AVR_ATmega323__" },
+  { "atmega324p",5, "__AVR_ATmega324P__" },
+  { "atmega325", 5, "__AVR_ATmega325__" },
+  { "atmega325p",  5, "__AVR_ATmega325P__" },
+  { "atmega3250", 5, "__AVR_ATmega3250__" },
+  { "atmega3250p", 5, "__AVR_ATmega3250P__" },
+  { "atmega329", 5, "__AVR_ATmega329__" },
+  { "atmega329p",  5, "__AVR_ATmega329P__" },
+  { "atmega3290", 5, "__AVR_ATmega3290__" },
+  { "atmega3290p", 5, "__AVR_ATmega3290P__" },
+  { "atmega406", 5, "__AVR_ATmega406__" },
   { "atmega64",  5, "__AVR_ATmega64__" },
+  { "atmega640", 5, "__AVR_ATmega640__" },
+  { "atmega644", 5, "__AVR_ATmega644__" },
+  { "atmega644p",5, "__AVR_ATmega644P__" },
+  { "atmega645", 5, "__AVR_ATmega645__" },
+  { "atmega6450", 5, "__AVR_ATmega6450__" },
+  { "atmega649", 5, "__AVR_ATmega649__" },
+  { "atmega6490", 5, "__AVR_ATmega6490__" },
   { "atmega128", 5, "__AVR_ATmega128__" },
+  { "atmega1280",5, "__AVR_ATmega1280__" },
+  { "atmega1281",5, "__AVR_ATmega1281__" },
+  { "at90can32", 5, "__AVR_AT90CAN32__" },
+  { "at90can64", 5, "__AVR_AT90CAN64__" },
+  { "at90can128", 5, "__AVR_AT90CAN128__" },
+  { "at90usb162",  5, "__AVR_AT90USB162__" },
+  { "at90usb646", 5, "__AVR_AT90USB646__" },
+  { "at90usb647", 5, "__AVR_AT90USB647__" },
+  { "at90usb1286", 5, "__AVR_AT90USB1286__" },
+  { "at90usb1287", 5, "__AVR_AT90USB1287__" },
   { "at94k",     5, "__AVR_AT94K__" },
     /* Assembler only.  */
   { "avr1",      1, NULL },
@@ -216,6 +268,12 @@ int avr_case_values_threshold = 30000;
 /* Initialize the GCC target structure.  */
 #undef TARGET_ASM_ALIGNED_HI_OP
 #define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
+#undef TARGET_ASM_ALIGNED_SI_OP
+#define TARGET_ASM_ALIGNED_SI_OP "\t.long\t"
+#undef TARGET_ASM_UNALIGNED_HI_OP
+#define TARGET_ASM_UNALIGNED_HI_OP "\t.word\t"
+#undef TARGET_ASM_UNALIGNED_SI_OP
+#define TARGET_ASM_UNALIGNED_SI_OP "\t.long\t"
 #undef TARGET_ASM_INTEGER
 #define TARGET_ASM_INTEGER avr_assemble_integer
 #undef TARGET_ASM_FILE_START
@@ -231,8 +289,8 @@ int avr_case_values_threshold = 30000;
 #define TARGET_ASM_FUNCTION_EPILOGUE avr_output_function_epilogue
 #undef TARGET_ATTRIBUTE_TABLE
 #define TARGET_ATTRIBUTE_TABLE avr_attribute_table
-#undef TARGET_ASM_UNIQUE_SECTION
-#define TARGET_ASM_UNIQUE_SECTION avr_unique_section
+#undef TARGET_ASM_FUNCTION_RODATA_SECTION
+#define TARGET_ASM_FUNCTION_RODATA_SECTION default_no_function_rodata_section
 #undef TARGET_INSERT_ATTRIBUTES
 #define TARGET_INSERT_ATTRIBUTES avr_insert_attributes
 #undef TARGET_SECTION_TYPE_FLAGS
@@ -244,8 +302,6 @@ int avr_case_values_threshold = 30000;
 #undef TARGET_MACHINE_DEPENDENT_REORG
 #define TARGET_MACHINE_DEPENDENT_REORG avr_reorg
 
-#undef TARGET_STRUCT_VALUE_RTX
-#define TARGET_STRUCT_VALUE_RTX hook_rtx_tree_int_null
 #undef TARGET_RETURN_IN_MEMORY
 #define TARGET_RETURN_IN_MEMORY avr_return_in_memory
 
@@ -266,7 +322,7 @@ avr_override_options (void)
 
   if (!t->name)
     {
-      fprintf (stderr, "unknown MCU `%s' specified\nKnown MCU names:\n",
+      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);
@@ -274,8 +330,9 @@ avr_override_options (void)
 
   base = &avr_arch_types[t->arch];
   avr_asm_only_p = base->asm_only;
-  avr_enhanced_p = base->enhanced;
+  avr_have_mul_p = base->have_mul;
   avr_mega_p = base->mega;
+  avr_have_movw_lpmx_p = base->have_movw_lpmx;
   avr_base_arch_macro = base->macro;
   avr_extra_arch_macro = t->macro;
 
@@ -312,35 +369,6 @@ avr_regno_reg_class (int r)
   return ALL_REGS;
 }
 
-
-/* A C expression which defines the machine-dependent operand
-   constraint letters for register classes.  If C is such a
-   letter, the value should be the register class corresponding to
-   it.  Otherwise, the value should be `NO_REGS'.  The register
-   letter `r', corresponding to class `GENERAL_REGS', will not be
-   passed to this macro; you do not need to handle it.  */
-
-enum reg_class
-avr_reg_class_from_letter  (int c)
-{
-  switch (c)
-    {
-    case 't' : return R0_REG;
-    case 'b' : return BASE_POINTER_REGS;
-    case 'e' : return POINTER_REGS;
-    case 'w' : return ADDW_REGS;
-    case 'd' : return LD_REGS;
-    case 'l' : return NO_LD_REGS;
-    case 'a' : return SIMPLE_LD_REGS;
-    case 'x' : return POINTER_X_REGS;
-    case 'y' : return POINTER_Y_REGS;
-    case 'z' : return POINTER_Z_REGS;
-    case 'q' : return STACK_REG;
-    default: break;
-    }
-  return NO_REGS;
-}
-
 /* Return nonzero if FUNC is a naked function.  */
 
 static int
@@ -348,8 +376,7 @@ avr_naked_function_p (tree func)
 {
   tree a;
 
-  if (TREE_CODE (func) != FUNCTION_DECL)
-    abort ();
+  gcc_assert (TREE_CODE (func) == FUNCTION_DECL);
   
   a = lookup_attribute ("naked", DECL_ATTRIBUTES (func));
   return a != NULL_TREE;
@@ -520,7 +547,7 @@ out_adj_frame_ptr (FILE *file, int adj)
       if (TARGET_TINY_STACK)
        {
          if (adj < -63 || adj > 63)
-           warning ("large frame pointer change (%d) with -mtiny-stack", adj);
+           warning (0, "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).  */
@@ -672,14 +699,12 @@ avr_output_function_prologue (FILE *file, HOST_WIDE_INT size)
     }
   else if (minimize && (frame_pointer_needed || live_seq > 6)) 
     {
-      const char *cfun_name = current_function_name ();
       fprintf (file, ("\t"
                      AS1 (ldi, r26) ",lo8(" HOST_WIDE_INT_PRINT_DEC ")" CR_TAB
                      AS1 (ldi, r27) ",hi8(" HOST_WIDE_INT_PRINT_DEC ")" 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),
-              cfun_name, cfun_name);
+      fputs ((AS2 (ldi,r30,pm_lo8(1f)) CR_TAB
+             AS2 (ldi,r31,pm_hi8(1f)) CR_TAB), file);
       
       prologue_size += 4;
       
@@ -695,7 +720,7 @@ avr_output_function_prologue (FILE *file, HOST_WIDE_INT size)
                   (18 - live_seq) * 2);
          ++prologue_size;
        }
-      fprintf (file, ".L_%s_body:\n", cfun_name);
+      fputs ("1:\n", file);
     }
   else
     {
@@ -950,7 +975,7 @@ legitimate_address_p (enum machine_mode mode, rtx x, int strict)
     }
   if (TARGET_ALL_DEBUG)
     {
-      fprintf (stderr, "   ret = %c\n", r);
+      fprintf (stderr, "   ret = %c\n", r + '0');
     }
   return r == NO_REGS ? 0 : (int)r;
 }
@@ -1000,7 +1025,7 @@ ptrreg_to_str (int regno)
     case REG_Y: return "Y";
     case REG_Z: return "Z";
     default:
-      abort ();
+      gcc_unreachable ();
     }
   return NULL;
 }
@@ -1032,7 +1057,7 @@ cond_string (enum rtx_code code)
     case LTU:
       return "lo";
     default:
-      abort ();
+      gcc_unreachable ();
     }
 }
 
@@ -1111,6 +1136,16 @@ print_operand (FILE *file, rtx x, int code)
 
          print_operand (file, XEXP (addr, 1), 0);
        }
+      else if (code == 'p' || code == 'r')
+        {
+          if (GET_CODE (addr) != POST_INC && GET_CODE (addr) != PRE_DEC)
+            fatal_insn ("bad address, not post_inc or pre_dec:", addr);
+          
+          if (code == 'p')
+            print_operand_address (file, XEXP (addr, 0));  /* X, Y, Z */
+          else
+            print_operand (file, XEXP (addr, 0), 0);  /* r26, r28, r30 */
+        }
       else if (GET_CODE (addr) == PLUS)
        {
          print_operand_address (file, XEXP (addr,0));
@@ -1141,22 +1176,6 @@ print_operand (FILE *file, rtx x, int code)
     print_operand_address (file, x);
 }
 
-/* Recognize operand OP of mode MODE used in call instructions.  */
-
-int
-call_insn_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  if (GET_CODE (op) == MEM)
-    {
-      rtx inside = XEXP (op, 0);
-      if (register_operand (inside, Pmode))
-        return 1;
-      if (CONSTANT_ADDRESS_P (inside))
-        return 1;
-    }
-  return 0;
-}
-
 /* Update the condition code in the INSN.  */
 
 void
@@ -1220,6 +1239,7 @@ notice_update_cc (rtx body ATTRIBUTE_UNUSED, rtx insn)
              rtx x = XEXP (src, 1);
 
              if (GET_CODE (x) == CONST_INT
+                 && INTVAL (x) > 0
                  && INTVAL (x) != 6)
                {
                  cc_status.value1 = SET_DEST (set);
@@ -1634,18 +1654,11 @@ output_movhi (rtx insn, rtx operands[], int *l)
                      AS2 (in,%B0,__SP_H__));
            }
 
-         if (AVR_ENHANCED)
+         if (AVR_HAVE_MOVW)
            {
              *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
            {
              *l = 2;
@@ -1825,6 +1838,9 @@ out_movhi_r_mr (rtx insn, rtx op[], int *l)
   rtx base = XEXP (src, 0);
   int reg_dest = true_regnum (dest);
   int reg_base = true_regnum (base);
+  /* "volatile" forces reading low byte first, even if less efficient,
+     for correct operation with 16-bit I/O registers.  */
+  int mem_volatile_p = MEM_VOLATILE_P (src);
   int tmp;
 
   if (!l)
@@ -1918,6 +1934,25 @@ out_movhi_r_mr (rtx insn, rtx op[], int *l)
       if (reg_overlap_mentioned_p (dest, XEXP (base, 0)))
        fatal_insn ("incorrect insn:", insn);
 
+      if (mem_volatile_p)
+        {
+          if (REGNO (XEXP (base, 0)) == REG_X)
+            {
+              *l = 4;
+              return (AS2 (sbiw,r26,2)  CR_TAB
+                      AS2 (ld,%A0,X+)   CR_TAB
+                      AS2 (ld,%B0,X)    CR_TAB
+                      AS2 (sbiw,r26,1));
+            }
+          else
+            {
+              *l = 3;
+              return (AS2 (sbiw,%r1,2)   CR_TAB
+                      AS2 (ld,%A0,%p1)  CR_TAB
+                      AS2 (ldd,%B0,%p1+1));
+            }
+        }
+
       *l = 2;
       return (AS2 (ld,%B0,%1) CR_TAB
              AS2 (ld,%A0,%1));
@@ -2281,7 +2316,7 @@ output_movsisf(rtx insn, rtx operands[], int *l)
        {
          if (true_regnum (dest) > true_regnum (src))
            {
-             if (AVR_ENHANCED)
+             if (AVR_HAVE_MOVW)
                {
                  *l = 2;
                  return (AS2 (movw,%C0,%C1) CR_TAB
@@ -2295,7 +2330,7 @@ output_movsisf(rtx insn, rtx operands[], int *l)
            }
          else
            {
-             if (AVR_ENHANCED)
+             if (AVR_HAVE_MOVW)
                {
                  *l = 2;
                  return (AS2 (movw,%A0,%A1) CR_TAB
@@ -2322,7 +2357,7 @@ output_movsisf(rtx insn, rtx operands[], int *l)
          if (GET_CODE (src) == CONST_INT)
            {
              const char *const clr_op0 =
-               AVR_ENHANCED ? (AS1 (clr,%A0) CR_TAB
+               AVR_HAVE_MOVW ? (AS1 (clr,%A0) CR_TAB
                                AS1 (clr,%B0) CR_TAB
                                AS2 (movw,%C0,%A0))
                             : (AS1 (clr,%A0) CR_TAB
@@ -2332,20 +2367,20 @@ output_movsisf(rtx insn, rtx operands[], int *l)
 
              if (src == const0_rtx) /* mov r,L */
                {
-                 *l = AVR_ENHANCED ? 3 : 4;
+                 *l = AVR_HAVE_MOVW ? 3 : 4;
                  return clr_op0;
                }
              else if (src == const1_rtx)
                {
                  if (!real_l)
                    output_asm_insn (clr_op0, operands);
-                 *l = AVR_ENHANCED ? 4 : 5;
+                 *l = AVR_HAVE_MOVW ? 4 : 5;
                  return AS1 (inc,%A0);
                }
              else if (src == constm1_rtx)
                {
                  /* Immediate constants -1 to any register */
-                 if (AVR_ENHANCED)
+                 if (AVR_HAVE_MOVW)
                    {
                      *l = 4;
                      return (AS1 (clr,%A0)     CR_TAB
@@ -2366,7 +2401,7 @@ output_movsisf(rtx insn, rtx operands[], int *l)
 
                  if (bit_nr >= 0)
                    {
-                     *l = AVR_ENHANCED ? 5 : 6;
+                     *l = AVR_HAVE_MOVW ? 5 : 6;
                      if (!real_l)
                        {
                          output_asm_insn (clr_op0, operands);
@@ -2498,7 +2533,11 @@ out_movhi_mr_r (rtx insn, rtx op[], int *l)
   rtx base = XEXP (dest, 0);
   int reg_base = true_regnum (base);
   int reg_src = true_regnum (src);
+  /* "volatile" forces writing high byte first, even if less efficient,
+     for correct operation with 16-bit I/O registers.  */
+  int mem_volatile_p = MEM_VOLATILE_P (dest);
   int tmp;
+
   if (!l)
     l = &tmp;
   if (CONSTANT_ADDRESS_P (base))
@@ -2518,33 +2557,33 @@ out_movhi_mr_r (rtx insn, rtx op[], int *l)
         {
           if (reg_src == REG_X)
             {
-             /* "st X+,r26" is undefined */
-              if (reg_unused_after (insn, src))
+              /* "st X+,r26" and "st -X,r26" are undefined.  */
+              if (!mem_volatile_p && 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=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));
+                              AS2 (sbiw,r26,1)          CR_TAB
+                              AS2 (st,X,r26));
             }
           else
             {
-              if (reg_unused_after (insn, base))
+              if (!mem_volatile_p && reg_unused_after (insn, base))
                 return *l=2, (AS2 (st,X+,%A1) CR_TAB
                               AS2 (st,X,%B1));
               else
-                return *l=3, (AS2 (st  ,X+,%A1) CR_TAB
-                              AS2 (st  ,X,%B1) CR_TAB
-                              AS2 (sbiw,r26,1));
+                return *l=3, (AS2 (adiw,r26,1) CR_TAB
+                              AS2 (st,X,%B1)   CR_TAB
+                              AS2 (st,-X,%A1));
             }
         }
       else
-        return  *l=2, (AS2 (st ,%0,%A1)    CR_TAB
-                       AS2 (std,%0+1,%B1));
+        return  *l=2, (AS2 (std,%0+1,%B1) CR_TAB
+                       AS2 (st,%0,%A1));
     }
   else if (GET_CODE (base) == PLUS)
     {
@@ -2557,14 +2596,14 @@ out_movhi_mr_r (rtx insn, rtx op[], int *l)
 
          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 (std,Y+62,%A1)    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 (st,Y,%A1)           CR_TAB
                          AS2 (subi,r28,lo8(%o0))  CR_TAB
                          AS2 (sbci,r29,hi8(%o0)));
        }
@@ -2572,31 +2611,53 @@ out_movhi_mr_r (rtx insn, rtx op[], int *l)
        {
          /* (X + d) = R */
          if (reg_src == REG_X)
-           {
+            {
              *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 (adiw,r26,%o0+1)       CR_TAB
                      AS2 (st,X,__zero_reg__)    CR_TAB
+                     AS2 (st,-X,__tmp_reg__)    CR_TAB
                      AS1 (clr,__zero_reg__)     CR_TAB
-                     AS2 (sbiw,r26,%o0+1));
+                      AS2 (sbiw,r26,%o0));
            }
          *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 (AS2 (adiw,r26,%o0+1) CR_TAB
+                  AS2 (st,X,%B1)       CR_TAB
+                  AS2 (st,-X,%A1)      CR_TAB
+                  AS2 (sbiw,r26,%o0));
        }
-      return *l=2, (AS2 (std,%A0,%A1)    CR_TAB
-                   AS2 (std,%B0,%B1));
+      return *l=2, (AS2 (std,%B0,%B1)    CR_TAB
+                    AS2 (std,%A0,%A1));
     }
   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 (base) == POST_INC) /* (R++) */
-    return *l=2, (AS2 (st,%0,%A1)  CR_TAB
-                 AS2 (st,%0,%B1));
+    {
+      if (mem_volatile_p)
+        {
+          if (REGNO (XEXP (base, 0)) == REG_X)
+            {
+              *l = 4;
+              return (AS2 (adiw,r26,1)  CR_TAB
+                      AS2 (st,X,%B1)    CR_TAB
+                      AS2 (st,-X,%A1)   CR_TAB
+                      AS2 (adiw,r26,2));
+            }
+          else
+            {
+              *l = 3;
+              return (AS2 (std,%p0+1,%B1) CR_TAB
+                      AS2 (st,%p0,%A1)    CR_TAB
+                      AS2 (adiw,%r0,2));
+            }
+        }
+
+      *l = 2;
+      return (AS2 (st,%0,%A1)  CR_TAB
+            AS2 (st,%0,%B1));
+    }
   fatal_insn ("unknown move insn:",insn);
   return "";
 }
@@ -2740,6 +2801,13 @@ out_shift_with_cnt (const char *template, rtx insn, rtx operands[],
       int count = INTVAL (operands[2]);
       int max_len = 10;  /* If larger than this, always use a loop.  */
 
+      if (count <= 0)
+       {
+         if (len)
+           *len = 0;
+         return;
+       }
+
       if (count < 8 && !scratch)
        use_zero_reg = 1;
 
@@ -2862,6 +2930,9 @@ ashlqi3_out (rtx insn, rtx operands[], int *len)
       switch (INTVAL (operands[2]))
        {
        default:
+         if (INTVAL (operands[2]) < 8)
+           break;
+
          *len = 1;
          return AS1 (clr,%0);
          
@@ -2958,6 +3029,14 @@ ashlhi3_out (rtx insn, rtx operands[], int *len)
       
       switch (INTVAL (operands[2]))
        {
+       default:
+         if (INTVAL (operands[2]) < 16)
+           break;
+
+         *len = 2;
+         return (AS1 (clr,%B0) CR_TAB
+                 AS1 (clr,%A0));
+
        case 4:
          if (optimize_size && scratch)
            break;  /* 5 */
@@ -3037,11 +3116,8 @@ ashlhi3_out (rtx insn, rtx operands[], int *len)
                  AS1 (ror,%A0));
 
        case 8:
-         if (true_regnum (operands[0]) + 1 == true_regnum (operands[1]))
-           return *len = 1, AS1 (clr,%A0);
-         else
-           return *len = 2, (AS2 (mov,%B0,%A1) CR_TAB
-                             AS1 (clr,%A0));
+         return *len = 2, (AS2 (mov,%B0,%A1) CR_TAB
+                           AS1 (clr,%A0));
 
        case 9:
          *len = 3;
@@ -3100,7 +3176,7 @@ ashlhi3_out (rtx insn, rtx operands[], int *len)
                      AS1 (lsl,%B0)     CR_TAB
                      AS2 (andi,%B0,0xe0));
            }
-         if (AVR_ENHANCED && scratch)
+         if (AVR_HAVE_MUL && scratch)
            {
              *len = 5;
              return (AS2 (ldi,%3,0x20) CR_TAB
@@ -3121,7 +3197,7 @@ ashlhi3_out (rtx insn, rtx operands[], int *len)
                      AS2 (ldi,%3,0xe0) CR_TAB
                      AS2 (and,%B0,%3));
            }
-         if (AVR_ENHANCED)
+         if (AVR_HAVE_MUL)
            {
              *len = 6;
              return ("set"            CR_TAB
@@ -3141,7 +3217,7 @@ ashlhi3_out (rtx insn, rtx operands[], int *len)
                  AS1 (lsl,%B0));
 
        case 14:
-         if (AVR_ENHANCED && ldi_ok)
+         if (AVR_HAVE_MUL && ldi_ok)
            {
              *len = 5;
              return (AS2 (ldi,%B0,0x40) CR_TAB
@@ -3150,7 +3226,7 @@ ashlhi3_out (rtx insn, rtx operands[], int *len)
                      AS1 (clr,%A0)      CR_TAB
                      AS1 (clr,__zero_reg__));
            }
-         if (AVR_ENHANCED && scratch)
+         if (AVR_HAVE_MUL && scratch)
            {
              *len = 5;
              return (AS2 (ldi,%3,0x40) CR_TAB
@@ -3209,6 +3285,20 @@ ashlsi3_out (rtx insn, rtx operands[], int *len)
       
       switch (INTVAL (operands[2]))
        {
+       default:
+         if (INTVAL (operands[2]) < 32)
+           break;
+
+         if (AVR_HAVE_MOVW)
+           return *len = 3, (AS1 (clr,%D0) CR_TAB
+                             AS1 (clr,%C0) CR_TAB
+                             AS2 (movw,%A0,%C0));
+         *len = 4;
+         return (AS1 (clr,%D0) CR_TAB
+                 AS1 (clr,%C0) CR_TAB
+                 AS1 (clr,%B0) CR_TAB
+                 AS1 (clr,%A0));
+
        case 8:
          {
            int reg0 = true_regnum (operands[0]);
@@ -3219,11 +3309,6 @@ ashlsi3_out (rtx insn, rtx operands[], int *len)
                      AS2 (mov,%C0,%B1)  CR_TAB
                      AS2 (mov,%B0,%A1)  CR_TAB
                      AS1 (clr,%A0));
-           else if (reg0 + 1 == reg1)
-             {
-               *len = 1;
-               return AS1 (clr,%A0);
-             }
            else
              return (AS1 (clr,%A0)      CR_TAB
                      AS2 (mov,%B0,%A1)  CR_TAB
@@ -3235,46 +3320,26 @@ ashlsi3_out (rtx insn, rtx operands[], int *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
-                     AS1 (clr,%B0)      CR_TAB
-                     AS1 (clr,%A0));
            if (reg0 + 2 == reg1)
-             {
-               *len = 2;
-               return (AS1 (clr,%B0)      CR_TAB
-                       AS1 (clr,%A0));
-             }
+             return *len = 2, (AS1 (clr,%B0)      CR_TAB
+                               AS1 (clr,%A0));
+           if (AVR_HAVE_MOVW)
+             return *len = 3, (AS2 (movw,%C0,%A1) CR_TAB
+                               AS1 (clr,%B0)      CR_TAB
+                               AS1 (clr,%A0));
            else
-             return (AS2 (mov,%C0,%A1)  CR_TAB
-                     AS2 (mov,%D0,%B1)  CR_TAB
-                     AS1 (clr,%B0)      CR_TAB
-                     AS1 (clr,%A0));
+             return *len = 4, (AS2 (mov,%C0,%A1)  CR_TAB
+                               AS2 (mov,%D0,%B1)  CR_TAB
+                               AS1 (clr,%B0)      CR_TAB
+                               AS1 (clr,%A0));
          }
 
        case 24:
          *len = 4;
-         if (true_regnum (operands[0]) + 3 != true_regnum (operands[1]))
-           return (AS2 (mov,%D0,%A1)  CR_TAB
-                   AS1 (clr,%C0)      CR_TAB
-                   AS1 (clr,%B0)      CR_TAB
-                   AS1 (clr,%A0));
-         else
-           {
-             *len = 3;
-             return (AS1 (clr,%C0)      CR_TAB
-                     AS1 (clr,%B0)      CR_TAB
-                     AS1 (clr,%A0));
-           }
+         return (AS2 (mov,%D0,%A1)  CR_TAB
+                 AS1 (clr,%C0)      CR_TAB
+                 AS1 (clr,%B0)      CR_TAB
+                 AS1 (clr,%A0));
 
        case 31:
          *len = 6;
@@ -3347,6 +3412,11 @@ ashrqi3_out (rtx insn, rtx operands[], int *len)
                  AS2 (bld,%0,0));
 
        default:
+         if (INTVAL (operands[2]) < 8)
+           break;
+
+         /* fall through */
+
        case 7:
          *len = 2;
          return (AS1 (lsl,%0) CR_TAB
@@ -3413,15 +3483,11 @@ ashrhi3_out (rtx insn, rtx operands[], int *len)
              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 = 4, (AS2 (mov,%A0,%B1) CR_TAB
+                               AS1 (clr,%B0)     CR_TAB
+                               AS2 (sbrc,%A0,7)  CR_TAB
+                               AS1 (dec,%B0));
          }
 
        case 9:
@@ -3440,7 +3506,7 @@ ashrhi3_out (rtx insn, rtx operands[], int *len)
                  AS1 (asr,%A0));
 
        case 11:
-         if (AVR_ENHANCED && ldi_ok)
+         if (AVR_HAVE_MUL && ldi_ok)
            {
              *len = 5;
              return (AS2 (ldi,%A0,0x20) CR_TAB
@@ -3460,7 +3526,7 @@ ashrhi3_out (rtx insn, rtx operands[], int *len)
                  AS1 (asr,%A0));
 
        case 12:
-         if (AVR_ENHANCED && ldi_ok)
+         if (AVR_HAVE_MUL && ldi_ok)
            {
              *len = 5;
              return (AS2 (ldi,%A0,0x10) CR_TAB
@@ -3481,7 +3547,7 @@ ashrhi3_out (rtx insn, rtx operands[], int *len)
                  AS1 (asr,%A0));
 
        case 13:
-         if (AVR_ENHANCED && ldi_ok)
+         if (AVR_HAVE_MUL && ldi_ok)
            {
              *len = 5;
              return (AS2 (ldi,%A0,0x08) CR_TAB
@@ -3510,6 +3576,12 @@ ashrhi3_out (rtx insn, rtx operands[], int *len)
                  AS2 (mov,%B0,%A0) CR_TAB
                  AS1 (rol,%A0));
 
+       default:
+         if (INTVAL (operands[2]) < 16)
+           break;
+
+         /* fall through */
+
        case 15:
          return *len = 3, (AS1 (lsl,%B0)     CR_TAB
                            AS2 (sbc,%A0,%A0) CR_TAB
@@ -3551,13 +3623,6 @@ ashrsi3_out (rtx insn, rtx operands[], int *len)
                      AS1 (clr,%D0)     CR_TAB
                      AS2 (sbrc,%C0,7)  CR_TAB
                      AS1 (dec,%D0));
-           else if (reg0 == reg1 + 1)
-             {
-               *len = 3;
-               return (AS1 (clr,%D0)     CR_TAB
-                       AS2 (sbrc,%C0,7)  CR_TAB
-                       AS1 (dec,%D0));
-             }
            else
              return (AS1 (clr,%D0)     CR_TAB
                      AS2 (sbrc,%D1,7)  CR_TAB
@@ -3571,54 +3636,43 @@ ashrsi3_out (rtx insn, rtx operands[], int *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
-                     AS1 (clr,%D0)     CR_TAB
-                     AS2 (sbrc,%B0,7)  CR_TAB
-                     AS1 (com,%D0)     CR_TAB
-                     AS2 (mov,%C0,%D0));
-           else if (reg0 == reg1 + 2)
+           
+           if (reg0 == reg1 + 2)
              return *len = 4, (AS1 (clr,%D0)     CR_TAB
                                AS2 (sbrc,%B0,7)  CR_TAB
                                AS1 (com,%D0)     CR_TAB
                                AS2 (mov,%C0,%D0));
-           else
-             return (AS2 (mov,%B0,%D1) CR_TAB
-                     AS2 (mov,%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 (AVR_HAVE_MOVW)
+             return *len = 5, (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));
+           else 
+             return *len = 6, (AS2 (mov,%B0,%D1) CR_TAB
+                               AS2 (mov,%A0,%C1) CR_TAB
+                               AS1 (clr,%D0)     CR_TAB
+                               AS2 (sbrc,%B0,7)  CR_TAB
+                               AS1 (com,%D0)     CR_TAB
+                               AS2 (mov,%C0,%D0));
          }
 
        case 24:
-         if (true_regnum (operands[0]) != true_regnum (operands[1]) + 3)
-           return *len = 6, (AS2 (mov,%A0,%D1) CR_TAB
-                             AS1 (clr,%D0)     CR_TAB
-                             AS2 (sbrc,%A0,7)  CR_TAB
-                             AS1 (com,%D0)     CR_TAB
-                             AS2 (mov,%B0,%D0) CR_TAB
-                             AS2 (mov,%C0,%D0));
-         else
-           return *len = 5, (AS1 (clr,%D0)     CR_TAB
-                             AS2 (sbrc,%A0,7)  CR_TAB
-                             AS1 (com,%D0)     CR_TAB
-                             AS2 (mov,%B0,%D0) CR_TAB
-                             AS2 (mov,%C0,%D0));
+         return *len = 6, (AS2 (mov,%A0,%D1) CR_TAB
+                           AS1 (clr,%D0)     CR_TAB
+                           AS2 (sbrc,%A0,7)  CR_TAB
+                           AS1 (com,%D0)     CR_TAB
+                           AS2 (mov,%B0,%D0) CR_TAB
+                           AS2 (mov,%C0,%D0));
+
+       default:
+         if (INTVAL (operands[2]) < 32)
+           break;
+
+         /* fall through */
 
        case 31:
-         if (AVR_ENHANCED)
+         if (AVR_HAVE_MOVW)
            return *len = 4, (AS1 (lsl,%D0)     CR_TAB
                              AS2 (sbc,%A0,%A0) CR_TAB
                              AS2 (mov,%B0,%A0) CR_TAB
@@ -3655,6 +3709,9 @@ lshrqi3_out (rtx insn, rtx operands[], int *len)
       switch (INTVAL (operands[2]))
        {
        default:
+         if (INTVAL (operands[2]) < 8)
+           break;
+
          *len = 1;
          return AS1 (clr,%0);
 
@@ -3749,6 +3806,14 @@ lshrhi3_out (rtx insn, rtx operands[], int *len)
       
       switch (INTVAL (operands[2]))
        {
+       default:
+         if (INTVAL (operands[2]) < 16)
+           break;
+
+         *len = 2;
+         return (AS1 (clr,%B0) CR_TAB
+                 AS1 (clr,%A0));
+
        case 4:
          if (optimize_size && scratch)
            break;  /* 5 */
@@ -3828,11 +3893,8 @@ lshrhi3_out (rtx insn, rtx operands[], int *len)
                  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);
+         return *len = 2, (AS2 (mov,%A0,%B1) CR_TAB
+                           AS1 (clr,%B0));
 
        case 9:
          *len = 3;
@@ -3891,7 +3953,7 @@ lshrhi3_out (rtx insn, rtx operands[], int *len)
                      AS1 (lsr,%A0)     CR_TAB
                      AS2 (andi,%A0,0x07));
            }
-         if (AVR_ENHANCED && scratch)
+         if (AVR_HAVE_MUL && scratch)
            {
              *len = 5;
              return (AS2 (ldi,%3,0x08) CR_TAB
@@ -3912,7 +3974,7 @@ lshrhi3_out (rtx insn, rtx operands[], int *len)
                      AS2 (ldi,%3,0x07) CR_TAB
                      AS2 (and,%A0,%3));
            }
-         if (AVR_ENHANCED)
+         if (AVR_HAVE_MUL)
            {
              *len = 6;
              return ("set"            CR_TAB
@@ -3932,7 +3994,7 @@ lshrhi3_out (rtx insn, rtx operands[], int *len)
                  AS1 (lsr,%A0));
 
        case 14:
-         if (AVR_ENHANCED && ldi_ok)
+         if (AVR_HAVE_MUL && ldi_ok)
            {
              *len = 5;
              return (AS2 (ldi,%A0,0x04) CR_TAB
@@ -3941,7 +4003,7 @@ lshrhi3_out (rtx insn, rtx operands[], int *len)
                      AS1 (clr,%B0)      CR_TAB
                      AS1 (clr,__zero_reg__));
            }
-         if (AVR_ENHANCED && scratch)
+         if (AVR_HAVE_MUL && scratch)
            {
              *len = 5;
              return (AS2 (ldi,%3,0x04) CR_TAB
@@ -3999,6 +4061,20 @@ lshrsi3_out (rtx insn, rtx operands[], int *len)
       
       switch (INTVAL (operands[2]))
        {
+       default:
+         if (INTVAL (operands[2]) < 32)
+           break;
+
+         if (AVR_HAVE_MOVW)
+           return *len = 3, (AS1 (clr,%D0) CR_TAB
+                             AS1 (clr,%C0) CR_TAB
+                             AS2 (movw,%A0,%C0));
+         *len = 4;
+         return (AS1 (clr,%D0) CR_TAB
+                 AS1 (clr,%C0) CR_TAB
+                 AS1 (clr,%B0) CR_TAB
+                 AS1 (clr,%A0));
+
        case 8:
          {
            int reg0 = true_regnum (operands[0]);
@@ -4009,8 +4085,6 @@ lshrsi3_out (rtx insn, rtx operands[], int *len)
                      AS2 (mov,%B0,%C1) CR_TAB
                      AS2 (mov,%C0,%D1) CR_TAB
                      AS1 (clr,%D0));
-           else if (reg0 == reg1 + 1)
-             return *len = 1, AS1 (clr,%D0);
            else
              return (AS1 (clr,%D0)     CR_TAB
                      AS2 (mov,%C0,%D1) CR_TAB
@@ -4022,39 +4096,26 @@ lshrsi3_out (rtx insn, rtx operands[], int *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
-                     AS1 (clr,%C0)     CR_TAB
-                     AS1 (clr,%D0));
-           else if (reg0 == reg1 + 2)
+
+           if (reg0 == reg1 + 2)
              return *len = 2, (AS1 (clr,%C0)     CR_TAB
                                AS1 (clr,%D0));
+           if (AVR_HAVE_MOVW)
+             return *len = 3, (AS2 (movw,%A0,%C1) CR_TAB
+                               AS1 (clr,%C0)      CR_TAB
+                               AS1 (clr,%D0));
            else
-             return (AS2 (mov,%B0,%D1) CR_TAB
-                     AS2 (mov,%A0,%C1) CR_TAB
-                     AS1 (clr,%C0)     CR_TAB
-                     AS1 (clr,%D0));
+             return *len = 4, (AS2 (mov,%B0,%D1) CR_TAB
+                               AS2 (mov,%A0,%C1) CR_TAB
+                               AS1 (clr,%C0)     CR_TAB
+                               AS1 (clr,%D0));
          }
          
        case 24:
-         if (true_regnum (operands[0]) != true_regnum (operands[1]) + 3)
-           return *len = 4, (AS2 (mov,%A0,%D1) CR_TAB
-                             AS1 (clr,%B0)     CR_TAB
-                             AS1 (clr,%C0)     CR_TAB
-                             AS1 (clr,%D0));
-         else
-           return *len = 3, (AS1 (clr,%B0)     CR_TAB
-                             AS1 (clr,%C0)     CR_TAB
-                             AS1 (clr,%D0));
+         return *len = 4, (AS2 (mov,%A0,%D1) CR_TAB
+                           AS1 (clr,%B0)     CR_TAB
+                           AS1 (clr,%C0)     CR_TAB
+                           AS1 (clr,%D0));
 
        case 31:
          *len = 6;
@@ -4253,6 +4314,7 @@ _reg_unused_after (rtx insn, rtx reg)
 
   while ((insn = NEXT_INSN (insn)))
     {
+      rtx set;
       code = GET_CODE (insn);
 
 #if 0
@@ -4265,6 +4327,9 @@ _reg_unused_after (rtx insn, rtx reg)
       /* else */
 #endif
 
+      if (!INSN_P (insn))
+       continue;
+
       if (code == JUMP_INSN)
        return 0;
 
@@ -4322,17 +4387,14 @@ _reg_unused_after (rtx insn, rtx reg)
            return 1;
        }
 
-      if (GET_RTX_CLASS (code) == 'i')
-       {
-         rtx set = single_set (insn);
+      set = single_set (insn);
 
-         if (set && reg_overlap_mentioned_p (reg, SET_SRC (set)))
-           return 0;
-         if (set && reg_overlap_mentioned_p (reg, SET_DEST (set)))
-           return GET_CODE (SET_DEST (set)) != MEM;
-         if (set == 0 && reg_overlap_mentioned_p (reg, PATTERN (insn)))
-           return 0;
-       }
+      if (set && reg_overlap_mentioned_p (reg, SET_SRC (set)))
+       return 0;
+      if (set && reg_overlap_mentioned_p (reg, SET_DEST (set)))
+       return GET_CODE (SET_DEST (set)) != MEM;
+      if (set == 0 && reg_overlap_mentioned_p (reg, PATTERN (insn)))
+       return 0;
     }
   return 1;
 }
@@ -4355,38 +4417,6 @@ avr_assemble_integer (rtx x, unsigned int size, int aligned_p)
   return default_assemble_integer (x, size, aligned_p);
 }
 
-/* Sets section name for declaration DECL.  */
-  
-static void
-avr_unique_section (tree decl, int reloc ATTRIBUTE_UNUSED)
-{
-  int len;
-  const char *name, *prefix;
-  char *string;
-
-  name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
-  name = (* targetm.strip_name_encoding) (name);
-
-  if (TREE_CODE (decl) == FUNCTION_DECL)
-    {
-      if (flag_function_sections)
-       prefix = ".text.";
-      else
-       prefix = ".text";
-    }
-  else 
-    abort ();
-
-  if (flag_function_sections)
-    {
-      len = strlen (name) + strlen (prefix);
-      string = alloca (len + 1);
-      sprintf (string, "%s%s", prefix, name);
-      DECL_SECTION_NAME (decl) = build_string (len, string);
-    }
-}
-
-
 /* 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)
@@ -4538,14 +4568,15 @@ avr_handle_progmem_attribute (tree *node, tree name,
        {
          if (DECL_INITIAL (*node) == NULL_TREE && !DECL_EXTERNAL (*node))
            {
-             warning ("only initialized variables can be placed into "
+             warning (0, "only initialized variables can be placed into "
                       "program memory area");
              *no_add_attrs = true;
            }
        }
       else
        {
-         warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+         warning (OPT_Wattributes, "%qs attribute ignored",
+                  IDENTIFIER_POINTER (name));
          *no_add_attrs = true;
        }
     }
@@ -4564,10 +4595,36 @@ avr_handle_fndecl_attribute (tree *node, tree name,
 {
   if (TREE_CODE (*node) != FUNCTION_DECL)
     {
-      warning ("`%s' attribute only applies to functions",
+      warning (OPT_Wattributes, "%qs attribute only applies to functions",
               IDENTIFIER_POINTER (name));
       *no_add_attrs = true;
     }
+  else
+    {
+      const char *func_name = IDENTIFIER_POINTER (DECL_NAME (*node));
+      const char *attr = IDENTIFIER_POINTER (name);
+
+      /* If the function has the 'signal' or 'interrupt' attribute, test to
+         make sure that the name of the function is "__vector_NN" so as to
+         catch when the user misspells the interrupt vector name.  */
+
+      if (strncmp (attr, "interrupt", strlen ("interrupt")) == 0)
+        {
+          if (strncmp (func_name, "__vector", strlen ("__vector")) != 0)
+            {
+              warning (0, "%qs appears to be a misspelled interrupt handler",
+                       func_name);
+            }
+        }
+      else if (strncmp (attr, "signal", strlen ("signal")) == 0)
+        {
+          if (strncmp (func_name, "__vector", strlen ("__vector")) != 0)
+            {
+              warning (0, "%qs appears to be a misspelled signal handler",
+                       func_name);
+            }
+        }
+    }
 
   return NULL_TREE;
 }
@@ -4576,7 +4633,7 @@ avr_handle_fndecl_attribute (tree *node, tree name,
    if found return 1, otherwise 0.  */
 
 int
-avr_progmem_p (tree decl)
+avr_progmem_p (tree decl, tree attributes)
 {
   tree a;
 
@@ -4584,7 +4641,7 @@ avr_progmem_p (tree decl)
     return 0;
 
   if (NULL_TREE
-      != lookup_attribute ("progmem", DECL_ATTRIBUTES (decl)))
+      != lookup_attribute ("progmem", attributes))
     return 1;
 
   a=decl;
@@ -4608,7 +4665,7 @@ avr_insert_attributes (tree node, tree *attributes)
 {
   if (TREE_CODE (node) == VAR_DECL
       && (TREE_STATIC (node) || DECL_EXTERNAL (node))
-      && avr_progmem_p (node))
+      && avr_progmem_p (node, *attributes))
     {
       static const char dsec[] = ".progmem.data";
       *attributes = tree_cons (get_identifier ("section"),
@@ -4621,6 +4678,29 @@ avr_insert_attributes (tree node, tree *attributes)
     }
 }
 
+/* A get_unnamed_section callback for switching to progmem_section.  */
+
+static void
+avr_output_progmem_section_asm_op (const void *arg ATTRIBUTE_UNUSED)
+{
+  fprintf (asm_out_file,
+          "\t.section .progmem.gcc_sw_table, \"%s\", @progbits\n",
+          AVR_MEGA ? "a" : "ax");
+  /* Should already be aligned, this is just to be safe if it isn't.  */
+  fprintf (asm_out_file, "\t.p2align 1\n");
+}
+
+/* Implement TARGET_ASM_INIT_SECTIONS.  */
+
+static void
+avr_asm_init_sections (void)
+{
+  progmem_section = get_unnamed_section (AVR_MEGA ? 0 : SECTION_CODE,
+                                        avr_output_progmem_section_asm_op,
+                                        NULL);
+  readonly_data_section = data_section;
+}
+
 static unsigned int
 avr_section_type_flags (tree decl, const char *name, int reloc)
 {
@@ -4632,7 +4712,7 @@ avr_section_type_flags (tree decl, const char *name, int reloc)
          && DECL_INITIAL (decl) == NULL_TREE)
        flags |= SECTION_BSS;  /* @nobits */
       else
-       warning ("only uninitialized variables can be placed in the "
+       warning (0, "only uninitialized variables can be placed in the "
                 ".noinit section");
     }
 
@@ -4646,11 +4726,11 @@ static void
 avr_file_start (void)
 {
   if (avr_asm_only_p)
-    error ("MCU `%s' supported for assembler only", avr_mcu_name);
+    error ("MCU %qs supported for assembler only", avr_mcu_name);
 
   default_file_start ();
 
-  fprintf (asm_out_file, "\t.arch %s\n", avr_mcu_name);
+/*  fprintf (asm_out_file, "\t.arch %s\n", avr_mcu_name);*/
   fputs ("__SREG__ = 0x3f\n"
         "__SP_H__ = 0x3e\n"
         "__SP_L__ = 0x3d\n", asm_out_file);
@@ -4741,110 +4821,558 @@ order_regs_for_local_alloc (void)
       reg_alloc_order[i] = order[i];
 }
 
-/* Calculate the cost of X code of the expression in which it is contained,
-   found in OUTER_CODE */
+
+/* Mutually recursive subroutine of avr_rtx_cost for calculating the
+   cost of an RTX operand given its context.  X is the rtx of the
+   operand, MODE is its mode, and OUTER is the rtx_code of this
+   operand's parent operator.  */
 
 static int
-default_rtx_costs (rtx X, enum rtx_code code, enum rtx_code outer_code)
+avr_operand_rtx_cost (rtx x, enum machine_mode mode, enum rtx_code outer)
 {
-  int cost=0;
+  enum rtx_code code = GET_CODE (x);
+  int total;
+
   switch (code)
     {
-    case SYMBOL_REF:
-    case LABEL_REF:
-      cost = 2 * GET_MODE_SIZE (GET_MODE (X));
-      break;
-    case MEM:
-      if (outer_code != SET)
-       cost = 1;
-      if (GET_CODE (XEXP (X,0)) == SYMBOL_REF)
-       cost += 2 * GET_MODE_SIZE (GET_MODE (X));
-      else
-       cost += GET_MODE_SIZE (GET_MODE (X));
-      break;
+    case REG:
+    case SUBREG:
+      return 0;
+
     case CONST_INT:
-      cost = 0;
-      break;
-    case SIGN_EXTEND:
-      if (outer_code == SET)
-       cost = GET_MODE_SIZE (GET_MODE (X));
-      else
-       cost = -GET_MODE_SIZE (GET_MODE (X));
-      break;
-    case ZERO_EXTEND:
-      if (outer_code == SET)
-       cost = GET_MODE_SIZE (GET_MODE (X));
-      else
-       cost = -1;
-      break;
-    case PLUS:
-    case MINUS:
-      if (outer_code == SET)
-       {
-         if (X == stack_pointer_rtx)
-           cost = -10;
-         else if (GET_CODE (XEXP (X,1)) == CONST_INT)
-           cost = (INTVAL (XEXP (X,1)) <= 63 ? 1 :
-                    GET_MODE_SIZE (GET_MODE (X)));
-         else
-           cost = GET_MODE_SIZE (GET_MODE (X));
-       }
-      break;
-    case COMPARE:
-      if (GET_CODE (XEXP (X,1)) == CONST_INT)
-       cost = GET_MODE_SIZE (GET_MODE (XEXP (X,0)));
-      break;
+    case CONST_DOUBLE:
+      return COSTS_N_INSNS (GET_MODE_SIZE (mode));
+
     default:
       break;
     }
-  return cost;
+
+  total = 0;
+  avr_rtx_costs (x, code, outer, &total);
+  return total;
 }
 
+/* The AVR backend's rtx_cost function.  X is rtx expression whose cost
+   is to be calculated.  Return true if the complete cost has been
+   computed, and false if subexpressions should be scanned.  In either
+   case, *TOTAL contains the cost result.  */
+
 static bool
-avr_rtx_costs (rtx x, int code, int outer_code, int *total)
+avr_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int *total)
 {
-  int cst;
+  enum machine_mode mode = GET_MODE (x);
+  HOST_WIDE_INT val;
 
   switch (code)
     {
     case CONST_INT:
-      if (outer_code == PLUS
-         || outer_code == IOR
-         || outer_code == AND
-         || outer_code == MINUS
-         || outer_code == SET
-         || INTVAL (x) == 0)
+    case CONST_DOUBLE:
+      /* Immediate constants are as cheap as registers.  */
+      *total = 0;
+      return true;
+
+    case MEM:
+    case CONST:
+    case LABEL_REF:
+    case SYMBOL_REF:
+      *total = COSTS_N_INSNS (GET_MODE_SIZE (mode));
+      return true;
+
+    case NEG:
+      switch (mode)
        {
-          *total = 2;
-         return true;
+       case QImode:
+       case SFmode:
+         *total = COSTS_N_INSNS (1);
+         break;
+
+       case HImode:
+         *total = COSTS_N_INSNS (3);
+         break;
+
+       case SImode:
+         *total = COSTS_N_INSNS (7);
+         break;
+
+       default:
+         return false;
        }
-      if (outer_code == COMPARE
-         && INTVAL (x) >= 0
-         && INTVAL (x) <= 255)
+      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
+      return true;
+
+    case ABS:
+      switch (mode)
        {
-         *total = 2;
-         return true;
+       case QImode:
+       case SFmode:
+         *total = COSTS_N_INSNS (1);
+         break;
+
+       default:
+         return false;
        }
-      /* FALLTHRU */
+      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
+      return true;
 
-    case CONST:
-    case LABEL_REF:
-    case SYMBOL_REF:
-    case CONST_DOUBLE:
-      *total = 4;
+    case NOT:
+      *total = COSTS_N_INSNS (GET_MODE_SIZE (mode));
+      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
       return true;
 
-    default:
-      cst = default_rtx_costs (x, code, outer_code);
-      if (cst > 0)
+    case ZERO_EXTEND:
+      *total = COSTS_N_INSNS (GET_MODE_SIZE (mode)
+                             - GET_MODE_SIZE (GET_MODE (XEXP (x, 0))));
+      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
+      return true;
+
+    case SIGN_EXTEND:
+      *total = COSTS_N_INSNS (GET_MODE_SIZE (mode) + 2
+                             - GET_MODE_SIZE (GET_MODE (XEXP (x, 0))));
+      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
+      return true;
+
+    case PLUS:
+      switch (mode)
+       {
+       case QImode:
+         *total = COSTS_N_INSNS (1);
+         if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+           *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
+         break;
+
+       case HImode:
+         if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+           {
+             *total = COSTS_N_INSNS (2);
+             *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
+           }
+         else if (INTVAL (XEXP (x, 1)) >= -63 && INTVAL (XEXP (x, 1)) <= 63)
+           *total = COSTS_N_INSNS (1);
+         else
+           *total = COSTS_N_INSNS (2);
+         break;
+
+       case SImode:
+         if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+           {
+             *total = COSTS_N_INSNS (4);
+             *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
+           }
+         else if (INTVAL (XEXP (x, 1)) >= -63 && INTVAL (XEXP (x, 1)) <= 63)
+           *total = COSTS_N_INSNS (1);
+         else
+           *total = COSTS_N_INSNS (4);
+         break;
+
+       default:
+         return false;
+       }
+      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
+      return true;
+
+    case MINUS:
+    case AND:
+    case IOR:
+      *total = COSTS_N_INSNS (GET_MODE_SIZE (mode));
+      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
+      if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+          *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
+      return true;
+
+    case XOR:
+      *total = COSTS_N_INSNS (GET_MODE_SIZE (mode));
+      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
+      *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
+      return true;
+
+    case MULT:
+      switch (mode)
        {
-         *total = cst;
-         return true;
+       case QImode:
+         if (AVR_HAVE_MUL)
+           *total = COSTS_N_INSNS (optimize_size ? 3 : 4);
+         else if (optimize_size)
+           *total = COSTS_N_INSNS (AVR_MEGA ? 2 : 1);
+         else
+           return false;
+
+       case HImode:
+         if (AVR_HAVE_MUL)
+           *total = COSTS_N_INSNS (optimize_size ? 7 : 10);
+         else if (optimize_size)
+           *total = COSTS_N_INSNS (AVR_MEGA ? 2 : 1);
+         else
+           return false;
+
+       default:
+         return false;
+       }
+      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
+      *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
+      return true;
+
+    case DIV:
+    case MOD:
+    case UDIV:
+    case UMOD:
+      if (optimize_size)
+       *total = COSTS_N_INSNS (AVR_MEGA ? 2 : 1);
+      else
+       return false;
+      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
+      *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
+      return true;
+
+    case ASHIFT:
+      switch (mode)
+       {
+       case QImode:
+         if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+           {
+             *total = COSTS_N_INSNS (optimize_size ? 4 : 17);
+             *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
+           }
+         else
+           {
+             val = INTVAL (XEXP (x, 1));
+             if (val == 7)
+               *total = COSTS_N_INSNS (3);
+             else if (val >= 0 && val <= 7)
+               *total = COSTS_N_INSNS (val);
+             else
+               *total = COSTS_N_INSNS (1);
+           }
+         break;
+
+       case HImode:
+         if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+           {
+             *total = COSTS_N_INSNS (optimize_size ? 5 : 41);
+             *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
+           }
+         else
+           switch (INTVAL (XEXP (x, 1)))
+             {
+             case 0:
+               *total = 0;
+               break;
+             case 1:
+             case 8:
+               *total = COSTS_N_INSNS (2);
+               break;
+             case 9:
+               *total = COSTS_N_INSNS (3);
+               break;
+             case 2:
+             case 3:
+             case 10:
+             case 15:
+               *total = COSTS_N_INSNS (4);
+               break;
+             case 7:
+             case 11:
+             case 12:
+               *total = COSTS_N_INSNS (5);
+               break;
+             case 4:
+               *total = COSTS_N_INSNS (optimize_size ? 5 : 8);
+               break;
+             case 6:
+               *total = COSTS_N_INSNS (optimize_size ? 5 : 9);
+               break;
+             case 5:
+               *total = COSTS_N_INSNS (optimize_size ? 5 : 10);
+               break;
+             default:
+               *total = COSTS_N_INSNS (optimize_size ? 5 : 41);
+               *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
+             }
+         break;
+
+       case SImode:
+         if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+           {
+             *total = COSTS_N_INSNS (optimize_size ? 7 : 113);
+             *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
+           }
+         else
+           switch (INTVAL (XEXP (x, 1)))
+             {
+             case 0:
+               *total = 0;
+               break;
+             case 24:
+               *total = COSTS_N_INSNS (3);
+               break;
+             case 1:
+             case 8:
+             case 16:
+               *total = COSTS_N_INSNS (4);
+               break;
+             case 31:
+               *total = COSTS_N_INSNS (6);
+               break;
+             case 2:
+               *total = COSTS_N_INSNS (optimize_size ? 7 : 8);
+               break;
+             default:
+               *total = COSTS_N_INSNS (optimize_size ? 7 : 113);
+               *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
+             }
+         break;
+
+       default:
+         return false;
        }
-      else if (cst < 0)
-       *total += -cst;
-      return false;
+      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
+      return true;
+
+    case ASHIFTRT:
+      switch (mode)
+       {
+       case QImode:
+         if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+           {
+             *total = COSTS_N_INSNS (optimize_size ? 4 : 17);
+             *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
+           }
+         else
+           {
+             val = INTVAL (XEXP (x, 1));
+             if (val == 6)
+               *total = COSTS_N_INSNS (4);
+             else if (val == 7)
+               *total = COSTS_N_INSNS (2);
+             else if (val >= 0 && val <= 7)
+               *total = COSTS_N_INSNS (val);
+             else
+               *total = COSTS_N_INSNS (1);
+           }
+         break;
+
+       case HImode:
+         if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+           {
+             *total = COSTS_N_INSNS (optimize_size ? 5 : 41);
+             *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
+           }
+         else
+           switch (INTVAL (XEXP (x, 1)))
+             {
+             case 0:
+               *total = 0;
+               break;
+             case 1:
+               *total = COSTS_N_INSNS (2);
+               break;
+             case 15:
+               *total = COSTS_N_INSNS (3);
+               break;
+             case 2:
+             case 7:
+              case 8:
+              case 9:
+               *total = COSTS_N_INSNS (4);
+               break;
+              case 10:
+             case 14:
+               *total = COSTS_N_INSNS (5);
+               break;
+              case 11:
+                *total = COSTS_N_INSNS (optimize_size ? 5 : 6);
+               break;
+              case 12:
+                *total = COSTS_N_INSNS (optimize_size ? 5 : 7);
+               break;
+              case 6:
+             case 13:
+                *total = COSTS_N_INSNS (optimize_size ? 5 : 8);
+               break;
+             default:
+               *total = COSTS_N_INSNS (optimize_size ? 5 : 41);
+               *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
+             }
+         break;
+
+       case SImode:
+         if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+           {
+             *total = COSTS_N_INSNS (optimize_size ? 7 : 113);
+             *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
+           }
+         else
+           switch (INTVAL (XEXP (x, 1)))
+             {
+             case 0:
+               *total = 0;
+               break;
+             case 1:
+               *total = COSTS_N_INSNS (4);
+               break;
+             case 8:
+             case 16:
+             case 24:
+               *total = COSTS_N_INSNS (6);
+               break;
+             case 2:
+               *total = COSTS_N_INSNS (optimize_size ? 7 : 8);
+               break;
+             case 31:
+               *total = COSTS_N_INSNS (AVR_HAVE_MOVW ? 4 : 5);
+               break;
+             default:
+               *total = COSTS_N_INSNS (optimize_size ? 7 : 113);
+               *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
+             }
+         break;
+
+       default:
+         return false;
+       }
+      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
+      return true;
+
+    case LSHIFTRT:
+      switch (mode)
+       {
+       case QImode:
+         if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+           {
+             *total = COSTS_N_INSNS (optimize_size ? 4 : 17);
+             *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
+           }
+         else
+           {
+             val = INTVAL (XEXP (x, 1));
+             if (val == 7)
+               *total = COSTS_N_INSNS (3);
+             else if (val >= 0 && val <= 7)
+               *total = COSTS_N_INSNS (val);
+             else
+               *total = COSTS_N_INSNS (1);
+           }
+         break;
+
+       case HImode:
+         if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+           {
+             *total = COSTS_N_INSNS (optimize_size ? 5 : 41);
+             *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
+           }
+         else
+           switch (INTVAL (XEXP (x, 1)))
+             {
+             case 0:
+               *total = 0;
+               break;
+             case 1:
+             case 8:
+               *total = COSTS_N_INSNS (2);
+               break;
+             case 9:
+               *total = COSTS_N_INSNS (3);
+               break;
+             case 2:
+             case 10:
+             case 15:
+               *total = COSTS_N_INSNS (4);
+               break;
+             case 7:
+              case 11:
+               *total = COSTS_N_INSNS (5);
+               break;
+             case 3:
+             case 12:
+             case 13:
+             case 14:
+               *total = COSTS_N_INSNS (optimize_size ? 5 : 6);
+               break;
+             case 4:
+               *total = COSTS_N_INSNS (optimize_size ? 5 : 7);
+               break;
+             case 5:
+             case 6:
+               *total = COSTS_N_INSNS (optimize_size ? 5 : 9);
+               break;
+             default:
+               *total = COSTS_N_INSNS (optimize_size ? 5 : 41);
+               *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
+             }
+         break;
+
+       case SImode:
+         if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+           {
+             *total = COSTS_N_INSNS (optimize_size ? 7 : 113);
+             *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
+           }
+         else
+           switch (INTVAL (XEXP (x, 1)))
+             {
+             case 0:
+               *total = 0;
+               break;
+             case 1:
+               *total = COSTS_N_INSNS (4);
+               break;
+             case 2:
+               *total = COSTS_N_INSNS (optimize_size ? 7 : 8);
+               break;
+             case 8:
+             case 16:
+             case 24:
+               *total = COSTS_N_INSNS (4);
+               break;
+             case 31:
+               *total = COSTS_N_INSNS (6);
+               break;
+             default:
+               *total = COSTS_N_INSNS (optimize_size ? 7 : 113);
+               *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
+             }
+         break;
+
+       default:
+         return false;
+       }
+      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
+      return true;
+
+    case COMPARE:
+      switch (GET_MODE (XEXP (x, 0)))
+       {
+       case QImode:
+         *total = COSTS_N_INSNS (1);
+         if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+           *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
+         break;
+
+        case HImode:
+         *total = COSTS_N_INSNS (2);
+         if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+            *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
+         else if (INTVAL (XEXP (x, 1)) != 0)
+           *total += COSTS_N_INSNS (1);
+          break;
+
+        case SImode:
+          *total = COSTS_N_INSNS (4);
+          if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+            *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
+         else if (INTVAL (XEXP (x, 1)) != 0)
+           *total += COSTS_N_INSNS (3);
+          break;
+
+       default:
+         return false;
+       }
+      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
+      return true;
+
+    default:
+      break;
     }
+  return false;
 }
 
 /* Calculate the cost of a memory address.  */
@@ -4866,48 +5394,35 @@ avr_address_cost (rtx x)
   return 4;
 }
 
-/*  EXTRA_CONSTRAINT helper */
+/* Test for extra memory constraint 'Q'.
+   It's a memory address based on Y or Z pointer with valid displacement.  */
 
 int
-extra_constraint (rtx x, int c)
+extra_constraint_Q (rtx x)
 {
-  if (c == 'Q'
-      && GET_CODE (x) == MEM
-      && GET_CODE (XEXP (x,0)) == PLUS)
+  if (GET_CODE (XEXP (x,0)) == PLUS
+      && REG_P (XEXP (XEXP (x,0), 0))
+      && GET_CODE (XEXP (XEXP (x,0), 1)) == CONST_INT
+      && (INTVAL (XEXP (XEXP (x,0), 1))
+         <= MAX_LD_OFFSET (GET_MODE (x))))
     {
-         if (TARGET_ALL_DEBUG)
-           {
-             fprintf (stderr, ("extra_constraint:\n"
-                               "reload_completed: %d\n"
-                               "reload_in_progress: %d\n"),
-                      reload_completed, reload_in_progress);
-             debug_rtx (x);
-           }
-      if (GET_CODE (x) == MEM
-         && GET_CODE (XEXP (x,0)) == PLUS
-         && REG_P (XEXP (XEXP (x,0), 0))
-         && GET_CODE (XEXP (XEXP (x,0), 1)) == CONST_INT
-         && (INTVAL (XEXP (XEXP (x,0), 1))
-             <= MAX_LD_OFFSET (GET_MODE (x))))
+      rtx xx = XEXP (XEXP (x,0), 0);
+      int regno = REGNO (xx);
+      if (TARGET_ALL_DEBUG)
        {
-         rtx xx = XEXP (XEXP (x,0), 0);
-         int regno = REGNO (xx);
-         if (TARGET_ALL_DEBUG)
-           {
-             fprintf (stderr, ("extra_constraint:\n"
-                               "reload_completed: %d\n"
-                               "reload_in_progress: %d\n"),
-                      reload_completed, reload_in_progress);
-             debug_rtx (x);
-           }
-         if (regno >= FIRST_PSEUDO_REGISTER)
-           return 1;           /* allocate pseudos */
-         else if (regno == REG_Z || regno == REG_Y)
-           return 1;           /* strictly check */
-         else if (xx == frame_pointer_rtx
-                  || xx == arg_pointer_rtx)
-           return 1;           /* XXX frame & arg pointer checks */
+         fprintf (stderr, ("extra_constraint:\n"
+                           "reload_completed: %d\n"
+                           "reload_in_progress: %d\n"),
+                  reload_completed, reload_in_progress);
+         debug_rtx (x);
        }
+      if (regno >= FIRST_PSEUDO_REGISTER)
+       return 1;               /* allocate pseudos */
+      else if (regno == REG_Z || regno == REG_Y)
+       return 1;               /* strictly check */
+      else if (xx == frame_pointer_rtx
+              || xx == arg_pointer_rtx)
+       return 1;               /* XXX frame & arg pointer checks */
     }
   return 0;
 }
@@ -4928,7 +5443,7 @@ avr_normalize_condition (RTX_CODE condition)
     case LEU:
       return LTU;
     default:
-      abort ();
+      gcc_unreachable ();
     }
 }
 
@@ -5018,7 +5533,7 @@ avr_ret_register (void)
   return 24;
 }
 
-/* Ceate an RTX representing the place where a
+/* Create an RTX representing the place where a
    library function returns a value of mode MODE.  */
 
 rtx
@@ -5052,28 +5567,6 @@ avr_function_value (tree type, tree func ATTRIBUTE_UNUSED)
   return gen_rtx_REG (BLKmode, RET_REGISTER + 2 - offs);
 }
 
-/* Returns nonzero if the number MASK has only one bit set.  */
-
-int
-mask_one_bit_p (HOST_WIDE_INT mask)
-{
-  int i;
-  unsigned HOST_WIDE_INT n=mask;
-  for (i = 0; i < 32; ++i)
-    {
-      if (n & 0x80000000L)
-       {
-         if (n & 0x7fffffffL)
-           return 0;
-         else
-           return 32-i;
-       }
-      n<<=1;
-    }
-  return 0; 
-}
-
-
 /* Places additional restrictions on the register class to
    use when it is necessary to copy value X into a register
    in class CLASS.  */
@@ -5117,17 +5610,22 @@ jump_over_one_insn_p (rtx insn, rtx dest)
 int
 avr_hard_regno_mode_ok (int regno, enum machine_mode mode)
 {
-  /* Bug workaround: recog.c (peep2_find_free_register) and probably
-     a few other places assume that the frame pointer is a single hard
-     register, so r29 may be allocated and overwrite the high byte of
-     the frame pointer.  Do not allow any value to start in r29.  */
-  if (regno == REG_Y + 1)
+  /* The only thing that can go into registers r28:r29 is a Pmode.  */
+  if (regno == REG_Y && mode == Pmode)
+    return 1;
+
+  /* Otherwise disallow all regno/mode combinations that span r28:r29.  */
+  if (regno <= (REG_Y + 1) && (regno + GET_MODE_SIZE (mode)) >= (REG_Y + 1))
     return 0;
 
   if (mode == QImode)
     return 1;
-  /*  if (regno < 24 && !AVR_ENHANCED)
-      return 1;*/
+
+  /* Modes larger than QImode occupy consecutive registers.  */
+  if (regno + GET_MODE_SIZE (mode) > FIRST_PSEUDO_REGISTER)
+    return 0;
+
+  /* All modes larger than QImode should start in an even register.  */
   return !(regno & 1);
 }
 
@@ -5142,20 +5640,6 @@ avr_io_address_p (rtx x, int size)
          && 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 (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 (rtx insn ATTRIBUTE_UNUSED, rtx *operands, int *len)
 {
@@ -5259,6 +5743,7 @@ avr_output_bld (rtx operands[], int bit_nr)
 void
 avr_output_addr_vec_elt (FILE *stream, int value)
 {
+  switch_to_section (progmem_section);
   if (AVR_MEGA)
     fprintf (stream, "\t.word pm(.L%d)\n", value);
   else