OSDN Git Service

2006-02-24 Anatoly Sokolov <aesok@post.ru>
[pf3gnuchains/gcc-fork.git] / gcc / config / avr / avr.c
index 16701d1..436c570 100644 (file)
@@ -1,23 +1,24 @@
 /* Subroutines for insn-output.c for ATMEL AVR micro controllers
-   Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007
+   Free Software Foundation, Inc.
    Contributed by Denis Chertykov (denisc@overta.ru)
 
-   This file is part of GNU CC.
+   This file is part of GCC.
 
-   GNU CC is free software; you can redistribute it and/or modify
+   GCC is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2, or (at your option)
    any later version.
    
-   GNU CC is distributed in the hope that it will be useful,
+   GCC is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with GNU CC; see the file COPYING.  If not, write to
-   the Free Software Foundation, 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
+   along with GCC; see the file COPYING.  If not, write to
+   the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
 
 #include "config.h"
 #include "system.h"
@@ -39,6 +40,7 @@
 #include "obstack.h"
 #include "function.h"
 #include "recog.h"
+#include "ggc.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))
 
-static int    avr_naked_function_p PARAMS ((tree));
-static int    interrupt_function_p PARAMS ((tree));
-static int    signal_function_p    PARAMS ((tree));
-static int    avr_regs_to_save     PARAMS ((HARD_REG_SET *));
-static int    sequent_regs_live    PARAMS ((void));
-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 tree   avr_handle_progmem_attribute PARAMS ((tree *, tree, tree, int, bool *));
-static tree   avr_handle_fndecl_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static int avr_naked_function_p (tree);
+static int interrupt_function_p (tree);
+static int signal_function_p (tree);
+static int avr_regs_to_save (HARD_REG_SET *);
+static int sequent_regs_live (void);
+static const char *ptrreg_to_str (int);
+static const char *cond_string (enum rtx_code);
+static int avr_num_arg_regs (enum machine_mode, tree);
+static int out_adj_frame_ptr (FILE *, int);
+static int out_set_stack_ptr (FILE *, int, int);
+static RTX_CODE compare_condition (rtx insn);
+static int compare_sign_p (rtx insn);
+static tree avr_handle_progmem_attribute (tree *, tree, tree, int, bool *);
+static tree avr_handle_fndecl_attribute (tree *, tree, tree, int, bool *);
 const struct attribute_spec avr_attribute_table[];
-static bool   avr_assemble_integer PARAMS ((rtx, unsigned int, int));
-static void   avr_file_start PARAMS ((void));
-static void   avr_file_end PARAMS ((void));
-static void   avr_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));
-static void   avr_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
-static void   avr_unique_section PARAMS ((tree, int));
-static void   avr_insert_attributes PARAMS ((tree, tree *));
-static unsigned int avr_section_type_flags PARAMS ((tree, const char *, int));
-
-static void avr_reorg PARAMS ((void));
-static void   avr_asm_out_ctor PARAMS ((rtx, int));
-static void   avr_asm_out_dtor PARAMS ((rtx, int));
-static int default_rtx_costs PARAMS ((rtx, enum rtx_code, enum rtx_code));
-static bool avr_rtx_costs PARAMS ((rtx, int, int, int *));
-static int avr_address_cost PARAMS ((rtx));
-
-/* Allocate registers from r25 to r8 for parameters for function calls */
+static bool avr_assemble_integer (rtx, unsigned int, int);
+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_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 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);
+
+/* Allocate registers from r25 to r8 for parameters for function calls.  */
 #define FIRST_CUM_REG 26
 
-/* Temporary register RTX (gen_rtx (REG,QImode,TMP_REGNO)) */
-rtx tmp_reg_rtx;
+/* Temporary register RTX (gen_rtx_REG (QImode, TMP_REGNO)) */
+static GTY(()) 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;
+/* Zeroed register RTX (gen_rtx_REG (QImode, ZERO_REGNO)) */
+static GTY(()) rtx zero_reg_rtx;
 
 /* AVR register names {"r0", "r1", ..., "r31"} */
 static const char *const avr_regnames[] = REGISTER_NAMES;
@@ -112,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 {
@@ -177,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__" },
@@ -188,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 },
@@ -217,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
@@ -232,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
@@ -245,10 +302,16 @@ int avr_case_values_threshold = 30000;
 #undef TARGET_MACHINE_DEPENDENT_REORG
 #define TARGET_MACHINE_DEPENDENT_REORG avr_reorg
 
+#undef TARGET_RETURN_IN_MEMORY
+#define TARGET_RETURN_IN_MEMORY avr_return_in_memory
+
+#undef TARGET_STRICT_ARGUMENT_NAMING
+#define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 void
-avr_override_options ()
+avr_override_options (void)
 {
   const struct mcu_type_s *t;
   const struct base_arch_s *base;
@@ -259,7 +322,7 @@ avr_override_options ()
 
   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);
@@ -267,37 +330,20 @@ avr_override_options ()
 
   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;
 
   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 ()
-{
-  tmp_reg_rtx = xcalloc (1, sizeof (struct rtx_def) + 1 * sizeof (rtunion));
-  PUT_CODE (tmp_reg_rtx, REG);
-  PUT_MODE (tmp_reg_rtx, QImode);
-  XINT (tmp_reg_rtx, 0) = TMP_REGNO;
-
-  zero_reg_rtx = xcalloc (1, sizeof (struct rtx_def) + 1 * sizeof (rtunion));
-  PUT_CODE (zero_reg_rtx, REG);
-  PUT_MODE (zero_reg_rtx, QImode);
-  XINT (zero_reg_rtx, 0) = ZERO_REGNO;
-
-  ldi_reg_rtx = xcalloc (1, 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;
+  tmp_reg_rtx  = gen_rtx_REG (QImode, TMP_REGNO);
+  zero_reg_rtx = gen_rtx_REG (QImode, ZERO_REGNO);
 }
 
-/*  return register class from register number */
+/*  return register class from register number */
 
 static const int reg_class_tab[]={
   GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,
@@ -313,57 +359,24 @@ static const int reg_class_tab[]={
   STACK_REG,STACK_REG           /* SPL,SPH */
 };
 
-/* Return register class for register R */
+/* Return register class for register R */
 
 enum reg_class
-avr_regno_reg_class (r)
-     int r;
+avr_regno_reg_class (int r)
 {
   if (r <= 33)
     return reg_class_tab[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  (c)
-     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
-avr_naked_function_p (func)
-     tree func;
+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;
@@ -373,8 +386,7 @@ avr_naked_function_p (func)
    by the "interrupt" attribute.  */
 
 static int
-interrupt_function_p (func)
-     tree func;
+interrupt_function_p (tree func)
 {
   tree a;
 
@@ -389,8 +401,7 @@ interrupt_function_p (func)
    by the "signal" attribute.  */
 
 static int
-signal_function_p (func)
-     tree func;
+signal_function_p (tree func)
 {
   tree a;
 
@@ -405,8 +416,7 @@ signal_function_p (func)
    of the current function, and optionally store these registers in SET.  */
 
 static int
-avr_regs_to_save (set)
-     HARD_REG_SET *set;
+avr_regs_to_save (HARD_REG_SET *set)
 {
   int reg, count;
   int int_or_sig_p = (interrupt_function_p (current_function_decl)
@@ -442,12 +452,10 @@ avr_regs_to_save (set)
   return count;
 }
 
-/* Compute offset between arg_pointer and frame_pointer */
+/* Compute offset between arg_pointer and frame_pointer */
 
 int
-initial_elimination_offset (from, to)
-     int from;
-     int to;
+initial_elimination_offset (int from, int to)
 {
   if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
     return 0;
@@ -463,7 +471,7 @@ initial_elimination_offset (from, to)
 /* Return 1 if the function epilogue is just a single "ret".  */
 
 int
-avr_simple_epilogue ()
+avr_simple_epilogue (void)
 {
   return (! frame_pointer_needed
          && get_frame_size () == 0
@@ -475,10 +483,10 @@ avr_simple_epilogue ()
          && ! TREE_THIS_VOLATILE (current_function_decl));
 }
 
-/* This function checks sequence of live registers */
+/* This function checks sequence of live registers */
 
 static int
-sequent_regs_live ()
+sequent_regs_live (void)
 {
   int reg;
   int live_seq=0;
@@ -530,9 +538,7 @@ sequent_regs_live ()
    (epilogue).  Returns the number of instructions generated.  */
 
 static int
-out_adj_frame_ptr (file, adj)
-     FILE *file;
-     int adj;
+out_adj_frame_ptr (FILE *file, int adj)
 {
   int size = 0;
 
@@ -541,7 +547,7 @@ out_adj_frame_ptr (file, 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).  */
@@ -577,10 +583,7 @@ out_adj_frame_ptr (file, adj)
    Returns the number of instructions generated.  */
 
 static int
-out_set_stack_ptr (file, before, after)
-     FILE *file;
-     int before;
-     int after;
+out_set_stack_ptr (FILE *file, int before, int after)
 {
   int do_sph, do_cli, do_save, do_sei, lock_sph, size;
 
@@ -637,12 +640,10 @@ out_set_stack_ptr (file, before, after)
 }
 
 
-/* Output function prologue */
+/* Output function prologue */
 
 static void
-avr_output_function_prologue (file, size)
-     FILE *file;
-     HOST_WIDE_INT size;
+avr_output_function_prologue (FILE *file, HOST_WIDE_INT size)
 {
   int reg;
   int interrupt_func_p;
@@ -702,9 +703,8 @@ avr_output_function_prologue (file, size)
                      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)
-              ,current_function_name, current_function_name);
+      fputs ((AS2 (ldi,r30,pm_lo8(1f)) CR_TAB
+             AS2 (ldi,r31,pm_hi8(1f)) CR_TAB), file);
       
       prologue_size += 4;
       
@@ -720,7 +720,7 @@ avr_output_function_prologue (file, size)
                   (18 - live_seq) * 2);
          ++prologue_size;
        }
-      fprintf (file, ".L_%s_body:\n", current_function_name);
+      fputs ("1:\n", file);
     }
   else
     {
@@ -736,32 +736,30 @@ avr_output_function_prologue (file, size)
        }
       if (frame_pointer_needed)
        {
-         {
-           fprintf (file, "\t"
-                    AS1 (push,r28) CR_TAB
-                    AS1 (push,r29) CR_TAB
-                    AS2 (in,r28,__SP_L__) CR_TAB
-                    AS2 (in,r29,__SP_H__) "\n");
-           prologue_size += 4;
-           if (size)
-             {
-               fputs ("\t", file);
-               prologue_size += out_adj_frame_ptr (file, size);
-
-               if (interrupt_func_p)
-                 {
-                   prologue_size += out_set_stack_ptr (file, 1, 1);
-                 }
-               else if (signal_func_p)
-                 {
-                   prologue_size += out_set_stack_ptr (file, 0, 0);
-                 }
-               else
-                 {
-                   prologue_size += out_set_stack_ptr (file, -1, -1);
-                 }
-             }
-         }
+         fprintf (file, "\t"
+                  AS1 (push,r28) CR_TAB
+                  AS1 (push,r29) CR_TAB
+                  AS2 (in,r28,__SP_L__) CR_TAB
+                  AS2 (in,r29,__SP_H__) "\n");
+         prologue_size += 4;
+         if (size)
+           {
+             fputs ("\t", file);
+             prologue_size += out_adj_frame_ptr (file, size);
+
+             if (interrupt_func_p)
+               {
+                 prologue_size += out_set_stack_ptr (file, 1, 1);
+               }
+             else if (signal_func_p)
+               {
+                 prologue_size += out_set_stack_ptr (file, 0, 0);
+               }
+             else
+               {
+                 prologue_size += out_set_stack_ptr (file, -1, -1);
+               }
+           }
        }
     }
 
@@ -769,12 +767,10 @@ avr_output_function_prologue (file, size)
   fprintf (file, "/* prologue end (size=%d) */\n", prologue_size);
 }
 
-/* Output function epilogue */
+/* Output function epilogue */
 
 static void
-avr_output_function_epilogue (file, size)
-     FILE *file;
-     HOST_WIDE_INT size;
+avr_output_function_epilogue (FILE *file, HOST_WIDE_INT size)
 {
   int reg;
   int interrupt_func_p;
@@ -911,7 +907,7 @@ avr_output_function_epilogue (file, size)
 
  out:
   fprintf (file, "/* epilogue end (size=%d) */\n", epilogue_size);
-  fprintf (file, "/* function %s size %d (%d) */\n", current_function_name,
+  fprintf (file, "/* function %s size %d (%d) */\n", current_function_name (),
           prologue_size + function_size + epilogue_size, function_size);
   commands_in_file += prologue_size + function_size + epilogue_size;
   commands_in_prologues += prologue_size;
@@ -923,10 +919,7 @@ avr_output_function_epilogue (file, size)
    machine for a memory operand of mode MODE.  */
 
 int
-legitimate_address_p (mode, x, strict)
-     enum machine_mode mode;
-     rtx x;
-     int strict;
+legitimate_address_p (enum machine_mode mode, rtx x, int strict)
 {
   enum reg_class r = NO_REGS;
   
@@ -982,7 +975,7 @@ legitimate_address_p (mode, x, 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;
 }
@@ -991,10 +984,7 @@ legitimate_address_p (mode, x, strict)
    memory address for an operand of mode MODE  */
 
 rtx
-legitimize_address (x, oldx, mode)
-     rtx x;
-     rtx oldx;
-     enum machine_mode mode;
+legitimize_address (rtx x, rtx oldx, enum machine_mode mode)
 {
   x = oldx;
   if (TARGET_ALL_DEBUG)
@@ -1024,11 +1014,10 @@ legitimize_address (x, oldx, mode)
 }
 
 
-/* Return a pointer register name as a string */
+/* Return a pointer register name as a string */
 
 static const char *
-ptrreg_to_str (regno)
-     int regno;
+ptrreg_to_str (int regno)
 {
   switch (regno)
     {
@@ -1036,7 +1025,7 @@ ptrreg_to_str (regno)
     case REG_Y: return "Y";
     case REG_Z: return "Z";
     default:
-      abort ();
+      gcc_unreachable ();
     }
   return NULL;
 }
@@ -1045,8 +1034,7 @@ ptrreg_to_str (regno)
    Used in conditional jump constructing  */
 
 static const char *
-cond_string (code)
-     enum rtx_code code;
+cond_string (enum rtx_code code)
 {
   switch (code)
     {
@@ -1069,16 +1057,14 @@ cond_string (code)
     case LTU:
       return "lo";
     default:
-      abort ();
+      gcc_unreachable ();
     }
 }
 
-/* Output ADDR to FILE as address */
+/* Output ADDR to FILE as address */
 
 void
-print_operand_address (file, addr)
-     FILE *file;
-     rtx addr;
+print_operand_address (FILE *file, rtx addr)
 {
   switch (GET_CODE (addr))
     {
@@ -1109,13 +1095,10 @@ print_operand_address (file, addr)
 }
 
 
-/* Output X as assembler operand to file FILE */
+/* Output X as assembler operand to file FILE */
      
 void
-print_operand (file, x, code)
-     FILE *file;
-     rtx x;
-     int code;
+print_operand (FILE *file, rtx x, int code)
 {
   int abcd = 0;
 
@@ -1153,6 +1136,16 @@ print_operand (file, x, 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));
@@ -1183,30 +1176,10 @@ print_operand (file, x, code)
     print_operand_address (file, x);
 }
 
-/* Recognize operand OP of mode MODE used in call instructions */
-
-int
-call_insn_operand (op, mode)
-     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
-notice_update_cc (body, insn)
-     rtx body ATTRIBUTE_UNUSED;
-     rtx insn;
+notice_update_cc (rtx body ATTRIBUTE_UNUSED, rtx insn)
 {
   rtx set;
   
@@ -1266,6 +1239,7 @@ notice_update_cc (body, insn)
              rtx x = XEXP (src, 1);
 
              if (GET_CODE (x) == CONST_INT
+                 && INTVAL (x) > 0
                  && INTVAL (x) != 6)
                {
                  cc_status.value1 = SET_DEST (set);
@@ -1281,9 +1255,7 @@ notice_update_cc (body, insn)
    class CLASS needed to hold a value of mode MODE.  */
 
 int
-class_max_nregs (class, mode)
-     enum reg_class class ATTRIBUTE_UNUSED;
-     enum machine_mode mode;
+class_max_nregs (enum reg_class class ATTRIBUTE_UNUSED,enum machine_mode mode)
 {
   return ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD);
 }
@@ -1294,9 +1266,7 @@ class_max_nregs (class, mode)
    3 - absolute jump (only for ATmega[16]03).  */
 
 int
-avr_jump_mode (x, insn)
-     rtx x;                     /* jump operand */
-     rtx insn;                  /* jump insn */
+avr_jump_mode (rtx x, rtx insn)
 {
   int dest_addr = INSN_ADDRESSES (INSN_UID (GET_MODE (x) == LABEL_REF
                                            ? XEXP (x, 0) : x));
@@ -1319,10 +1289,7 @@ avr_jump_mode (x, insn)
    if REVERSE nonzero then condition code in X must be reversed.  */
 
 const char *
-ret_cond_branch (x, len, reverse)
-     rtx x;
-     int len;
-     int reverse;
+ret_cond_branch (rtx x, int len, int reverse)
 {
   RTX_CODE cond = reverse ? reverse_condition (GET_CODE (x)) : GET_CODE (x);
   
@@ -1421,9 +1388,7 @@ ret_cond_branch (x, len, reverse)
 /* Predicate function for immediate operand which fits to byte (8bit) */
 
 int
-byte_immediate_operand (op, mode)
-     register rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+byte_immediate_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
   return (GET_CODE (op) == CONST_INT
           && INTVAL (op) <= 0xff && INTVAL (op) >= 0);
@@ -1435,9 +1400,8 @@ byte_immediate_operand (op, mode)
    Output insn cost for next insn.  */
 
 void
-final_prescan_insn (insn, operand, num_operands)
-     rtx insn, *operand ATTRIBUTE_UNUSED;
-     int num_operands ATTRIBUTE_UNUSED;
+final_prescan_insn (rtx insn, rtx *operand ATTRIBUTE_UNUSED,
+                   int num_operands ATTRIBUTE_UNUSED)
 {
   int uid = INSN_UID (insn);
 
@@ -1454,10 +1418,7 @@ final_prescan_insn (insn, operand, num_operands)
 /* Return 0 if undefined, 1 if always true or always false.  */
 
 int
-avr_simplify_comparison_p (mode, operator, x)
-     enum machine_mode mode;
-     RTX_CODE operator;
-     rtx x;
+avr_simplify_comparison_p (enum machine_mode mode, RTX_CODE operator, rtx x)
 {
   unsigned int max = (mode == QImode ? 0xff :
                       mode == HImode ? 0xffff :
@@ -1479,8 +1440,7 @@ avr_simplify_comparison_p (mode, operator, x)
    register in which function arguments are sometimes passed.  */
 
 int
-function_arg_regno_p(r)
-     int r;
+function_arg_regno_p(int r)
 {
   return (r >= 8 && r <= 25);
 }
@@ -1489,11 +1449,8 @@ function_arg_regno_p(r)
    of the argument list.  */
 
 void
-init_cumulative_args (cum, fntype, libname, fndecl)
-     CUMULATIVE_ARGS *cum;
-     tree fntype;
-     rtx libname;
-     tree fndecl ATTRIBUTE_UNUSED;
+init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype, rtx libname,
+                     tree fndecl ATTRIBUTE_UNUSED)
 {
   cum->nregs = 18;
   cum->regno = FIRST_CUM_REG;
@@ -1510,9 +1467,7 @@ init_cumulative_args (cum, fntype, libname, fndecl)
 /* 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;
+avr_num_arg_regs (enum machine_mode mode, tree type)
 {
   int size;
 
@@ -1528,19 +1483,16 @@ avr_num_arg_regs (mode, type)
 }
 
 /* Controls whether a function argument is passed
-   in a register, and which register. */
+   in a register, and which register.  */
 
 rtx
-function_arg (cum, mode, type, named)
-     CUMULATIVE_ARGS *cum;
-     enum machine_mode mode;
-     tree type;
-     int named ATTRIBUTE_UNUSED;
+function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
+             int named ATTRIBUTE_UNUSED)
 {
   int bytes = avr_num_arg_regs (mode, type);
 
   if (cum->nregs && bytes <= cum->nregs)
-    return gen_rtx (REG, mode, cum->regno - bytes);
+    return gen_rtx_REG (mode, cum->regno - bytes);
 
   return NULL_RTX;
 }
@@ -1549,11 +1501,8 @@ function_arg (cum, mode, type, named)
    in the argument list.  */
    
 void
-function_arg_advance (cum, mode, type, named)
-     CUMULATIVE_ARGS *cum;      /* current arg information */
-     enum machine_mode mode;    /* current arg mode */
-     tree type;                 /* type of the argument or 0 if lib support */
-     int named ATTRIBUTE_UNUSED; /* whether or not the argument was named */
+function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
+                     int named ATTRIBUTE_UNUSED)
 {
   int bytes = avr_num_arg_regs (mode, type);
 
@@ -1571,10 +1520,7 @@ function_arg_advance (cum, mode, type, named)
   Functions for outputting various mov's for a various modes
 ************************************************************************/
 const char *
-output_movqi (insn, operands, l)
-     rtx insn;
-     rtx operands[];
-     int *l;
+output_movqi (rtx insn, rtx operands[], int *l)
 {
   int dummy;
   rtx dest = operands[0];
@@ -1666,10 +1612,7 @@ output_movqi (insn, operands, l)
 
 
 const char *
-output_movhi (insn, operands, l)
-     rtx insn;
-     rtx operands[];
-     int *l;
+output_movhi (rtx insn, rtx operands[], int *l)
 {
   int dummy;
   rtx dest = operands[0];
@@ -1711,18 +1654,11 @@ output_movhi (insn, operands, 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;
@@ -1832,10 +1768,7 @@ output_movhi (insn, operands, l)
 }
 
 const char *
-out_movqi_r_mr (insn, op, l)
-     rtx insn;
-     rtx op[];
-     int *l; /* instruction length */
+out_movqi_r_mr (rtx insn, rtx op[], int *l)
 {
   rtx dest = op[0];
   rtx src = op[1];
@@ -1898,16 +1831,16 @@ out_movqi_r_mr (insn, op, l)
 }
 
 const char *
-out_movhi_r_mr (insn, op, l)
-     rtx insn;
-     rtx op[];
-     int *l; /* instruction length */
+out_movhi_r_mr (rtx insn, rtx op[], int *l)
 {
   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);
+  /* "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)
@@ -2001,6 +1934,25 @@ out_movhi_r_mr (insn, op, 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));
@@ -2032,10 +1984,7 @@ out_movhi_r_mr (insn, op, l)
 }
 
 const char *
-out_movsi_r_mr (insn, op, l)
-     rtx insn;
-     rtx op[];
-     int *l; /* instruction length */
+out_movsi_r_mr (rtx insn, rtx op[], int *l)
 {
   rtx dest = op[0];
   rtx src = op[1];
@@ -2196,10 +2145,7 @@ out_movsi_r_mr (insn, op, l)
 }
 
 const char *
-out_movsi_mr_r (insn, op, l)
-     rtx insn;
-     rtx op[];
-     int *l;
+out_movsi_mr_r (rtx insn, rtx op[], int *l)
 {
   rtx dest = op[0];
   rtx src = op[1];
@@ -2354,10 +2300,7 @@ out_movsi_mr_r (insn, op, l)
 }
 
 const char *
-output_movsisf(insn, operands, l)
-     rtx insn;
-     rtx operands[];
-     int *l;
+output_movsisf(rtx insn, rtx operands[], int *l)
 {
   int dummy;
   rtx dest = operands[0];
@@ -2373,7 +2316,7 @@ output_movsisf(insn, operands, l)
        {
          if (true_regnum (dest) > true_regnum (src))
            {
-             if (AVR_ENHANCED)
+             if (AVR_HAVE_MOVW)
                {
                  *l = 2;
                  return (AS2 (movw,%C0,%C1) CR_TAB
@@ -2387,7 +2330,7 @@ output_movsisf(insn, operands, l)
            }
          else
            {
-             if (AVR_ENHANCED)
+             if (AVR_HAVE_MOVW)
                {
                  *l = 2;
                  return (AS2 (movw,%A0,%A1) CR_TAB
@@ -2414,7 +2357,7 @@ output_movsisf(insn, operands, 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
@@ -2424,20 +2367,20 @@ output_movsisf(insn, operands, 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
@@ -2458,7 +2401,7 @@ output_movsisf(insn, operands, 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);
@@ -2508,10 +2451,7 @@ output_movsisf(insn, operands, l)
 }
 
 const char *
-out_movqi_mr_r (insn, op, l)
-     rtx insn;
-     rtx op[];
-     int *l; /* instruction length */
+out_movqi_mr_r (rtx insn, rtx op[], int *l)
 {
   rtx dest = op[0];
   rtx src = op[1];
@@ -2586,17 +2526,18 @@ out_movqi_mr_r (insn, op, l)
 }
 
 const char *
-out_movhi_mr_r (insn, op, l)
-     rtx insn;
-     rtx op[];
-     int *l;
+out_movhi_mr_r (rtx insn, rtx op[], int *l)
 {
   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);
+  /* "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))
@@ -2616,33 +2557,33 @@ out_movhi_mr_r (insn, op, 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)
     {
@@ -2655,14 +2596,14 @@ out_movhi_mr_r (insn, op, 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)));
        }
@@ -2670,39 +2611,61 @@ out_movhi_mr_r (insn, op, 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 "";
 }
 
-/* Return 1 if frame pointer for current function required */
+/* Return 1 if frame pointer for current function required */
 
 int
-frame_pointer_required_p ()
+frame_pointer_required_p (void)
 {
   return (current_function_calls_alloca
          || current_function_args_info.nregs == 0
@@ -2712,8 +2675,7 @@ frame_pointer_required_p ()
 /* Returns the condition of compare insn INSN, or UNKNOWN.  */
 
 static RTX_CODE
-compare_condition (insn)
-     rtx insn;
+compare_condition (rtx insn)
 {
   rtx next = next_real_insn (insn);
   RTX_CODE cond = UNKNOWN;
@@ -2730,8 +2692,7 @@ compare_condition (insn)
 /* Returns nonzero if INSN is a tst insn that only tests the sign.  */
 
 static int
-compare_sign_p (insn)
-     rtx insn;
+compare_sign_p (rtx insn)
 {
   RTX_CODE cond = compare_condition (insn);
   return (cond == GE || cond == LT);
@@ -2741,8 +2702,7 @@ compare_sign_p (insn)
    that needs to be swapped (GT, GTU, LE, LEU).  */
 
 int
-compare_diff_p (insn)
-     rtx insn;
+compare_diff_p (rtx insn)
 {
   RTX_CODE cond = compare_condition (insn);
   return (cond == GT || cond == GTU || cond == LE || cond == LEU) ? cond : 0;
@@ -2751,20 +2711,17 @@ compare_diff_p (insn)
 /* Returns nonzero if INSN is a compare insn with the EQ or NE condition.  */
 
 int
-compare_eq_p (insn)
-     rtx insn;
+compare_eq_p (rtx insn)
 {
   RTX_CODE cond = compare_condition (insn);
   return (cond == EQ || cond == NE);
 }
 
 
-/* Output test instruction for HImode */
+/* Output test instruction for HImode */
 
 const char *
-out_tsthi (insn, l)
-     rtx insn;
-     int *l;
+out_tsthi (rtx insn, int *l)
 {
   if (compare_sign_p (insn))
     {
@@ -2774,7 +2731,7 @@ out_tsthi (insn, l)
   if (reg_unused_after (insn, SET_SRC (PATTERN (insn)))
       && compare_eq_p (insn))
     {
-      /* faster than sbiw if we can clobber the operand */
+      /* Faster than sbiw if we can clobber the operand.  */
       if (l) *l = 1;
       return AS2 (or,%A0,%B0);
     }
@@ -2789,12 +2746,10 @@ out_tsthi (insn, l)
 }
 
 
-/* Output test instruction for SImode */
+/* Output test instruction for SImode */
 
 const char *
-out_tstsi (insn, l)
-     rtx insn;
-     int *l;
+out_tstsi (rtx insn, int *l)
 {
   if (compare_sign_p (insn))
     {
@@ -2822,12 +2777,8 @@ out_tstsi (insn, l)
    carefully hand-optimized in ?sh??i3_out.  */
 
 void
-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.  */
+out_shift_with_cnt (const char *template, rtx insn, rtx operands[],
+                   int *len, int t_len)
 {
   rtx op[10];
   char str[500];
@@ -2850,6 +2801,13 @@ out_shift_with_cnt (template, insn, operands, len, t_len)
       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;
 
@@ -2892,7 +2850,7 @@ out_shift_with_cnt (template, insn, operands, len, t_len)
          /* 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,
+         op[3] = gen_rtx_REG (QImode,
                           ((true_regnum (operands[0]) - 1) & 15) + 16);
          op[4] = tmp_reg_rtx;
          saved_in_tmp = 1;
@@ -2960,10 +2918,7 @@ out_shift_with_cnt (template, insn, operands, len, t_len)
 /* 8bit shift left ((char)x << i)   */
 
 const char *
-ashlqi3_out (insn, operands, len)
-     rtx insn;
-     rtx operands[];
-     int *len;                 /* insn length (may be NULL) */
+ashlqi3_out (rtx insn, rtx operands[], int *len)
 {
   if (GET_CODE (operands[2]) == CONST_INT)
     {
@@ -2975,6 +2930,9 @@ ashlqi3_out (insn, operands, len)
       switch (INTVAL (operands[2]))
        {
        default:
+         if (INTVAL (operands[2]) < 8)
+           break;
+
          *len = 1;
          return AS1 (clr,%0);
          
@@ -3057,10 +3015,7 @@ ashlqi3_out (insn, operands, len)
 /* 16bit shift left ((short)x << i)   */
 
 const char *
-ashlhi3_out (insn, operands, len)
-     rtx insn;
-     rtx operands[];
-     int *len;
+ashlhi3_out (rtx insn, rtx operands[], int *len)
 {
   if (GET_CODE (operands[2]) == CONST_INT)
     {
@@ -3074,6 +3029,14 @@ ashlhi3_out (insn, operands, 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 */
@@ -3153,11 +3116,8 @@ ashlhi3_out (insn, operands, 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;
@@ -3216,7 +3176,7 @@ ashlhi3_out (insn, operands, 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
@@ -3237,7 +3197,7 @@ ashlhi3_out (insn, operands, len)
                      AS2 (ldi,%3,0xe0) CR_TAB
                      AS2 (and,%B0,%3));
            }
-         if (AVR_ENHANCED)
+         if (AVR_HAVE_MUL)
            {
              *len = 6;
              return ("set"            CR_TAB
@@ -3257,7 +3217,7 @@ ashlhi3_out (insn, operands, 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
@@ -3266,7 +3226,7 @@ ashlhi3_out (insn, operands, 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
@@ -3313,10 +3273,7 @@ ashlhi3_out (insn, operands, len)
 /* 32bit shift left ((long)x << i)   */
 
 const char *
-ashlsi3_out (insn, operands, len)
-     rtx insn;
-     rtx operands[];
-     int *len;
+ashlsi3_out (rtx insn, rtx operands[], int *len)
 {
   if (GET_CODE (operands[2]) == CONST_INT)
     {
@@ -3328,6 +3285,20 @@ ashlsi3_out (insn, operands, 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]);
@@ -3338,11 +3309,6 @@ ashlsi3_out (insn, operands, 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
@@ -3354,46 +3320,26 @@ 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
-                     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;
@@ -3417,10 +3363,7 @@ ashlsi3_out (insn, operands, len)
 /* 8bit arithmetic shift right  ((signed char)x >> i) */
 
 const char *
-ashrqi3_out (insn, operands, len)
-     rtx insn;
-     rtx operands[];
-     int *len; /* insn length */
+ashrqi3_out (rtx insn, rtx operands[], int *len)
 {
   if (GET_CODE (operands[2]) == CONST_INT)
     {
@@ -3469,6 +3412,11 @@ ashrqi3_out (insn, operands, len)
                  AS2 (bld,%0,0));
 
        default:
+         if (INTVAL (operands[2]) < 8)
+           break;
+
+         /* fall through */
+
        case 7:
          *len = 2;
          return (AS1 (lsl,%0) CR_TAB
@@ -3487,10 +3435,7 @@ ashrqi3_out (insn, operands, len)
 /* 16bit arithmetic shift right  ((signed short)x >> i) */
 
 const char *
-ashrhi3_out (insn, operands, len)
-     rtx insn;
-     rtx operands[];
-     int *len;
+ashrhi3_out (rtx insn, rtx operands[], int *len)
 {
   if (GET_CODE (operands[2]) == CONST_INT)
     {
@@ -3538,15 +3483,11 @@ ashrhi3_out (insn, operands, 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:
@@ -3565,7 +3506,7 @@ ashrhi3_out (insn, operands, 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
@@ -3585,7 +3526,7 @@ ashrhi3_out (insn, operands, 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
@@ -3606,7 +3547,7 @@ ashrhi3_out (insn, operands, 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
@@ -3635,6 +3576,12 @@ ashrhi3_out (insn, operands, 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
@@ -3652,10 +3599,7 @@ ashrhi3_out (insn, operands, len)
 /* 32bit arithmetic shift right  ((signed long)x >> i) */
 
 const char *
-ashrsi3_out (insn, operands, len)
-     rtx insn;
-     rtx operands[];
-     int *len;
+ashrsi3_out (rtx insn, rtx operands[], int *len)
 {
   if (GET_CODE (operands[2]) == CONST_INT)
     {
@@ -3679,13 +3623,6 @@ ashrsi3_out (insn, operands, 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
@@ -3699,54 +3636,43 @@ 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
-                     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
@@ -3771,10 +3697,7 @@ ashrsi3_out (insn, operands, len)
 /* 8bit logic shift right ((unsigned char)x >> i) */
 
 const char *
-lshrqi3_out (insn, operands, len)
-     rtx insn;
-     rtx operands[];
-     int *len;
+lshrqi3_out (rtx insn, rtx operands[], int *len)
 {
   if (GET_CODE (operands[2]) == CONST_INT)
     {
@@ -3786,6 +3709,9 @@ lshrqi3_out (insn, operands, len)
       switch (INTVAL (operands[2]))
        {
        default:
+         if (INTVAL (operands[2]) < 8)
+           break;
+
          *len = 1;
          return AS1 (clr,%0);
 
@@ -3866,10 +3792,7 @@ lshrqi3_out (insn, operands, len)
 /* 16bit logic shift right ((unsigned short)x >> i) */
 
 const char *
-lshrhi3_out (insn, operands, len)
-     rtx insn;
-     rtx operands[];
-     int *len;
+lshrhi3_out (rtx insn, rtx operands[], int *len)
 {
   if (GET_CODE (operands[2]) == CONST_INT)
     {
@@ -3883,6 +3806,14 @@ lshrhi3_out (insn, operands, 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 */
@@ -3962,11 +3893,8 @@ lshrhi3_out (insn, operands, 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;
@@ -4025,7 +3953,7 @@ lshrhi3_out (insn, operands, 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
@@ -4046,7 +3974,7 @@ lshrhi3_out (insn, operands, len)
                      AS2 (ldi,%3,0x07) CR_TAB
                      AS2 (and,%A0,%3));
            }
-         if (AVR_ENHANCED)
+         if (AVR_HAVE_MUL)
            {
              *len = 6;
              return ("set"            CR_TAB
@@ -4066,7 +3994,7 @@ lshrhi3_out (insn, operands, 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
@@ -4075,7 +4003,7 @@ lshrhi3_out (insn, operands, 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
@@ -4121,10 +4049,7 @@ lshrhi3_out (insn, operands, len)
 /* 32bit logic shift right ((unsigned int)x >> i) */
 
 const char *
-lshrsi3_out (insn, operands, len)
-     rtx insn;
-     rtx operands[];
-     int *len;
+lshrsi3_out (rtx insn, rtx operands[], int *len)
 {
   if (GET_CODE (operands[2]) == CONST_INT)
     {
@@ -4136,6 +4061,20 @@ lshrsi3_out (insn, operands, 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]);
@@ -4146,8 +4085,6 @@ lshrsi3_out (insn, operands, 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
@@ -4159,39 +4096,26 @@ 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
-                     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;
@@ -4216,9 +4140,7 @@ lshrsi3_out (insn, operands, len)
  LEN is the initially computed length of the insn.  */
 
 int
-adjust_insn_length (insn, len)
-     rtx insn;
-     int len;
+adjust_insn_length (rtx insn, int len)
 {
   rtx patt = PATTERN (insn);
   rtx set;
@@ -4363,12 +4285,10 @@ adjust_insn_length (insn, len)
   return len;
 }
 
-/* Return nonzero if register REG dead after INSN */
+/* Return nonzero if register REG dead after INSN */
 
 int
-reg_unused_after (insn, reg)
-     rtx insn;
-     rtx reg;
+reg_unused_after (rtx insn, rtx reg)
 {
   return (dead_or_set_p (insn, reg)
          || (REG_P(reg) && _reg_unused_after (insn, reg)));
@@ -4379,9 +4299,7 @@ reg_unused_after (insn, reg)
    not live past labels.  It may live past calls or jumps though.  */
 
 int
-_reg_unused_after (insn, reg)
-     rtx insn;
-     rtx reg;
+_reg_unused_after (rtx insn, rtx reg)
 {
   enum rtx_code code;
   rtx set;
@@ -4396,6 +4314,7 @@ _reg_unused_after (insn, reg)
 
   while ((insn = NEXT_INSN (insn)))
     {
+      rtx set;
       code = GET_CODE (insn);
 
 #if 0
@@ -4408,6 +4327,9 @@ _reg_unused_after (insn, reg)
       /* else */
 #endif
 
+      if (!INSN_P (insn))
+       continue;
+
       if (code == JUMP_INSN)
        return 0;
 
@@ -4465,17 +4387,14 @@ _reg_unused_after (insn, 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;
 }
@@ -4484,10 +4403,7 @@ _reg_unused_after (insn, reg)
    special handling for references to certain labels.  */
 
 static bool
-avr_assemble_integer (x, size, aligned_p)
-     rtx x;
-     unsigned int size;
-     int aligned_p;
+avr_assemble_integer (rtx x, unsigned int size, int aligned_p)
 {
   if (size == POINTER_SIZE / BITS_PER_UNIT && aligned_p
       && ((GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P (x))
@@ -4501,51 +4417,15 @@ avr_assemble_integer (x, size, aligned_p)
   return default_assemble_integer (x, size, aligned_p);
 }
 
-/* Sets section name for declaration DECL */
-  
-static void
-avr_unique_section (decl, reloc)
-     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)
    as well as more readable, especially for targets like the i386
    (where the only alternative is to output character sequences as
-   comma separated lists of numbers).   */
+   comma separated lists of numbers).  */
 
 void
-gas_output_limited_string(file, str)
-     FILE *file;
-     const char * str;
+gas_output_limited_string(FILE *file, const char *str)
 {
   const unsigned char *_limited_str = (unsigned char *) str;
   unsigned ch;
@@ -4578,10 +4458,7 @@ gas_output_limited_string(file, str)
    STRING_LIMIT) we output those using ASM_OUTPUT_LIMITED_STRING.  */
 
 void
-gas_output_ascii(file, str, length)
-     FILE * file;
-     const char * str;
-     size_t length;
+gas_output_ascii(FILE *file, const char *str, size_t length)
 {
   const unsigned char *_ascii_bytes = (const unsigned char *) str;
   const unsigned char *limit = _ascii_bytes + length;
@@ -4639,8 +4516,7 @@ gas_output_ascii(file, str, length)
    because registers of CLASS are needed for spill registers.  */
 
 enum reg_class
-class_likely_spilled_p (c)
-     int c;
+class_likely_spilled_p (int c)
 {
   return (c != ALL_REGS && c != ADDW_REGS);
 }
@@ -4668,12 +4544,10 @@ const struct attribute_spec avr_attribute_table[] =
 /* Handle a "progmem" attribute; arguments as in
    struct attribute_spec.handler.  */
 static tree
-avr_handle_progmem_attribute (node, name, args, flags, no_add_attrs)
-     tree *node;
-     tree name;
-     tree args ATTRIBUTE_UNUSED;
-     int flags ATTRIBUTE_UNUSED;
-     bool *no_add_attrs;
+avr_handle_progmem_attribute (tree *node, tree name,
+                             tree args ATTRIBUTE_UNUSED,
+                             int flags ATTRIBUTE_UNUSED,
+                             bool *no_add_attrs)
 {
   if (DECL_P (*node))
     {
@@ -4694,14 +4568,15 @@ avr_handle_progmem_attribute (node, name, args, flags, no_add_attrs)
        {
          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;
        }
     }
@@ -4711,20 +4586,45 @@ avr_handle_progmem_attribute (node, name, args, flags, no_add_attrs)
 
 /* Handle an attribute requiring a FUNCTION_DECL; arguments as in
    struct attribute_spec.handler.  */
+
 static tree
-avr_handle_fndecl_attribute (node, name, args, flags, no_add_attrs)
-     tree *node;
-     tree name;
-     tree args ATTRIBUTE_UNUSED;
-     int flags ATTRIBUTE_UNUSED;
-     bool *no_add_attrs;
+avr_handle_fndecl_attribute (tree *node, tree name,
+                            tree args ATTRIBUTE_UNUSED,
+                            int flags ATTRIBUTE_UNUSED,
+                            bool *no_add_attrs)
 {
   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;
 }
@@ -4733,8 +4633,7 @@ avr_handle_fndecl_attribute (node, name, args, flags, no_add_attrs)
    if found return 1, otherwise 0.  */
 
 int
-avr_progmem_p (decl)
-     tree decl;
+avr_progmem_p (tree decl, tree attributes)
 {
   tree a;
 
@@ -4742,7 +4641,7 @@ avr_progmem_p (decl)
     return 0;
 
   if (NULL_TREE
-      != lookup_attribute ("progmem", DECL_ATTRIBUTES (decl)))
+      != lookup_attribute ("progmem", attributes))
     return 1;
 
   a=decl;
@@ -4762,13 +4661,11 @@ avr_progmem_p (decl)
 /* Add the section attribute if the variable is in progmem.  */
 
 static void
-avr_insert_attributes (node, attributes)
-     tree node;
-     tree *attributes;
+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"),
@@ -4781,11 +4678,31 @@ avr_insert_attributes (node, 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 (decl, name, reloc)
-     tree decl;
-     const char *name;
-     int reloc;
+avr_section_type_flags (tree decl, const char *name, int reloc)
 {
   unsigned int flags = default_section_type_flags (decl, name, reloc);
 
@@ -4795,7 +4712,7 @@ avr_section_type_flags (decl, name, 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");
     }
 
@@ -4806,14 +4723,14 @@ avr_section_type_flags (decl, name, reloc)
    file.  */
 
 static void
-avr_file_start ()
+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);
@@ -4836,7 +4753,7 @@ avr_file_start ()
    appropriate text to go at the end of an assembler file.  */
 
 static void
-avr_file_end ()
+avr_file_end (void)
 {
   fputs ("/* File ", asm_out_file);
   output_quoted_string (asm_out_file, main_input_filename);
@@ -4856,7 +4773,7 @@ avr_file_end ()
    next register; and so on.  */
 
 void
-order_regs_for_local_alloc ()
+order_regs_for_local_alloc (void)
 {
   unsigned int i;
   static const int order_0[] = {
@@ -4904,123 +4821,564 @@ order_regs_for_local_alloc ()
       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 (X, code, outer_code)
-     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 (x, code, outer_code, total)
-     rtx x;
-     int code, 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)
        {
-         *total = cst;
-         return true;
+       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)
+       {
+       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 */
+/* Calculate the cost of a memory address */
 
 static int
-avr_address_cost (x)
-     rtx x;
+avr_address_cost (rtx x)
 {
   if (GET_CODE (x) == PLUS
       && GET_CODE (XEXP (x,1)) == CONST_INT
@@ -5036,59 +5394,43 @@ avr_address_cost (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 (x, c)
-     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;
 }
 
-/* Convert condition code CONDITION to the valid AVR condition code */
+/* Convert condition code CONDITION to the valid AVR condition code */
 
 RTX_CODE
-avr_normalize_condition (condition)
-     RTX_CODE condition;
+avr_normalize_condition (RTX_CODE condition)
 {
   switch (condition)
     {
@@ -5101,14 +5443,14 @@ avr_normalize_condition (condition)
     case LEU:
       return LTU;
     default:
-      abort ();
+      gcc_unreachable ();
     }
 }
 
 /* This function optimizes conditional jumps.  */
 
 static void
-avr_reorg ()
+avr_reorg (void)
 {
   rtx insn, pattern;
   
@@ -5130,7 +5472,7 @@ avr_reorg ()
        {
          if (GET_CODE (SET_SRC (pattern)) == COMPARE)
            {
-             /* Now we work under compare insn */
+             /* Now we work under compare insn */
              
              pattern = SET_SRC (pattern);
              if (true_regnum (XEXP (pattern,0)) >= 0
@@ -5174,9 +5516,8 @@ avr_reorg ()
              rtx t = XEXP (src,0);
 
              PUT_CODE (t, swap_condition (GET_CODE (t)));
-             SET_SRC (pattern) = gen_rtx (NEG,
-                                          GET_MODE (SET_SRC (pattern)),
-                                          SET_SRC (pattern));
+             SET_SRC (pattern) = gen_rtx_NEG (GET_MODE (SET_SRC (pattern)),
+                                              SET_SRC (pattern));
              INSN_CODE (next) = -1;
              INSN_CODE (insn) = -1;
            }
@@ -5187,31 +5528,28 @@ avr_reorg ()
 /* Returns register number for function return value.*/
 
 int
-avr_ret_register ()
+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
-avr_libcall_value (mode)
-     enum machine_mode mode;
+avr_libcall_value (enum machine_mode mode)
 {
   int offs = GET_MODE_SIZE (mode);
   if (offs < 2)
     offs = 2;
-  return gen_rtx (REG, mode, RET_REGISTER + 2 - offs);
+  return gen_rtx_REG (mode, RET_REGISTER + 2 - offs);
 }
 
 /* Create an RTX representing the place where a
    function returns a value of data type VALTYPE.  */
 
 rtx
-avr_function_value (type, func)
-     tree type;
-     tree func ATTRIBUTE_UNUSED;
+avr_function_value (tree type, tree func ATTRIBUTE_UNUSED)
 {
   unsigned int offs;
   
@@ -5226,48 +5564,21 @@ avr_function_value (type, func)
   else if (offs > GET_MODE_SIZE (SImode) && offs < GET_MODE_SIZE (DImode))
     offs = GET_MODE_SIZE (DImode);
   
-  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 (mask)
-     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; 
+  return gen_rtx_REG (BLKmode, RET_REGISTER + 2 - offs);
 }
 
-
 /* Places additional restrictions on the register class to
    use when it is necessary to copy value X into a register
    in class CLASS.  */
 
 enum reg_class
-preferred_reload_class (x, class)
-     rtx x ATTRIBUTE_UNUSED;
-     enum reg_class class;
+preferred_reload_class (rtx x ATTRIBUTE_UNUSED, enum reg_class class)
 {
   return class;
 }
 
 int
-test_hard_reg_class (class, x)
-     enum reg_class class;
-     rtx x;
+test_hard_reg_class (enum reg_class class, rtx x)
 {
   int regno = true_regnum (x);
   if (regno < 0)
@@ -5281,9 +5592,7 @@ test_hard_reg_class (class, x)
 
 
 int
-jump_over_one_insn_p (insn, dest)
-     rtx insn;
-     rtx dest;
+jump_over_one_insn_p (rtx insn, rtx dest)
 {
   int uid = INSN_UID (GET_CODE (dest) == LABEL_REF
                      ? XEXP (dest, 0)
@@ -5299,21 +5608,24 @@ jump_over_one_insn_p (insn, dest)
    (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;
+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);
 }
 
@@ -5322,34 +5634,14 @@ avr_hard_regno_mode_ok (regno, mode)
    to check for the lower half of I/O space (for cbi/sbi/sbic/sbis).  */
 
 int
-avr_io_address_p (x, size)
-     rtx x;
-     int size;
+avr_io_address_p (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;
+output_reload_inhi (rtx insn ATTRIBUTE_UNUSED, rtx *operands, int *len)
 {
   int tmp;
   if (!len)
@@ -5389,10 +5681,7 @@ output_reload_inhi (insn, operands, len)
 
 
 const char *
-output_reload_insisf (insn, operands, len)
-     rtx insn ATTRIBUTE_UNUSED;
-     rtx *operands;
-     int *len;
+output_reload_insisf (rtx insn ATTRIBUTE_UNUSED, rtx *operands, int *len)
 {
   rtx src = operands[1];
   int cnst = (GET_CODE (src) == CONST_INT);
@@ -5442,9 +5731,7 @@ output_reload_insisf (insn, operands, len)
 }
 
 void
-avr_output_bld (operands, bit_nr)
-     rtx operands[];
-     int bit_nr;
+avr_output_bld (rtx operands[], int bit_nr)
 {
   static char s[] = "bld %A0,0";
 
@@ -5454,10 +5741,9 @@ avr_output_bld (operands, bit_nr)
 }
 
 void
-avr_output_addr_vec_elt (stream, value)
-     FILE *stream;
-     int value;
+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
@@ -5470,8 +5756,7 @@ avr_output_addr_vec_elt (stream, value)
    registers (for a define_peephole2) in the current function.  */
 
 int
-avr_peep2_scratch_safe (scratch)
-     rtx scratch;
+avr_peep2_scratch_safe (rtx scratch)
 {
   if ((interrupt_function_p (current_function_decl)
        || signal_function_p (current_function_decl))
@@ -5499,9 +5784,7 @@ avr_peep2_scratch_safe (scratch)
    Operand 3: label to jump to if the test is true.  */
 
 const char *
-avr_out_sbxx_branch (insn, operands)
-     rtx insn;
-     rtx operands[];
+avr_out_sbxx_branch (rtx insn, rtx operands[])
 {
   enum rtx_code comp = GET_CODE (operands[0]);
   int long_jump = (get_attr_length (insn) >= 4);
@@ -5563,21 +5846,36 @@ avr_out_sbxx_branch (insn, operands)
   return "";
 }
 
+/* Worker function for TARGET_ASM_CONSTRUCTOR.  */
+
 static void
-avr_asm_out_ctor (symbol, priority)
-     rtx symbol;
-     int priority;
+avr_asm_out_ctor (rtx symbol, int priority)
 {
   fputs ("\t.global __do_global_ctors\n", asm_out_file);
   default_ctor_section_asm_out_constructor (symbol, priority);
 }
 
+/* Worker function for TARGET_ASM_DESTRUCTOR.  */
+
 static void
-avr_asm_out_dtor (symbol, priority)
-     rtx symbol;
-     int priority;
+avr_asm_out_dtor (rtx symbol, int priority)
 {
   fputs ("\t.global __do_global_dtors\n", asm_out_file);
   default_dtor_section_asm_out_destructor (symbol, priority);
 }
 
+/* Worker function for TARGET_RETURN_IN_MEMORY.  */
+
+static bool
+avr_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
+{
+  if (TYPE_MODE (type) == BLKmode)
+    {
+      HOST_WIDE_INT size = int_size_in_bytes (type);
+      return (size == -1 || size > 8);
+    }
+  else
+    return false;
+}
+
+#include "gt-avr.h"