]> oss.titaniummirror.com Git - msp430-gcc.git/blobdiff - gcc/config/avr/avr.c
Imported gcc-4.4.3
[msp430-gcc.git] / gcc / config / avr / avr.c
index a3c48a8b111c27c42d8883ee21ac84ff08474da2..79607c3d9b32d6eb6ce02250cd86f9669fa975fa 100644 (file)
 /* 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, 2008,
+   2009 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)
+   the Free Software Foundation; either version 3, 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 COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "rtl.h"
 #include "regs.h"
 #include "hard-reg-set.h"
 #include "real.h"
 #include "insn-config.h"
 #include "conditions.h"
-#include "output.h"
 #include "insn-attr.h"
 #include "flags.h"
 #include "reload.h"
 #include "tree.h"
+#include "output.h"
 #include "expr.h"
 #include "toplev.h"
 #include "obstack.h"
 #include "function.h"
 #include "recog.h"
+#include "ggc.h"
 #include "tm_p.h"
 #include "target.h"
 #include "target-def.h"
+#include "params.h"
+#include "df.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    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 int    reg_was_0            PARAMS ((rtx insn, rtx op));
-static int    io_address_p         PARAMS ((rtx x, int size));
-void          debug_hard_reg_set   PARAMS ((HARD_REG_SET set));
-static 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_OS_task_function_p (tree);
+static int avr_OS_main_function_p (tree);
+static int avr_regs_to_save (HARD_REG_SET *);
+static int get_sequence_length (rtx insns);
+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 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 *);
+static tree avr_handle_fntype_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_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));
-static void   avr_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
-
-/* Allocate registers from r25 to r8 for parameters for function calls */
+static bool avr_assemble_integer (rtx, unsigned int, int);
+static void avr_file_start (void);
+static void avr_file_end (void);
+static void avr_asm_function_end_prologue (FILE *);
+static void avr_asm_function_begin_epilogue (FILE *);
+static rtx avr_function_value (const_tree, const_tree, bool);
+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, bool);
+static bool avr_rtx_costs (rtx, int, int, int *, bool);
+static int avr_address_cost (rtx, bool);
+static bool avr_return_in_memory (const_tree, const_tree);
+static struct machine_function * avr_init_machine_status (void);
+static rtx avr_builtin_setjmp_frame_value (void);
+static bool avr_hard_regno_scratch_ok (unsigned int);
+
+/* 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;
-
-/* Zeroed register RTX (gen_rtx (REG,QImode,ZERO_REGNO)) */
-rtx zero_reg_rtx;
+/* Temporary register RTX (gen_rtx_REG (QImode, TMP_REGNO)) */
+static GTY(()) rtx tmp_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;
@@ -84,45 +103,51 @@ static const char *const avr_regnames[] = REGISTER_NAMES;
 /* This holds the last insn address.  */
 static int last_insn_address = 0;
 
-/* Commands count in the compiled file */
-static int commands_in_file;
-
-/* Commands in the functions prologues in the compiled file */
-static int commands_in_prologues;
-
-/* Commands in the functions epilogues in the compiled file */
-static int commands_in_epilogues;
-
-/* Prologue/Epilogue size in words */
-static int prologue_size;
-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";
-
-/* More than 8K of program memory: use "call" and "jmp".  */
-int avr_mega_p = 0;
+/* Preprocessor macros to define depending on MCU type.  */
+const char *avr_extra_arch_macro;
+
+/* Current architecture.  */
+const struct base_arch_s *avr_current_arch;
+
+section *progmem_section;
+
+static const struct base_arch_s avr_arch_types[] = {
+  { 1, 0, 0, 0, 0, 0, 0, 0, NULL },  /* unknown device specified */
+  { 1, 0, 0, 0, 0, 0, 0, 0, "__AVR_ARCH__=1"   },
+  { 0, 0, 0, 0, 0, 0, 0, 0, "__AVR_ARCH__=2"   },
+  { 0, 0, 0, 1, 0, 0, 0, 0, "__AVR_ARCH__=25"  },
+  { 0, 0, 1, 0, 0, 0, 0, 0, "__AVR_ARCH__=3"   },
+  { 0, 0, 1, 0, 1, 0, 0, 0, "__AVR_ARCH__=31"  },
+  { 0, 0, 1, 1, 0, 0, 0, 0, "__AVR_ARCH__=35"  },
+  { 0, 1, 0, 1, 0, 0, 0, 0, "__AVR_ARCH__=4"   },
+  { 0, 1, 1, 1, 0, 0, 0, 0, "__AVR_ARCH__=5"   },
+  { 0, 1, 1, 1, 1, 1, 0, 0, "__AVR_ARCH__=51"  },
+  { 0, 1, 1, 1, 1, 1, 1, 0, "__AVR_ARCH__=6"   }
+};
 
-/* Enhanced core: use "movw", "mul", ...  */
-int avr_enhanced_p = 0;
+/* These names are used as the index into the avr_arch_types[] table 
+   above.  */
 
-enum avr_arch {
-  AVR1 = 1,
-  AVR2,
-  AVR3,
-  AVR4,
-  AVR5
+enum avr_arch
+{
+  ARCH_UNKNOWN,
+  ARCH_AVR1,
+  ARCH_AVR2,
+  ARCH_AVR25,
+  ARCH_AVR3,
+  ARCH_AVR31,
+  ARCH_AVR35,
+  ARCH_AVR4,
+  ARCH_AVR5,
+  ARCH_AVR51,
+  ARCH_AVR6
 };
 
 struct mcu_type_s {
   const char *const name;
-  const enum avr_arch arch;
+  int arch;  /* index in avr_arch_types[] */
+  /* Must lie outside user's namespace.  NULL == no macro.  */
+  const char *const macro;
 };
 
 /* List of all known AVR MCU types - if updated, it has to be kept
@@ -135,49 +160,152 @@ struct mcu_type_s {
 
 static const struct mcu_type_s avr_mcu_types[] = {
     /* Classic, <= 8K.  */
-  { "avr2",      AVR2 },
-  { "at90s2313", AVR2 },
-  { "at90s2323", AVR2 },
-  { "attiny22",  AVR2 },
-  { "at90s2333", AVR2 },
-  { "at90s2343", AVR2 },
-  { "at90s4414", AVR2 },
-  { "at90s4433", AVR2 },
-  { "at90s4434", AVR2 },
-  { "at90s8515", AVR2 },
-  { "at90c8534", AVR2 },
-  { "at90s8535", AVR2 },
-    /* Classic, > 8K.  */
-  { "avr3",      AVR3 },
-  { "atmega103", AVR3 },
-  { "atmega603", AVR3 },
-  { "at43usb320", AVR3 },
-  { "at76c711",  AVR3 },
+  { "avr2",         ARCH_AVR2, NULL },
+  { "at90s2313",    ARCH_AVR2, "__AVR_AT90S2313__" },
+  { "at90s2323",    ARCH_AVR2, "__AVR_AT90S2323__" },
+  { "at90s2333",    ARCH_AVR2, "__AVR_AT90S2333__" },
+  { "at90s2343",    ARCH_AVR2, "__AVR_AT90S2343__" },
+  { "attiny22",     ARCH_AVR2, "__AVR_ATtiny22__" },
+  { "attiny26",     ARCH_AVR2, "__AVR_ATtiny26__" },
+  { "at90s4414",    ARCH_AVR2, "__AVR_AT90S4414__" },
+  { "at90s4433",    ARCH_AVR2, "__AVR_AT90S4433__" },
+  { "at90s4434",    ARCH_AVR2, "__AVR_AT90S4434__" },
+  { "at90s8515",    ARCH_AVR2, "__AVR_AT90S8515__" },
+  { "at90c8534",    ARCH_AVR2, "__AVR_AT90C8534__" },
+  { "at90s8535",    ARCH_AVR2, "__AVR_AT90S8535__" },
+    /* Classic + MOVW, <= 8K.  */
+  { "avr25",        ARCH_AVR25, NULL },
+  { "ata6289",      ARCH_AVR25, "__AVR_ATA6289__" },
+  { "attiny13",     ARCH_AVR25, "__AVR_ATtiny13__" },
+  { "attiny13a",    ARCH_AVR25, "__AVR_ATtiny13A__" },
+  { "attiny2313",   ARCH_AVR25, "__AVR_ATtiny2313__" },
+  { "attiny24",     ARCH_AVR25, "__AVR_ATtiny24__" },
+  { "attiny44",     ARCH_AVR25, "__AVR_ATtiny44__" },
+  { "attiny84",     ARCH_AVR25, "__AVR_ATtiny84__" },
+  { "attiny25",     ARCH_AVR25, "__AVR_ATtiny25__" },
+  { "attiny45",     ARCH_AVR25, "__AVR_ATtiny45__" },
+  { "attiny85",     ARCH_AVR25, "__AVR_ATtiny85__" },
+  { "attiny261",    ARCH_AVR25, "__AVR_ATtiny261__" },
+  { "attiny461",    ARCH_AVR25, "__AVR_ATtiny461__" },
+  { "attiny861",    ARCH_AVR25, "__AVR_ATtiny861__" },
+  { "attiny43u",    ARCH_AVR25, "__AVR_ATtiny43U__" },
+  { "attiny87",     ARCH_AVR25, "__AVR_ATtiny87__" },
+  { "attiny48",     ARCH_AVR25, "__AVR_ATtiny48__" },
+  { "attiny88",     ARCH_AVR25, "__AVR_ATtiny88__" },
+  { "at86rf401",    ARCH_AVR25, "__AVR_AT86RF401__" },
+    /* Classic, > 8K, <= 64K.  */
+  { "avr3",         ARCH_AVR3, NULL },
+  { "at43usb355",   ARCH_AVR3, "__AVR_AT43USB355__" },
+  { "at76c711",     ARCH_AVR3, "__AVR_AT76C711__" },
+    /* Classic, == 128K.  */
+  { "avr31",        ARCH_AVR31, NULL },
+  { "atmega103",    ARCH_AVR31, "__AVR_ATmega103__" },
+  { "at43usb320",   ARCH_AVR31, "__AVR_AT43USB320__" },
+    /* Classic + MOVW + JMP/CALL.  */
+  { "avr35",        ARCH_AVR35, NULL },
+  { "at90usb82",    ARCH_AVR35, "__AVR_AT90USB82__" },
+  { "at90usb162",   ARCH_AVR35, "__AVR_AT90USB162__" },
+  { "attiny167",    ARCH_AVR35, "__AVR_ATtiny167__" },
+  { "attiny327",    ARCH_AVR35, "__AVR_ATtiny327__" },
     /* Enhanced, <= 8K.  */
-  { "avr4",      AVR4 },
-  { "atmega8",   AVR4 },
-  { "atmega83",  AVR4 },
-  { "atmega85",  AVR4 },
-    /* Enhanced, > 8K.  */
-  { "avr5",      AVR5 },
-  { "atmega16",  AVR5 },
-  { "atmega161", AVR5 },
-  { "atmega163", AVR5 },
-  { "atmega32",  AVR5 },
-  { "atmega323", AVR5 },
-  { "atmega64",  AVR5 },
-  { "atmega128", AVR5 },
-  { "at43usb355", AVR5 },
-  { "at94k",     AVR5 },
+  { "avr4",         ARCH_AVR4, NULL },
+  { "atmega8",      ARCH_AVR4, "__AVR_ATmega8__" },
+  { "atmega48",     ARCH_AVR4, "__AVR_ATmega48__" },
+  { "atmega48p",    ARCH_AVR4, "__AVR_ATmega48P__" },
+  { "atmega88",     ARCH_AVR4, "__AVR_ATmega88__" },
+  { "atmega88p",    ARCH_AVR4, "__AVR_ATmega88P__" },
+  { "atmega8515",   ARCH_AVR4, "__AVR_ATmega8515__" },
+  { "atmega8535",   ARCH_AVR4, "__AVR_ATmega8535__" },
+  { "atmega8hva",   ARCH_AVR4, "__AVR_ATmega8HVA__" },
+  { "atmega4hvd",   ARCH_AVR4, "__AVR_ATmega4HVD__" },
+  { "atmega8hvd",   ARCH_AVR4, "__AVR_ATmega8HVD__" },
+  { "atmega8c1",    ARCH_AVR4, "__AVR_ATmega8C1__" },
+  { "atmega8m1",    ARCH_AVR4, "__AVR_ATmega8M1__" },
+  { "at90pwm1",     ARCH_AVR4, "__AVR_AT90PWM1__" },
+  { "at90pwm2",     ARCH_AVR4, "__AVR_AT90PWM2__" },
+  { "at90pwm2b",    ARCH_AVR4, "__AVR_AT90PWM2B__" },
+  { "at90pwm3",     ARCH_AVR4, "__AVR_AT90PWM3__" },
+  { "at90pwm3b",    ARCH_AVR4, "__AVR_AT90PWM3B__" },
+  { "at90pwm81",    ARCH_AVR4, "__AVR_AT90PWM81__" },
+    /* Enhanced, > 8K, <= 64K.  */
+  { "avr5",         ARCH_AVR5, NULL },
+  { "atmega16",     ARCH_AVR5, "__AVR_ATmega16__" },
+  { "atmega161",    ARCH_AVR5, "__AVR_ATmega161__" },
+  { "atmega162",    ARCH_AVR5, "__AVR_ATmega162__" },
+  { "atmega163",    ARCH_AVR5, "__AVR_ATmega163__" },
+  { "atmega164p",   ARCH_AVR5, "__AVR_ATmega164P__" },
+  { "atmega165",    ARCH_AVR5, "__AVR_ATmega165__" },
+  { "atmega165p",   ARCH_AVR5, "__AVR_ATmega165P__" },
+  { "atmega168",    ARCH_AVR5, "__AVR_ATmega168__" },
+  { "atmega168p",   ARCH_AVR5, "__AVR_ATmega168P__" },
+  { "atmega169",    ARCH_AVR5, "__AVR_ATmega169__" },
+  { "atmega169p",   ARCH_AVR5, "__AVR_ATmega169P__" },
+  { "atmega32",     ARCH_AVR5, "__AVR_ATmega32__" },
+  { "atmega323",    ARCH_AVR5, "__AVR_ATmega323__" },
+  { "atmega324p",   ARCH_AVR5, "__AVR_ATmega324P__" },
+  { "atmega325",    ARCH_AVR5, "__AVR_ATmega325__" },
+  { "atmega325p",   ARCH_AVR5, "__AVR_ATmega325P__" },
+  { "atmega3250",   ARCH_AVR5, "__AVR_ATmega3250__" },
+  { "atmega3250p",  ARCH_AVR5, "__AVR_ATmega3250P__" },
+  { "atmega328p",   ARCH_AVR5, "__AVR_ATmega328P__" },
+  { "atmega329",    ARCH_AVR5, "__AVR_ATmega329__" },
+  { "atmega329p",   ARCH_AVR5, "__AVR_ATmega329P__" },
+  { "atmega3290",   ARCH_AVR5, "__AVR_ATmega3290__" },
+  { "atmega3290p",  ARCH_AVR5, "__AVR_ATmega3290P__" },
+  { "atmega406",    ARCH_AVR5, "__AVR_ATmega406__" },
+  { "atmega64",     ARCH_AVR5, "__AVR_ATmega64__" },
+  { "atmega640",    ARCH_AVR5, "__AVR_ATmega640__" },
+  { "atmega644",    ARCH_AVR5, "__AVR_ATmega644__" },
+  { "atmega644p",   ARCH_AVR5, "__AVR_ATmega644P__" },
+  { "atmega645",    ARCH_AVR5, "__AVR_ATmega645__" },
+  { "atmega6450",   ARCH_AVR5, "__AVR_ATmega6450__" },
+  { "atmega649",    ARCH_AVR5, "__AVR_ATmega649__" },
+  { "atmega6490",   ARCH_AVR5, "__AVR_ATmega6490__" },
+  { "atmega16hva",  ARCH_AVR5, "__AVR_ATmega16HVA__" },
+  { "atmega16hvb",  ARCH_AVR5, "__AVR_ATmega16HVB__" },
+  { "atmega32hvb",  ARCH_AVR5, "__AVR_ATmega32HVB__" },
+  { "at90can32",    ARCH_AVR5, "__AVR_AT90CAN32__" },
+  { "at90can64",    ARCH_AVR5, "__AVR_AT90CAN64__" },
+  { "at90pwm216",   ARCH_AVR5, "__AVR_AT90PWM216__" },
+  { "at90pwm316",   ARCH_AVR5, "__AVR_AT90PWM316__" },
+  { "atmega16c1",   ARCH_AVR5, "__AVR_ATmega16C1__" },
+  { "atmega32c1",   ARCH_AVR5, "__AVR_ATmega32C1__" },
+  { "atmega64c1",   ARCH_AVR5, "__AVR_ATmega64C1__" },
+  { "atmega16m1",   ARCH_AVR5, "__AVR_ATmega16M1__" },
+  { "atmega32m1",   ARCH_AVR5, "__AVR_ATmega32M1__" },
+  { "atmega64m1",   ARCH_AVR5, "__AVR_ATmega64M1__" },
+  { "atmega16u4",   ARCH_AVR5, "__AVR_ATmega16U4__" },
+  { "atmega32u4",   ARCH_AVR5, "__AVR_ATmega32U4__" },
+  { "atmega32u6",   ARCH_AVR5, "__AVR_ATmega32U6__" },
+  { "at90scr100",   ARCH_AVR5, "__AVR_AT90SCR100__" },
+  { "at90usb646",   ARCH_AVR5, "__AVR_AT90USB646__" },
+  { "at90usb647",   ARCH_AVR5, "__AVR_AT90USB647__" },
+  { "at94k",        ARCH_AVR5, "__AVR_AT94K__" },
+    /* Enhanced, == 128K.  */
+  { "avr51",        ARCH_AVR51, NULL },
+  { "atmega128",    ARCH_AVR51, "__AVR_ATmega128__" },
+  { "atmega1280",   ARCH_AVR51, "__AVR_ATmega1280__" },
+  { "atmega1281",   ARCH_AVR51, "__AVR_ATmega1281__" },
+  { "atmega1284p",  ARCH_AVR51, "__AVR_ATmega1284P__" },
+  { "atmega128rfa1",  ARCH_AVR51, "__AVR_ATmega128RFA1__" },
+  { "at90can128",   ARCH_AVR51, "__AVR_AT90CAN128__" },
+  { "at90usb1286",  ARCH_AVR51, "__AVR_AT90USB1286__" },
+  { "at90usb1287",  ARCH_AVR51, "__AVR_AT90USB1287__" },
+  { "m3000f",       ARCH_AVR51, "__AVR_M3000F__" },
+  { "m3000s",       ARCH_AVR51, "__AVR_M3000S__" },
+  { "m3001b",       ARCH_AVR51, "__AVR_M3001B__" },
+    /* 3-Byte PC.  */
+  { "avr6",         ARCH_AVR6, NULL },
+  { "atmega2560",   ARCH_AVR6, "__AVR_ATmega2560__" },
+  { "atmega2561",   ARCH_AVR6, "__AVR_ATmega2561__" },
     /* Assembler only.  */
-  { "avr1",      AVR1 },
-  { "at90s1200", AVR1 },
-  { "attiny10",  AVR1 },
-  { "attiny11",  AVR1 },
-  { "attiny12",  AVR1 },
-  { "attiny15",  AVR1 },
-  { "attiny28",  AVR1 },
-  { NULL, 0 }
+  { "avr1",         ARCH_AVR1, NULL },
+  { "at90s1200",    ARCH_AVR1, "__AVR_AT90S1200__" },
+  { "attiny11",     ARCH_AVR1, "__AVR_ATtiny11__" },
+  { "attiny12",     ARCH_AVR1, "__AVR_ATtiny12__" },
+  { "attiny15",     ARCH_AVR1, "__AVR_ATtiny15__" },
+  { "attiny28",     ARCH_AVR1, "__AVR_ATtiny28__" },
+  { NULL,           ARCH_UNKNOWN, NULL }
 };
 
 int avr_case_values_threshold = 30000;
@@ -185,22 +313,66 @@ 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_FUNCTION_PROLOGUE
-#define TARGET_ASM_FUNCTION_PROLOGUE avr_output_function_prologue
-#undef TARGET_ASM_FUNCTION_EPILOGUE
-#define TARGET_ASM_FUNCTION_EPILOGUE avr_output_function_epilogue
+#undef TARGET_ASM_FILE_START
+#define TARGET_ASM_FILE_START avr_file_start
+#undef TARGET_ASM_FILE_START_FILE_DIRECTIVE
+#define TARGET_ASM_FILE_START_FILE_DIRECTIVE true
+#undef TARGET_ASM_FILE_END
+#define TARGET_ASM_FILE_END avr_file_end
+
+#undef TARGET_ASM_FUNCTION_END_PROLOGUE
+#define TARGET_ASM_FUNCTION_END_PROLOGUE avr_asm_function_end_prologue
+#undef TARGET_ASM_FUNCTION_BEGIN_EPILOGUE
+#define TARGET_ASM_FUNCTION_BEGIN_EPILOGUE avr_asm_function_begin_epilogue
+#undef TARGET_FUNCTION_VALUE
+#define TARGET_FUNCTION_VALUE avr_function_value
 #undef TARGET_ATTRIBUTE_TABLE
 #define TARGET_ATTRIBUTE_TABLE avr_attribute_table
+#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
+#define TARGET_SECTION_TYPE_FLAGS avr_section_type_flags
+#undef TARGET_RTX_COSTS
+#define TARGET_RTX_COSTS avr_rtx_costs
+#undef TARGET_ADDRESS_COST
+#define TARGET_ADDRESS_COST avr_address_cost
+#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
+
+#undef TARGET_BUILTIN_SETJMP_FRAME_VALUE
+#define TARGET_BUILTIN_SETJMP_FRAME_VALUE avr_builtin_setjmp_frame_value
+
+#undef TARGET_HARD_REGNO_SCRATCH_OK
+#define TARGET_HARD_REGNO_SCRATCH_OK avr_hard_regno_scratch_ok
 
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 void
-avr_override_options ()
+avr_override_options (void)
 {
   const struct mcu_type_s *t;
+  static bool warned_no_tablejump_deprecated = false;
+
+  flag_delete_null_pointer_checks = 0;
+
+  if (!PARAM_SET_P (PARAM_INLINE_CALL_COST))
+    set_param_value ("inline-call-cost", 5);
 
   for (t = avr_mcu_types; t->name; t++)
     if (strcmp (t->name, avr_mcu_name) == 0)
@@ -208,53 +380,35 @@ 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);
     }
 
-  switch (t->arch)
-    {
-    case AVR1:
-    default:
-      error ("MCU `%s' not supported", avr_mcu_name);
-      /* ... fall through ... */
-    case AVR2: avr_enhanced_p = 0; avr_mega_p = 0; break;
-    case AVR3: avr_enhanced_p = 0; avr_mega_p = 1; break;
-    case AVR4: avr_enhanced_p = 1; avr_mega_p = 0; break;
-    case AVR5: avr_enhanced_p = 1; avr_mega_p = 1; break;
-    }
+  avr_current_arch = &avr_arch_types[t->arch];
+  avr_extra_arch_macro = t->macro;
 
   if (optimize && !TARGET_NO_TABLEJUMP)
-    avr_case_values_threshold = (!AVR_MEGA || TARGET_CALL_PROLOGUES) ? 8 : 17;
-}
+    avr_case_values_threshold = 
+      (!AVR_HAVE_JMP_CALL || TARGET_CALL_PROLOGUES) ? 8 : 17;
+
+  if (TARGET_NO_TABLEJUMP
+      && !warned_no_tablejump_deprecated)
+    {
+      inform (input_location, "the -mno-tablejump switch is deprecated");
+      inform (input_location, "GCC 4.4 is the last release with this switch");
+      inform (input_location, "use the -fno-jump-tables switch instead");
+      warned_no_tablejump_deprecated = true;
+    }
 
+  tmp_reg_rtx  = gen_rtx_REG (QImode, TMP_REGNO);
+  zero_reg_rtx = gen_rtx_REG (QImode, ZERO_REGNO);
 
-/* Initialize TMP_REG_RTX and ZERO_REG_RTX */
-void
-avr_init_once ()
-{
-  tmp_reg_rtx = xmalloc (sizeof (struct rtx_def) + 1 * sizeof (rtunion));
-  memset (tmp_reg_rtx, 0, sizeof (struct rtx_def) + 1 * sizeof (rtunion));
-  PUT_CODE (tmp_reg_rtx, REG);
-  PUT_MODE (tmp_reg_rtx, QImode);
-  XINT (tmp_reg_rtx, 0) = TMP_REGNO;
-
-  zero_reg_rtx = xmalloc (sizeof (struct rtx_def) + 1 * sizeof (rtunion));
-  memset (zero_reg_rtx, 0, 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 = xmalloc (sizeof (struct rtx_def) + 1 * sizeof (rtunion));
-  memset (ldi_reg_rtx, 0, sizeof (struct rtx_def) + 1 * sizeof (rtunion));
-  PUT_CODE (ldi_reg_rtx, REG);
-  PUT_MODE (ldi_reg_rtx, QImode);
-  XINT (ldi_reg_rtx, 0) = LDI_REG_REGNO;
+  init_machine_status = avr_init_machine_status;
 }
 
-/*  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,
@@ -270,59 +424,35 @@ static const int reg_class_tab[]={
   STACK_REG,STACK_REG           /* SPL,SPH */
 };
 
-/* Return register class for register R */
+/* Function to set up the backend function structure.  */
 
-enum reg_class
-avr_regno_reg_class (r)
-     int r;
+static struct machine_function *
+avr_init_machine_status (void)
 {
-  if (r <= 33)
-    return reg_class_tab[r];
-  return ALL_REGS;
+  return ((struct machine_function *) 
+          ggc_alloc_cleared (sizeof (struct machine_function)));
 }
 
-
-/* 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.  */
+/* Return register class for register R.  */
 
 enum reg_class
-avr_reg_class_from_letter  (c)
-     int c;
+avr_regno_reg_class (int r)
 {
-  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;
+  if (r <= 33)
+    return reg_class_tab[r];
+  return ALL_REGS;
 }
 
-/* Return non-zero if FUNC is a naked function.  */
+/* 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));
+  a = lookup_attribute ("naked", TYPE_ATTRIBUTES (TREE_TYPE (func)));
   return a != NULL_TREE;
 }
 
@@ -330,8 +460,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;
 
@@ -346,8 +475,7 @@ interrupt_function_p (func)
    by the "signal" attribute.  */
 
 static int
-signal_function_p (func)
-     tree func;
+signal_function_p (tree func)
 {
   tree a;
 
@@ -358,44 +486,123 @@ signal_function_p (func)
   return a != NULL_TREE;
 }
 
-/* Compute offset between arg_pointer and frame_pointer */
+/* Return nonzero if FUNC is a OS_task function.  */
+
+static int
+avr_OS_task_function_p (tree func)
+{
+  tree a;
+
+  gcc_assert (TREE_CODE (func) == FUNCTION_DECL);
+  
+  a = lookup_attribute ("OS_task", TYPE_ATTRIBUTES (TREE_TYPE (func)));
+  return a != NULL_TREE;
+}
+
+/* Return nonzero if FUNC is a OS_main function.  */
+
+static int
+avr_OS_main_function_p (tree func)
+{
+  tree a;
+
+  gcc_assert (TREE_CODE (func) == FUNCTION_DECL);
+  
+  a = lookup_attribute ("OS_main", TYPE_ATTRIBUTES (TREE_TYPE (func)));
+  return a != NULL_TREE;
+}
+
+/* Return the number of hard registers to push/pop in the prologue/epilogue
+   of the current function, and optionally store these registers in SET.  */
+
+static int
+avr_regs_to_save (HARD_REG_SET *set)
+{
+  int reg, count;
+  int int_or_sig_p = (interrupt_function_p (current_function_decl)
+                     || signal_function_p (current_function_decl));
+
+  if (!reload_completed)
+    cfun->machine->is_leaf = leaf_function_p ();
+
+  if (set)
+    CLEAR_HARD_REG_SET (*set);
+  count = 0;
+
+  /* No need to save any registers if the function never returns or 
+     is have "OS_task" or "OS_main" attribute.  */
+  if (TREE_THIS_VOLATILE (current_function_decl)
+      || cfun->machine->is_OS_task
+      || cfun->machine->is_OS_main)
+    return 0;
+
+  for (reg = 0; reg < 32; reg++)
+    {
+      /* Do not push/pop __tmp_reg__, __zero_reg__, as well as
+        any global register variables.  */
+      if (fixed_regs[reg])
+       continue;
+
+      if ((int_or_sig_p && !cfun->machine->is_leaf && call_used_regs[reg])
+         || (df_regs_ever_live_p (reg)
+             && (int_or_sig_p || !call_used_regs[reg])
+             && !(frame_pointer_needed
+                  && (reg == REG_Y || reg == (REG_Y+1)))))
+       {
+         if (set)
+           SET_HARD_REG_BIT (*set, reg);
+         count++;
+       }
+    }
+  return count;
+}
+
+/* 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)
 {
-  int reg;
   if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
     return 0;
   else
     {
-      int interrupt_func_p = interrupt_function_p (current_function_decl);
-      int signal_func_p = signal_function_p (current_function_decl);
-      int leaf_func_p = leaf_function_p ();
-      int offset= frame_pointer_needed ? 2 : 0;
+      int offset = frame_pointer_needed ? 2 : 0;
+      int avr_pc_size = AVR_HAVE_EIJMP_EICALL ? 3 : 2;
 
-      for (reg = 0; reg < 32; ++reg)
-       {
-         if ((!leaf_func_p && (call_used_regs[reg]
-                               && (interrupt_func_p || signal_func_p)))
-             || (regs_ever_live[reg]
-                 && (!call_used_regs[reg] || interrupt_func_p || signal_func_p)
-                 && ! (frame_pointer_needed
-                       && (reg == REG_Y || reg == (REG_Y+1)))))
-           {
-             ++offset;
-           }
-       }
-      return get_frame_size () + 2 + 1 + offset;
+      offset += avr_regs_to_save (NULL);
+      return get_frame_size () + (avr_pc_size) + 1 + offset;
     }
-  return 0;
 }
 
-/* This function checks sequence of live registers */
+/* Actual start of frame is virtual_stack_vars_rtx this is offset from 
+   frame pointer by +STARTING_FRAME_OFFSET.
+   Using saved frame = virtual_stack_vars_rtx - STARTING_FRAME_OFFSET
+   avoids creating add/sub of offset in nonlocal goto and setjmp.  */
+
+rtx avr_builtin_setjmp_frame_value (void)
+{
+  return gen_rtx_MINUS (Pmode, virtual_stack_vars_rtx, 
+                        gen_int_mode (STARTING_FRAME_OFFSET, Pmode));
+}
+
+/* Return 1 if the function epilogue is just a single "ret".  */
+
+int
+avr_simple_epilogue (void)
+{
+  return (! frame_pointer_needed
+         && get_frame_size () == 0
+         && avr_regs_to_save (NULL) == 0
+         && ! interrupt_function_p (current_function_decl)
+         && ! signal_function_p (current_function_decl)
+         && ! avr_naked_function_p (current_function_decl)
+         && ! TREE_THIS_VOLATILE (current_function_decl));
+}
+
+/* This function checks sequence of live registers.  */
 
 static int
-sequent_regs_live ()
+sequent_regs_live (void)
 {
   int reg;
   int live_seq=0;
@@ -405,7 +612,7 @@ sequent_regs_live ()
     {
       if (!call_used_regs[reg])
        {
-         if (regs_ever_live[reg])
+         if (df_regs_ever_live_p (reg))
            {
              ++live_seq;
              ++cur_seq;
@@ -417,7 +624,7 @@ sequent_regs_live ()
 
   if (!frame_pointer_needed)
     {
-      if (regs_ever_live[REG_Y])
+      if (df_regs_ever_live_p (REG_Y))
        {
          ++live_seq;
          ++cur_seq;
@@ -425,7 +632,7 @@ sequent_regs_live ()
       else
        cur_seq = 0;
 
-      if (regs_ever_live[REG_Y+1])
+      if (df_regs_ever_live_p (REG_Y+1))
        {
          ++live_seq;
          ++cur_seq;
@@ -441,323 +648,326 @@ sequent_regs_live ()
   return (cur_seq == live_seq) ? live_seq : 0;
 }
 
+/* Obtain the length sequence of insns.  */
 
-/* Output to FILE the asm instructions to adjust the frame pointer by
-   ADJ (r29:r28 -= ADJ;) which can be positive (prologue) or negative
-   (epilogue).  Returns the number of instructions generated.  */
-
-static int
-out_adj_frame_ptr (file, adj)
-     FILE *file;
-     int adj;
+int
+get_sequence_length (rtx insns)
 {
-  int size = 0;
-
-  if (adj)
-    {
-      if (TARGET_TINY_STACK)
-       {
-         if (adj < -63 || adj > 63)
-           warning ("large frame pointer change (%d) with -mtiny-stack", adj);
-
-         /* The high byte (r29) doesn't change - prefer "subi" (1 cycle)
-            over "sbiw" (2 cycles, same size).  */
-
-         fprintf (file, (AS2 (subi, r28, %d) CR_TAB), adj);
-         size++;
-       }
-      else if (adj < -63 || adj > 63)
-       {
-         fprintf (file, (AS2 (subi, r28, lo8(%d)) CR_TAB
-                         AS2 (sbci, r29, hi8(%d)) CR_TAB),
-                  adj, adj);
-         size += 2;
-       }
-      else if (adj < 0)
-       {
-         fprintf (file, (AS2 (adiw, r28, %d) CR_TAB), -adj);
-         size++;
-       }
-      else
-       {
-         fprintf (file, (AS2 (sbiw, r28, %d) CR_TAB), adj);
-         size++;
-       }
-    }
-  return size;
+  rtx insn;
+  int length;
+  
+  for (insn = insns, length = 0; insn; insn = NEXT_INSN (insn))
+    length += get_attr_length (insn);
+               
+  return length;
 }
 
+/*  Output function prologue.  */
 
-/* Output to FILE the asm instructions to copy r29:r28 to SPH:SPL,
-   handling various cases of interrupt enable flag state BEFORE and AFTER
-   (0=disabled, 1=enabled, -1=unknown/unchanged) and target_flags.
-   Returns the number of instructions generated.  */
-
-static int
-out_set_stack_ptr (file, before, after)
-     FILE *file;
-     int before;
-     int after;
+void
+expand_prologue (void)
 {
-  int do_sph, do_cli, do_save, do_sei, lock_sph, size;
-
-  /* The logic here is so that -mno-interrupts actually means
-     "it is safe to write SPH in one instruction, then SPL in the
-     next instruction, without disabling interrupts first".
-     The after != -1 case (interrupt/signal) is not affected.  */
-
-  do_sph = !TARGET_TINY_STACK;
-  lock_sph = do_sph && !TARGET_NO_INTERRUPTS;
-  do_cli = (before != 0 && (after == 0 || lock_sph));
-  do_save = (do_cli && before == -1 && after == -1);
-  do_sei = ((do_cli || before != 1) && after == 1);
-  size = 1;
+  int live_seq;
+  HARD_REG_SET set;
+  int minimize;
+  HOST_WIDE_INT size = get_frame_size();
+  /* Define templates for push instructions.  */
+  rtx pushbyte = gen_rtx_MEM (QImode,
+                  gen_rtx_POST_DEC (HImode, stack_pointer_rtx));
+  rtx pushword = gen_rtx_MEM (HImode,
+                  gen_rtx_POST_DEC (HImode, stack_pointer_rtx));
+  rtx insn;
 
-  if (do_save)
+  last_insn_address = 0;
+  
+  /* Init cfun->machine.  */
+  cfun->machine->is_naked = avr_naked_function_p (current_function_decl);
+  cfun->machine->is_interrupt = interrupt_function_p (current_function_decl);
+  cfun->machine->is_signal = signal_function_p (current_function_decl);
+  cfun->machine->is_OS_task = avr_OS_task_function_p (current_function_decl);
+  cfun->machine->is_OS_main = avr_OS_main_function_p (current_function_decl);
+  
+  /* Prologue: naked.  */
+  if (cfun->machine->is_naked)
     {
-      fprintf (file, AS2 (in, __tmp_reg__, __SREG__) CR_TAB);
-      size++;
+      return;
     }
 
-  if (do_cli)
-    {
-      fprintf (file, "cli" CR_TAB);
-      size++;
-    }
+  avr_regs_to_save (&set);
+  live_seq = sequent_regs_live ();
+  minimize = (TARGET_CALL_PROLOGUES
+             && !cfun->machine->is_interrupt
+             && !cfun->machine->is_signal
+             && !cfun->machine->is_OS_task
+             && !cfun->machine->is_OS_main
+             && live_seq);
 
-  /* Do SPH first - maybe this will disable interrupts for one instruction
-     someday (a suggestion has been sent to avr@atmel.com for consideration
-     in future devices - that would make -mno-interrupts always safe).  */
-  if (do_sph)
+  if (cfun->machine->is_interrupt || cfun->machine->is_signal)
     {
-      fprintf (file, AS2 (out, __SP_H__, r29) CR_TAB);
-      size++;
-    }
+      if (cfun->machine->is_interrupt)
+        {
+          /* Enable interrupts.  */
+          insn = emit_insn (gen_enable_interrupt ());
+          RTX_FRAME_RELATED_P (insn) = 1;
+        }
+       
+      /* Push zero reg.  */
+      insn = emit_move_insn (pushbyte, zero_reg_rtx);
+      RTX_FRAME_RELATED_P (insn) = 1;
+
+      /* Push tmp reg.  */
+      insn = emit_move_insn (pushbyte, tmp_reg_rtx);
+      RTX_FRAME_RELATED_P (insn) = 1;
+
+      /* Push SREG.  */
+      insn = emit_move_insn (tmp_reg_rtx, 
+                             gen_rtx_MEM (QImode, GEN_INT (SREG_ADDR)));
+      RTX_FRAME_RELATED_P (insn) = 1;
+      insn = emit_move_insn (pushbyte, tmp_reg_rtx);
+      RTX_FRAME_RELATED_P (insn) = 1;
+
+      /* Push RAMPZ.  */
+      if(AVR_HAVE_RAMPZ 
+         && (TEST_HARD_REG_BIT (set, REG_Z) && TEST_HARD_REG_BIT (set, REG_Z + 1)))
+        {
+          insn = emit_move_insn (tmp_reg_rtx, 
+                                 gen_rtx_MEM (QImode, GEN_INT (RAMPZ_ADDR)));
+          RTX_FRAME_RELATED_P (insn) = 1;
+          insn = emit_move_insn (pushbyte, tmp_reg_rtx);
+          RTX_FRAME_RELATED_P (insn) = 1;
+        }
+       
+      /* Clear zero reg.  */
+      insn = emit_move_insn (zero_reg_rtx, const0_rtx);
+      RTX_FRAME_RELATED_P (insn) = 1;
 
-  /* Set/restore the I flag now - interrupts will be really enabled only
-     after the next instruction.  This is not clearly documented, but
-     believed to be true for all AVR devices.  */
-  if (do_save)
-    {
-      fprintf (file, AS2 (out, __SREG__, __tmp_reg__) CR_TAB);
-      size++;
+      /* Prevent any attempt to delete the setting of ZERO_REG!  */
+      emit_use (zero_reg_rtx);
     }
-  else if (do_sei)
+  if (minimize && (frame_pointer_needed 
+                  || (AVR_2_BYTE_PC && live_seq > 6)
+                  || live_seq > 7)) 
     {
-      fprintf (file, "sei" CR_TAB);
-      size++;
+      insn = emit_move_insn (gen_rtx_REG (HImode, REG_X), 
+                             gen_int_mode (size, HImode));
+      RTX_FRAME_RELATED_P (insn) = 1;
+
+      insn = 
+        emit_insn (gen_call_prologue_saves (gen_int_mode (live_seq, HImode),
+                                           gen_int_mode (size + live_seq, HImode)));
+      RTX_FRAME_RELATED_P (insn) = 1;
     }
+  else
+    {
+      int reg;
+      for (reg = 0; reg < 32; ++reg)
+        {
+          if (TEST_HARD_REG_BIT (set, reg))
+            {
+              /* Emit push of register to save.  */
+              insn=emit_move_insn (pushbyte, gen_rtx_REG (QImode, reg));
+              RTX_FRAME_RELATED_P (insn) = 1;
+            }
+        }
+      if (frame_pointer_needed)
+        {
+         if (!(cfun->machine->is_OS_task || cfun->machine->is_OS_main))
+           {
+              /* Push frame pointer.  */
+             insn = emit_move_insn (pushword, frame_pointer_rtx);
+              RTX_FRAME_RELATED_P (insn) = 1;
+           }
 
-  fprintf (file, AS2 (out, __SP_L__, r28) "\n");
+          if (!size)
+            {
+              insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
+              RTX_FRAME_RELATED_P (insn) = 1;
+            }
+          else
+            {
+              /*  Creating a frame can be done by direct manipulation of the
+                  stack or via the frame pointer. These two methods are:
+                    fp=sp
+                    fp-=size
+                    sp=fp
+                OR
+                    sp-=size
+                    fp=sp
+              the optimum method depends on function type, stack and frame size.
+              To avoid a complex logic, both methods are tested and shortest
+              is selected.  */
+              rtx myfp;
+             rtx fp_plus_insns; 
+             rtx sp_plus_insns = NULL_RTX;
+
+              if (TARGET_TINY_STACK)
+                {
+                  /* The high byte (r29) doesn't change - prefer 'subi' (1 cycle)
+                     over 'sbiw' (2 cycles, same size).  */
+                  myfp = gen_rtx_REG (QImode, REGNO (frame_pointer_rtx));
+                }
+              else 
+                {
+                  /*  Normal sized addition.  */
+                  myfp = frame_pointer_rtx;
+                }
+
+             /* Method 1-Adjust frame pointer.  */
+             start_sequence ();
+
+              insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
+              RTX_FRAME_RELATED_P (insn) = 1;
+
+              insn = 
+               emit_move_insn (myfp,
+                               gen_rtx_PLUS (GET_MODE(myfp), myfp, 
+                                             gen_int_mode (-size, 
+                                                           GET_MODE(myfp))));
+              RTX_FRAME_RELATED_P (insn) = 1;
+
+             /* Copy to stack pointer.  */
+             if (TARGET_TINY_STACK)
+               {
+                 insn = emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
+                 RTX_FRAME_RELATED_P (insn) = 1;
+               }
+             else if (TARGET_NO_INTERRUPTS 
+                      || cfun->machine->is_signal
+                      || cfun->machine->is_OS_main)
+               {
+                 insn = 
+                   emit_insn (gen_movhi_sp_r_irq_off (stack_pointer_rtx, 
+                                                      frame_pointer_rtx));
+                 RTX_FRAME_RELATED_P (insn) = 1;               
+               }
+             else if (cfun->machine->is_interrupt)
+               {
+                 insn = emit_insn (gen_movhi_sp_r_irq_on (stack_pointer_rtx, 
+                                                          frame_pointer_rtx));
+                 RTX_FRAME_RELATED_P (insn) = 1;
+               }
+             else
+               {
+                 insn = emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
+                 RTX_FRAME_RELATED_P (insn) = 1;
+               }
 
-  return size;
+             fp_plus_insns = get_insns ();
+             end_sequence ();
+
+             /* Method 2-Adjust Stack pointer.  */
+              if (size <= 6)
+                {
+                 start_sequence ();
+
+                 insn = 
+                   emit_move_insn (stack_pointer_rtx,
+                                   gen_rtx_PLUS (HImode, 
+                                                 stack_pointer_rtx, 
+                                                 gen_int_mode (-size, 
+                                                               HImode)));
+                 RTX_FRAME_RELATED_P (insn) = 1;
+                 
+                 insn = 
+                   emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
+                 RTX_FRAME_RELATED_P (insn) = 1;
+
+                 sp_plus_insns = get_insns ();
+                 end_sequence ();
+                }
+
+              /* Use shortest method.  */
+              if (size <= 6 && (get_sequence_length (sp_plus_insns) 
+                                < get_sequence_length (fp_plus_insns)))
+               emit_insn (sp_plus_insns);
+              else
+               emit_insn (fp_plus_insns);
+            }
+        }
+    }
 }
 
-
-/* Output function prologue */
+/* Output summary at end of function prologue.  */
 
 static void
-avr_output_function_prologue (file, size)
-     FILE *file;
-     HOST_WIDE_INT size;
+avr_asm_function_end_prologue (FILE *file)
 {
-  int reg;
-  int interrupt_func_p;
-  int signal_func_p;
-  int leaf_func_p;
-  int main_p;
-  int live_seq;
-  int minimize;
-  
-  if (avr_naked_function_p (current_function_decl))
-    {
-      fprintf (file, "/* prologue: naked */\n");
-      return;
-    }
-
-  interrupt_func_p = interrupt_function_p (current_function_decl);
-  signal_func_p = signal_function_p (current_function_decl);
-  leaf_func_p = leaf_function_p ();
-  main_p = MAIN_NAME_P (DECL_NAME (current_function_decl));
-  live_seq = sequent_regs_live ();
-  minimize = (TARGET_CALL_PROLOGUES
-             && !interrupt_func_p && !signal_func_p && live_seq);
-
-  last_insn_address = 0;
-  jump_tables_size = 0;
-  prologue_size = 0;
-  fprintf (file, "/* prologue: frame size=%d */\n", size);
-  
-  if (interrupt_func_p)
-    {
-      fprintf (file,"\tsei\n");
-      ++prologue_size;
-    }
-  if (interrupt_func_p | signal_func_p)
-    {
-      fprintf (file, "\t"
-               AS1 (push,__zero_reg__)   CR_TAB
-               AS1 (push,__tmp_reg__)    CR_TAB
-              AS2 (in,__tmp_reg__,__SREG__) CR_TAB
-              AS1 (push,__tmp_reg__)    CR_TAB
-              AS1 (clr,__zero_reg__)    "\n");
-      prologue_size += 5;
-    }
-  if (main_p)
-    {
-      fprintf (file, ("\t" 
-                     AS2 (ldi,r28,lo8(%s - %d)) CR_TAB
-                     AS2 (ldi,r29,hi8(%s - %d)) CR_TAB
-                     AS2 (out,__SP_H__,r29)     CR_TAB
-                     AS2 (out,__SP_L__,r28) "\n"),
-              avr_init_stack, size, avr_init_stack, size);
-      
-      prologue_size += 4;
-    }
-  else if (minimize && (frame_pointer_needed || live_seq > 6)) 
+  if (cfun->machine->is_naked)
     {
-      fprintf (file, ("\t"
-                     AS2 (ldi, r26, lo8(%d)) CR_TAB
-                     AS2 (ldi, r27, hi8(%d)) CR_TAB), size, size);
-
-      fprintf (file, (AS2 (ldi, r30, pm_lo8(.L_%s_body)) CR_TAB
-                     AS2 (ldi, r31, pm_hi8(.L_%s_body)) CR_TAB)
-              ,current_function_name, current_function_name);
-      
-      prologue_size += 4;
-      
-      if (AVR_MEGA)
-       {
-         fprintf (file, AS1 (jmp,__prologue_saves__+%d) "\n",
-                  (18 - live_seq) * 2);
-         prologue_size += 2;
-       }
-      else
-       {
-         fprintf (file, AS1 (rjmp,__prologue_saves__+%d) "\n",
-                  (18 - live_seq) * 2);
-         ++prologue_size;
-       }
-      fprintf (file, ".L_%s_body:\n", current_function_name);
+      fputs ("/* prologue: naked */\n", file);
     }
   else
     {
-      for (reg = 0; reg < 32; ++reg)
-       {
-         if ((!leaf_func_p
-              && (call_used_regs[reg]
-                  && (interrupt_func_p || signal_func_p)
-                  && !(reg == TMP_REGNO || reg == ZERO_REGNO)))
-             || (regs_ever_live[reg]
-                 && (!call_used_regs[reg]
-                     || interrupt_func_p || signal_func_p)
-                 && ! (frame_pointer_needed
-                       && (reg == REG_Y || reg == (REG_Y+1)))))
-           {
-             fprintf (file, "\t" AS1 (push,%s) "\n", avr_regnames[reg]);
-             ++prologue_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);
-                 }
-             }
-         }
-       }
+      if (cfun->machine->is_interrupt)
+        {
+          fputs ("/* prologue: Interrupt */\n", file);
+        }
+      else if (cfun->machine->is_signal)
+        {
+          fputs ("/* prologue: Signal */\n", file);
+        }
+      else
+        fputs ("/* prologue: function */\n", file);
     }
-  fprintf (file, "/* prologue end (size=%d) */\n", prologue_size);
+  fprintf (file, "/* frame size = " HOST_WIDE_INT_PRINT_DEC " */\n",
+                 get_frame_size());
 }
 
-/* Output function epilogue */
 
-static void
-avr_output_function_epilogue (file, size)
-     FILE *file;
-     HOST_WIDE_INT size;
+/* Implement EPILOGUE_USES.  */
+
+int
+avr_epilogue_uses (int regno ATTRIBUTE_UNUSED)
+{
+  if (reload_completed 
+      && cfun->machine
+      && (cfun->machine->is_interrupt || cfun->machine->is_signal))
+    return 1;
+  return 0;
+}
+
+/*  Output RTL epilogue.  */
+
+void
+expand_epilogue (void)
 {
   int reg;
-  int interrupt_func_p;
-  int signal_func_p;
-  int leaf_func_p;
-  int main_p;
-  int function_size;
   int live_seq;
+  HARD_REG_SET set;      
   int minimize;
-
-  if (avr_naked_function_p (current_function_decl))
+  HOST_WIDE_INT size = get_frame_size();
+  
+  /* epilogue: naked  */
+  if (cfun->machine->is_naked)
     {
-      fprintf (file, "/* epilogue: naked */\n");
+      emit_jump_insn (gen_return ());
       return;
     }
 
-  interrupt_func_p = interrupt_function_p (current_function_decl);
-  signal_func_p = signal_function_p (current_function_decl);
-  leaf_func_p = leaf_function_p ();
-  main_p = MAIN_NAME_P (DECL_NAME (current_function_decl));
-  function_size = (INSN_ADDRESSES (INSN_UID (get_last_insn ()))
-                  - INSN_ADDRESSES (INSN_UID (get_insns ())));
-  function_size += jump_tables_size;
+  avr_regs_to_save (&set);
   live_seq = sequent_regs_live ();
   minimize = (TARGET_CALL_PROLOGUES
-             && !interrupt_func_p && !signal_func_p && live_seq);
+             && !cfun->machine->is_interrupt
+             && !cfun->machine->is_signal
+             && !cfun->machine->is_OS_task
+             && !cfun->machine->is_OS_main
+             && live_seq);
   
-  epilogue_size = 0;
-  fprintf (file, "/* epilogue: frame size=%d */\n", size);
-  if (main_p)
+  if (minimize && (frame_pointer_needed || live_seq > 4))
     {
-      fprintf (file, "__stop_progIi__:\n\trjmp __stop_progIi__\n");
-      ++epilogue_size;
-    }
-  else if (minimize && (frame_pointer_needed || live_seq > 4))
-    {
-      fprintf (file, ("\t" AS2 (ldi, r30, %d) CR_TAB), live_seq);
-      ++epilogue_size;
       if (frame_pointer_needed)
        {
-         epilogue_size += out_adj_frame_ptr (file, -size);
-       }
-      else
-       {
-         fprintf (file, (AS2 (in , r28, __SP_L__) CR_TAB
-                         AS2 (in , r29, __SP_H__) CR_TAB));
-         epilogue_size += 2;
-       }
-      
-      if (AVR_MEGA)
-       {
-         fprintf (file, AS1 (jmp,__epilogue_restores__+%d) "\n",
-                  (18 - live_seq) * 2);
-         epilogue_size += 2;
+          /*  Get rid of frame.  */
+         emit_move_insn(frame_pointer_rtx,
+                         gen_rtx_PLUS (HImode, frame_pointer_rtx,
+                                       gen_int_mode (size, HImode)));
        }
       else
        {
-         fprintf (file, AS1 (rjmp,__epilogue_restores__+%d) "\n",
-                  (18 - live_seq) * 2);
-         ++epilogue_size;
+          emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
        }
+       
+      emit_insn (gen_epilogue_restores (gen_int_mode (live_seq, HImode)));
     }
   else
     {
@@ -765,73 +975,129 @@ avr_output_function_epilogue (file, size)
        {
          if (size)
            {
-             fputs ("\t", file);
-             epilogue_size += out_adj_frame_ptr (file, -size);
+              /* Try two methods to adjust stack and select shortest.  */
+             rtx myfp;
+             rtx fp_plus_insns;
+             rtx sp_plus_insns = NULL_RTX;
+             
+             if (TARGET_TINY_STACK)
+                {
+                  /* The high byte (r29) doesn't change - prefer 'subi' 
+                     (1 cycle) over 'sbiw' (2 cycles, same size).  */
+                  myfp = gen_rtx_REG (QImode, REGNO (frame_pointer_rtx));
+                }
+              else 
+                {
+                  /* Normal sized addition.  */
+                  myfp = frame_pointer_rtx;
+                }
+             
+              /* Method 1-Adjust frame pointer.  */
+             start_sequence ();
 
-             if (interrupt_func_p | signal_func_p)
+             emit_move_insn (myfp,
+                             gen_rtx_PLUS (GET_MODE (myfp), myfp,
+                                           gen_int_mode (size, 
+                                                         GET_MODE(myfp))));
+
+             /* Copy to stack pointer.  */
+             if (TARGET_TINY_STACK)
+               {
+                 emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
+               }
+             else if (TARGET_NO_INTERRUPTS 
+                      || cfun->machine->is_signal)
                {
-                 epilogue_size += out_set_stack_ptr (file, -1, 0);
+                 emit_insn (gen_movhi_sp_r_irq_off (stack_pointer_rtx, 
+                                                    frame_pointer_rtx));
+               }
+             else if (cfun->machine->is_interrupt)
+               {
+                 emit_insn (gen_movhi_sp_r_irq_on (stack_pointer_rtx, 
+                                                   frame_pointer_rtx));
                }
              else
                {
-                 epilogue_size += out_set_stack_ptr (file, -1, -1);
+                 emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
                }
-           }
-         fprintf (file, "\t"
-                  AS1 (pop,r29) CR_TAB
-                  AS1 (pop,r28) "\n");
-         epilogue_size += 2;
-       }
 
-      for (reg = 31; reg >= 0; --reg)
-       {
-         if ((!leaf_func_p
-              && (call_used_regs[reg]
-                  && (interrupt_func_p || signal_func_p)
-                  && !(reg == TMP_REGNO || reg == ZERO_REGNO)))
-             || (regs_ever_live[reg]
-                 && (!call_used_regs[reg]
-                     || interrupt_func_p || signal_func_p)
-                 && ! (frame_pointer_needed
-                       && (reg == REG_Y || reg == (REG_Y+1)))))
+             fp_plus_insns = get_insns ();
+             end_sequence ();        
+
+              /* Method 2-Adjust Stack pointer.  */
+              if (size <= 5)
+                {
+                 start_sequence ();
+
+                 emit_move_insn (stack_pointer_rtx,
+                                 gen_rtx_PLUS (HImode, stack_pointer_rtx,
+                                               gen_int_mode (size, 
+                                                             HImode)));
+
+                 sp_plus_insns = get_insns ();
+                 end_sequence ();
+                }
+
+              /* Use shortest method.  */
+              if (size <= 5 && (get_sequence_length (sp_plus_insns) 
+                                < get_sequence_length (fp_plus_insns)))
+               emit_insn (sp_plus_insns);
+              else
+               emit_insn (fp_plus_insns);
+            }
+         if (!(cfun->machine->is_OS_task || cfun->machine->is_OS_main))
            {
-             fprintf (file, "\t" AS1 (pop,%s) "\n", avr_regnames[reg]);
-             ++epilogue_size;
+              /* Restore previous frame_pointer.  */
+             emit_insn (gen_pophi (frame_pointer_rtx));
            }
        }
+      /* Restore used registers.  */
+      for (reg = 31; reg >= 0; --reg)
+        {
+          if (TEST_HARD_REG_BIT (set, reg))
+              emit_insn (gen_popqi (gen_rtx_REG (QImode, reg)));
+        }
+      if (cfun->machine->is_interrupt || cfun->machine->is_signal)
+        {
+          /* Restore RAMPZ using tmp reg as scratch.  */
+         if(AVR_HAVE_RAMPZ 
+             && (TEST_HARD_REG_BIT (set, REG_Z) && TEST_HARD_REG_BIT (set, REG_Z + 1)))
+            {
+             emit_insn (gen_popqi (tmp_reg_rtx));
+             emit_move_insn (gen_rtx_MEM(QImode, GEN_INT(RAMPZ_ADDR)), 
+                             tmp_reg_rtx);
+           }
+
+          /* Restore SREG using tmp reg as scratch.  */
+          emit_insn (gen_popqi (tmp_reg_rtx));
       
-      if (interrupt_func_p | signal_func_p)
-       {
-         fprintf (file, "\t"
-                  AS1 (pop,__tmp_reg__)      CR_TAB
-                  AS2 (out,__SREG__,__tmp_reg__) CR_TAB
-                  AS1 (pop,__tmp_reg__)      CR_TAB
-                  AS1 (pop,__zero_reg__)     "\n");
-         epilogue_size += 4;
-         fprintf (file, "\treti\n");
-       }
-      else
-       fprintf (file, "\tret\n");
-      ++epilogue_size;
+          emit_move_insn (gen_rtx_MEM(QImode, GEN_INT(SREG_ADDR)), 
+                         tmp_reg_rtx);
+
+          /* Restore tmp REG.  */
+          emit_insn (gen_popqi (tmp_reg_rtx));
+
+          /* Restore zero REG.  */
+          emit_insn (gen_popqi (zero_reg_rtx));
+        }
+
+      emit_jump_insn (gen_return ());
     }
-  
-  fprintf (file, "/* epilogue end (size=%d) */\n", epilogue_size);
-  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;
-  commands_in_epilogues += epilogue_size;
 }
 
+/* Output summary messages at beginning of function epilogue.  */
+
+static void
+avr_asm_function_begin_epilogue (FILE *file)
+{
+  fprintf (file, "/* epilogue start */\n");
+}
 
 /* Return nonzero if X (an RTX) is a legitimate memory address on the target
    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;
   
@@ -854,6 +1120,8 @@ legitimate_address_p (mode, x, strict)
                 true_regnum (XEXP (x, 0)));
       debug_rtx (x);
     }
+  if (!strict && GET_CODE (x) == SUBREG)
+       x = SUBREG_REG (x);
   if (REG_P (x) && (strict ? REG_OK_FOR_BASE_STRICT_P (x)
                     : REG_OK_FOR_BASE_NOSTRICT_P (x)))
     r = POINTER_REGS;
@@ -868,6 +1136,7 @@ legitimate_address_p (mode, x, strict)
       if (fit)
        {
          if (! strict
+             || REGNO (XEXP (x,0)) == REG_X
              || REGNO (XEXP (x,0)) == REG_Y
              || REGNO (XEXP (x,0)) == REG_Z)
            r = BASE_POINTER_REGS;
@@ -887,7 +1156,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;
 }
@@ -896,10 +1165,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)
@@ -929,11 +1195,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)
     {
@@ -941,7 +1206,7 @@ ptrreg_to_str (regno)
     case REG_Y: return "Y";
     case REG_Z: return "Z";
     default:
-      abort ();
+      output_operand_lossage ("address operand requires constraint for X, Y, or Z register");
     }
   return NULL;
 }
@@ -950,8 +1215,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)
     {
@@ -974,16 +1238,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))
     {
@@ -1001,9 +1263,10 @@ print_operand_address (file, addr)
 
     default:
       if (CONSTANT_ADDRESS_P (addr)
-         && (SYMBOL_REF_FLAG (addr) || GET_CODE (addr) == LABEL_REF))
+         && ((GET_CODE (addr) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P (addr))
+             || GET_CODE (addr) == LABEL_REF))
        {
-         fprintf (file, "pm(");
+         fprintf (file, "gs(");
          output_addr_const (file,addr);
          fprintf (file ,")");
        }
@@ -1013,13 +1276,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;
 
@@ -1028,9 +1288,14 @@ print_operand (file, x, code)
 
   if (code == '~')
     {
-      if (!AVR_MEGA)
+      if (!AVR_HAVE_JMP_CALL)
        fputc ('r', file);
     }
+  else if (code == '!')
+    {
+      if (AVR_HAVE_EIJMP_EICALL)
+       fputc ('e', file);
+    }
   else if (REG_P (x))
     {
       if (x == zero_reg_rtx)
@@ -1039,7 +1304,7 @@ print_operand (file, x, code)
        fprintf (file, reg_names[true_regnum (x) + abcd]);
     }
   else if (GET_CODE (x) == CONST_INT)
-    fprintf (file, "%d", INTVAL (x) + abcd);
+    fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) + abcd);
   else if (GET_CODE (x) == MEM)
     {
       rtx addr = XEXP (x,0);
@@ -1057,6 +1322,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));
@@ -1077,40 +1352,20 @@ print_operand (file, x, code)
        fatal_insn ("internal compiler error.  Unknown mode:", x);
       REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
       REAL_VALUE_TO_TARGET_SINGLE (rv, val);
-      asm_fprintf (file, "0x%lx", val);
+      fprintf (file, "0x%lx", val);
     }
   else if (code == 'j')
-    asm_fprintf (file, cond_string (GET_CODE (x)));
+    fputs (cond_string (GET_CODE (x)), file);
   else if (code == 'k')
-    asm_fprintf (file, cond_string (reverse_condition (GET_CODE (x))));
+    fputs (cond_string (reverse_condition (GET_CODE (x))), file);
   else
     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;
   
@@ -1170,6 +1425,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);
@@ -1185,9 +1441,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 rclass ATTRIBUTE_UNUSED,enum machine_mode mode)
 {
   return ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD);
 }
@@ -1198,9 +1452,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));
@@ -1211,7 +1463,7 @@ avr_jump_mode (x, insn)
     return 1;
   else if (-2046 <= jump_distance && jump_distance <= 2045)
     return 2;
-  else if (AVR_MEGA)
+  else if (AVR_HAVE_JMP_CALL)
     return 3;
   
   return 2;
@@ -1223,10 +1475,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);
   
@@ -1325,9 +1574,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);
@@ -1339,9 +1586,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);
 
@@ -1350,32 +1596,22 @@ final_prescan_insn (insn, operand, num_operands)
       fprintf (asm_out_file, "/*DEBUG: 0x%x\t\t%d\t%d */\n",
               INSN_ADDRESSES (uid),
                INSN_ADDRESSES (uid) - last_insn_address,
-              rtx_cost (PATTERN (insn), INSN));
+              rtx_cost (PATTERN (insn), INSN, !optimize_size));
     }
   last_insn_address = INSN_ADDRESSES (uid);
-
-  if (TARGET_RTL_DUMP)
-    {
-      fprintf (asm_out_file, "/*****************\n");
-      print_rtl_single (asm_out_file, insn);
-      fprintf (asm_out_file, "*****************/\n");
-    }
 }
 
 /* Return 0 if undefined, 1 if always true or always false.  */
 
 int
-avr_simplify_comparision_p (mode, operator, x)
-     enum machine_mode mode;
-     RTX_CODE operator;
-     rtx x;
+avr_simplify_comparison_p (enum machine_mode mode, RTX_CODE op, rtx x)
 {
   unsigned int max = (mode == QImode ? 0xff :
                       mode == HImode ? 0xffff :
                       mode == SImode ? 0xffffffff : 0);
-  if (max && operator && GET_CODE (x) == CONST_INT)
+  if (max && op && GET_CODE (x) == CONST_INT)
     {
-      if (unsigned_condition (operator) != operator)
+      if (unsigned_condition (op) != op)
        max >>= 1;
 
       if (max != (INTVAL (x) & max)
@@ -1390,8 +1626,7 @@ avr_simplify_comparision_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);
 }
@@ -1400,15 +1635,12 @@ function_arg_regno_p(r)
    of the argument list.  */
 
 void
-init_cumulative_args (cum, fntype, libname, indirect)
-     CUMULATIVE_ARGS *cum;
-     tree fntype;
-     rtx libname;
-     int indirect ATTRIBUTE_UNUSED;
+init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype, rtx libname,
+                     tree fndecl ATTRIBUTE_UNUSED)
 {
   cum->nregs = 18;
   cum->regno = FIRST_CUM_REG;
-  if (!libname)
+  if (!libname && fntype)
     {
       int stdarg = (TYPE_ARG_TYPES (fntype) != 0
                     && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
@@ -1421,9 +1653,7 @@ init_cumulative_args (cum, fntype, libname, indirect)
 /* Returns the number of registers to allocate for a function argument.  */
 
 static int
-avr_num_arg_regs (mode, type)
-     enum machine_mode mode;
-     tree type;
+avr_num_arg_regs (enum machine_mode mode, tree type)
 {
   int size;
 
@@ -1439,19 +1669,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;
 }
@@ -1460,11 +1687,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);
 
@@ -1482,10 +1706,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];
@@ -1519,9 +1740,6 @@ output_movqi (insn, operands, l)
                return AS1 (clr,%0);
              else if (src == const1_rtx)
                {
-                 if (reg_was_0 (insn, dest))
-                   return AS1 (inc,%0 ; reg_was_0);
-
                  *l = 2;
                  return (AS1 (clr,%0) CR_TAB
                          AS1 (inc,%0));
@@ -1529,9 +1747,6 @@ output_movqi (insn, operands, l)
              else if (src == constm1_rtx)
                {
                  /* Immediate constants -1 to any register */
-                 if (reg_was_0 (insn, dest))
-                   return AS1 (dec,%0 ; reg_was_0);
-
                  *l = 2;
                  return (AS1 (clr,%0) CR_TAB
                          AS1 (dec,%0));
@@ -1542,19 +1757,10 @@ output_movqi (insn, operands, l)
 
                  if (bit_nr >= 0)
                    {
-                     if (reg_was_0 (insn, dest))
-                       {
-                         *l = 2;
-                         if (!real_l)
-                           output_asm_insn ("set ; reg_was_0", operands);
-                       }
-                     else
-                       {
-                         *l = 3;
-                         if (!real_l)
-                           output_asm_insn ((AS1 (clr,%0) CR_TAB
-                                             "set"), operands);
-                       }
+                     *l = 3;
+                     if (!real_l)
+                       output_asm_insn ((AS1 (clr,%0) CR_TAB
+                                         "set"), operands);
                      if (!real_l)
                        avr_output_bld (operands, bit_nr);
 
@@ -1575,15 +1781,15 @@ output_movqi (insn, operands, l)
     }
   else if (GET_CODE (dest) == MEM)
     {
-      const char *template;
+      const char *templ;
 
       if (src == const0_rtx)
        operands[1] = zero_reg_rtx;
 
-      template = out_movqi_mr_r (insn, operands, real_l);
+      templ = out_movqi_mr_r (insn, operands, real_l);
 
       if (!real_l)
-       output_asm_insn (template, operands);
+       output_asm_insn (templ, operands);
 
       operands[1] = src;
     }
@@ -1592,10 +1798,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];
@@ -1612,17 +1815,12 @@ output_movhi (insn, operands, l)
          if (test_hard_reg_class (STACK_REG, dest))
            {
              if (TARGET_TINY_STACK)
-               {
-                 *l = 1;
-                 return AS2 (out,__SP_L__,%A1);
-               }
+               return *l = 1, AS2 (out,__SP_L__,%A1);
+              /* Use simple load of stack pointer if no interrupts are 
+                used.  */
              else if (TARGET_NO_INTERRUPTS)
-               {
-                 *l = 2;
-                 return (AS2 (out,__SP_H__,%B1) CR_TAB
-                         AS2 (out,__SP_L__,%A1));
-               }
-
+               return *l = 2, (AS2 (out,__SP_H__,%B1) CR_TAB
+                               AS2 (out,__SP_L__,%A1));
              *l = 5;
              return (AS2 (in,__tmp_reg__,__SREG__)  CR_TAB
                      "cli"                          CR_TAB
@@ -1637,18 +1835,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;
@@ -1660,13 +1851,6 @@ output_movhi (insn, operands, l)
        {
          if (test_hard_reg_class (LD_REGS, dest)) /* ldi d,i */
            {
-             if (byte_immediate_operand (src, HImode)
-                 && reg_was_0 (insn, dest))
-               {
-                 *l = 1;
-                 return (AS2 (ldi,%A0,lo8(%1) ; reg_was_0));
-               }
-
              *l = 2;
              return (AS2 (ldi,%A0,lo8(%1)) CR_TAB
                      AS2 (ldi,%B0,hi8(%1)));
@@ -1682,12 +1866,6 @@ output_movhi (insn, operands, l)
                }
              else if (src == const1_rtx)
                {
-                 if (reg_was_0 (insn, dest))
-                   {
-                     *l = 1;
-                     return AS1 (inc,%0 ; reg_was_0);
-                   }
-
                  *l = 3;
                  return (AS1 (clr,%A0) CR_TAB
                          AS1 (clr,%B0) CR_TAB
@@ -1696,13 +1874,6 @@ output_movhi (insn, operands, l)
              else if (src == constm1_rtx)
                {
                  /* Immediate constants -1 to any register */
-                 if (reg_was_0 (insn, dest))
-                   {
-                     *l = 2;
-                     return (AS1 (dec,%A0 ; reg_was_0) CR_TAB
-                             AS1 (dec,%B0));
-                   }
-
                  *l = 3;
                  return (AS1 (clr,%0)  CR_TAB
                          AS1 (dec,%A0) CR_TAB
@@ -1714,20 +1885,11 @@ output_movhi (insn, operands, l)
 
                  if (bit_nr >= 0)
                    {
-                     if (reg_was_0 (insn, dest))
-                       {
-                         *l = 2;
-                         if (!real_l)
-                           output_asm_insn ("set ; reg_was_0", operands);
-                       }
-                     else
-                       {
-                         *l = 4;
-                         if (!real_l)
-                           output_asm_insn ((AS1 (clr,%A0) CR_TAB
-                                             AS1 (clr,%B0) CR_TAB
-                                             "set"), operands);
-                       }
+                     *l = 4;
+                     if (!real_l)
+                       output_asm_insn ((AS1 (clr,%A0) CR_TAB
+                                         AS1 (clr,%B0) CR_TAB
+                                         "set"), operands);
                      if (!real_l)
                        avr_output_bld (operands, bit_nr);
 
@@ -1769,15 +1931,15 @@ output_movhi (insn, operands, l)
     }
   else if (GET_CODE (dest) == MEM)
     {
-      const char *template;
+      const char *templ;
 
       if (src == const0_rtx)
        operands[1] = zero_reg_rtx;
 
-      template = out_movhi_mr_r (insn, operands, real_l);
+      templ = out_movhi_mr_r (insn, operands, real_l);
 
       if (!real_l)
-       output_asm_insn (template, operands);
+       output_asm_insn (templ, operands);
 
       operands[1] = src;
       return "";
@@ -1787,10 +1949,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];
@@ -1802,7 +1961,12 @@ out_movqi_r_mr (insn, op, l)
   
   if (CONSTANT_ADDRESS_P (x))
     {
-      if (io_address_p (x, 1))
+      if (CONST_INT_P (x) && INTVAL (x) == SREG_ADDR)
+       {
+         *l = 1;
+         return AS2 (in,%0,__SREG__);
+       }
+      if (optimize > 0 && io_address_operand (x, QImode))
        {
          *l = 1;
          return AS2 (in,%0,%1-0x20);
@@ -1853,16 +2017,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)
@@ -1956,6 +2120,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));
@@ -1971,7 +2154,7 @@ out_movhi_r_mr (insn, op, l)
     }
   else if (CONSTANT_ADDRESS_P (base))
     {
-      if (io_address_p (base, 2))
+      if (optimize > 0 && io_address_operand (base, HImode))
        {
          *l = 2;
          return (AS2 (in,%A0,%A1-0x20) CR_TAB
@@ -1987,10 +2170,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];
@@ -2151,10 +2331,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];
@@ -2309,10 +2486,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];
@@ -2328,7 +2502,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
@@ -2342,7 +2516,7 @@ output_movsisf(insn, operands, l)
            }
          else
            {
-             if (AVR_ENHANCED)
+             if (AVR_HAVE_MOVW)
                {
                  *l = 2;
                  return (AS2 (movw,%A0,%A1) CR_TAB
@@ -2359,13 +2533,6 @@ output_movsisf(insn, operands, l)
        {
          if (test_hard_reg_class (LD_REGS, dest)) /* ldi d,i */
            {
-             if (byte_immediate_operand (src, SImode)
-                 && reg_was_0 (insn, dest))
-               {
-                 *l = 1;
-                 return (AS2 (ldi,%A0,lo8(%1) ; reg_was_0));
-               }
-
              *l = 4;
              return (AS2 (ldi,%A0,lo8(%1))  CR_TAB
                      AS2 (ldi,%B0,hi8(%1))  CR_TAB
@@ -2376,7 +2543,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
@@ -2386,40 +2553,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 (reg_was_0 (insn, dest))
-                   {
-                     *l = 1;
-                     return AS1 (inc,%A0 ; reg_was_0);
-                   }
                  if (!real_l)
                    output_asm_insn (clr_op0, operands);
-                 *l = AVR_ENHANCED ? 4 : 5;
+                 *l = AVR_HAVE_MOVW ? 4 : 5;
                  return AS1 (inc,%A0);
                }
              else if (src == constm1_rtx)
                {
                  /* Immediate constants -1 to any register */
-                 if (reg_was_0 (insn, dest))
-                   {
-                     if (AVR_ENHANCED)
-                       {
-                         *l = 3;
-                         return (AS1 (dec,%A0) CR_TAB
-                                 AS1 (dec,%B0) CR_TAB
-                                 AS2 (movw,%C0,%A0));
-                       }
-                     *l = 4;
-                     return (AS1 (dec,%D0 ; reg_was_0) CR_TAB
-                             AS1 (dec,%C0)             CR_TAB
-                             AS1 (dec,%B0)             CR_TAB
-                             AS1 (dec,%A0));
-                   }
-                 if (AVR_ENHANCED)
+                 if (AVR_HAVE_MOVW)
                    {
                      *l = 4;
                      return (AS1 (clr,%A0)     CR_TAB
@@ -2440,20 +2587,11 @@ output_movsisf(insn, operands, l)
 
                  if (bit_nr >= 0)
                    {
-                     if (reg_was_0 (insn, dest))
-                       {
-                         *l = 2;
-                         if (!real_l)
-                           output_asm_insn ("set ; reg_was_0", operands);
-                       }
-                     else
+                     *l = AVR_HAVE_MOVW ? 5 : 6;
+                     if (!real_l)
                        {
-                         *l = AVR_ENHANCED ? 5 : 6;
-                         if (!real_l)
-                           {
-                             output_asm_insn (clr_op0, operands);
-                             output_asm_insn ("set", operands);
-                           }
+                         output_asm_insn (clr_op0, operands);
+                         output_asm_insn ("set", operands);
                        }
                      if (!real_l)
                        avr_output_bld (operands, bit_nr);
@@ -2481,15 +2619,15 @@ output_movsisf(insn, operands, l)
     }
   else if (GET_CODE (dest) == MEM)
     {
-      const char *template;
+      const char *templ;
 
       if (src == const0_rtx)
          operands[1] = zero_reg_rtx;
 
-      template = out_movsi_mr_r (insn, operands, real_l);
+      templ = out_movsi_mr_r (insn, operands, real_l);
 
       if (!real_l)
-       output_asm_insn (template, operands);
+       output_asm_insn (templ, operands);
 
       operands[1] = src;
       return "";
@@ -2499,10 +2637,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];
@@ -2514,7 +2649,12 @@ out_movqi_mr_r (insn, op, l)
   
   if (CONSTANT_ADDRESS_P (x))
     {
-      if (io_address_p (x, 1))
+      if (CONST_INT_P (x) && INTVAL (x) == SREG_ADDR)
+       {
+         *l = 1;
+         return AS2 (out,__SREG__,%1);
+       }
+      if (optimize > 0 && io_address_operand (x, QImode))
        {
          *l = 1;
          return AS2 (out,%0-0x20,%1);
@@ -2577,22 +2717,23 @@ 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))
     {
-      if (io_address_p (base, 2))
+      if (optimize > 0 && io_address_operand (base, HImode))
        {
          *l = 2;
          return (AS2 (out,%B0-0x20,%B1) CR_TAB
@@ -2607,33 +2748,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)
     {
@@ -2646,14 +2787,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)));
        }
@@ -2661,51 +2802,71 @@ 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
-         || current_function_varargs
+  return (cfun->calls_alloca
+         || crtl->args.info.nregs == 0
          || get_frame_size () > 0);
 }
 
 /* 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;
@@ -2722,8 +2883,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);
@@ -2733,8 +2893,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;
@@ -2743,20 +2902,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))
     {
@@ -2766,7 +2922,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);
     }
@@ -2781,12 +2937,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))
     {
@@ -2814,12 +2968,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 *templ, rtx insn, rtx operands[],
+                   int *len, int t_len)
 {
   rtx op[10];
   char str[500];
@@ -2842,6 +2992,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;
 
@@ -2856,7 +3013,7 @@ out_shift_with_cnt (template, insn, operands, len, t_len)
          else
            {
              while (count-- > 0)
-               output_asm_insn (template, op);
+               output_asm_insn (templ, op);
            }
 
          return;
@@ -2884,7 +3041,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;
@@ -2937,7 +3094,7 @@ out_shift_with_cnt (template, insn, operands, len, t_len)
   else
     {
       strcat (str, "\n1:\t");
-      strcat (str, template);
+      strcat (str, templ);
       strcat (str, second_label ? "\n2:\t" : "\n\t");
       strcat (str, use_zero_reg ? AS1 (lsr,%3) : AS1 (dec,%3));
       strcat (str, CR_TAB);
@@ -2952,10 +3109,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)
     {
@@ -2967,6 +3121,9 @@ ashlqi3_out (insn, operands, len)
       switch (INTVAL (operands[2]))
        {
        default:
+         if (INTVAL (operands[2]) < 8)
+           break;
+
          *len = 1;
          return AS1 (clr,%0);
          
@@ -3049,10 +3206,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)
     {
@@ -3066,6 +3220,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 */
@@ -3145,11 +3307,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;
@@ -3208,7 +3367,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
@@ -3229,7 +3388,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
@@ -3249,7 +3408,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
@@ -3258,7 +3417,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
@@ -3305,10 +3464,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)
     {
@@ -3320,6 +3476,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]);
@@ -3330,11 +3500,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
@@ -3346,46 +3511,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;
@@ -3409,10 +3554,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)
     {
@@ -3461,6 +3603,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
@@ -3479,10 +3626,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)
     {
@@ -3530,15 +3674,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:
@@ -3557,7 +3697,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
@@ -3577,7 +3717,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
@@ -3598,7 +3738,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
@@ -3627,6 +3767,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
@@ -3644,10 +3790,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)
     {
@@ -3671,13 +3814,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
@@ -3691,54 +3827,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
@@ -3763,10 +3888,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)
     {
@@ -3778,6 +3900,9 @@ lshrqi3_out (insn, operands, len)
       switch (INTVAL (operands[2]))
        {
        default:
+         if (INTVAL (operands[2]) < 8)
+           break;
+
          *len = 1;
          return AS1 (clr,%0);
 
@@ -3858,10 +3983,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)
     {
@@ -3875,6 +3997,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 */
@@ -3954,11 +4084,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;
@@ -4017,7 +4144,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
@@ -4038,7 +4165,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
@@ -4058,7 +4185,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
@@ -4067,7 +4194,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
@@ -4113,10 +4240,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)
     {
@@ -4128,6 +4252,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]);
@@ -4138,8 +4276,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
@@ -4151,39 +4287,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;
@@ -4208,9 +4331,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;
@@ -4355,25 +4476,21 @@ adjust_insn_length (insn, len)
   return len;
 }
 
-/* Return non-zero 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)));
 }
 
-/* Return non-zero if REG is not used after INSN.
+/* Return nonzero if REG is not used after INSN.
    We assume REG is a reload reg, and therefore does
    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;
@@ -4388,6 +4505,7 @@ _reg_unused_after (insn, reg)
 
   while ((insn = NEXT_INSN (insn)))
     {
+      rtx set;
       code = GET_CODE (insn);
 
 #if 0
@@ -4400,6 +4518,9 @@ _reg_unused_after (insn, reg)
       /* else */
 #endif
 
+      if (!INSN_P (insn))
+       continue;
+
       if (code == JUMP_INSN)
        return 0;
 
@@ -4457,17 +4578,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;
 }
@@ -4476,16 +4594,13 @@ _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_FLAG (x))
+      && ((GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P (x))
          || GET_CODE (x) == LABEL_REF))
     {
-      fputs ("\t.word\tpm(", asm_out_file);
+      fputs ("\t.word\tgs(", asm_out_file);
       output_addr_const (asm_out_file, x);
       fputs (")\n", asm_out_file);
       return true;
@@ -4493,53 +4608,50 @@ avr_assemble_integer (x, size, aligned_p)
   return default_assemble_integer (x, size, aligned_p);
 }
 
-/* Sets section name for declaration DECL */
-  
+/* Worker function for ASM_DECLARE_FUNCTION_NAME.  */
+
 void
-unique_section (decl, reloc)
-     tree decl;
-     int reloc ATTRIBUTE_UNUSED;
+avr_asm_declare_function_name (FILE *file, const char *name, tree decl)
 {
-  int len;
-  const char *name, *prefix;
-  char *string;
-  name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
-  /* Strip off any encoding in name.  */
-  STRIP_NAME_ENCODING (name, name);
-
-  if (TREE_CODE (decl) == FUNCTION_DECL)
+
+  /* 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 (cfun->machine->is_interrupt)
     {
-      if (flag_function_sections)
-       prefix = ".text.";
-      else
-       prefix = ".text";
+      if (strncmp (name, "__vector", strlen ("__vector")) != 0)
+        {
+          warning_at (DECL_SOURCE_LOCATION (decl), 0,
+                      "%qs appears to be a misspelled interrupt handler",
+                      name);
+        }
     }
-  else 
-    abort ();
-
-  if (flag_function_sections)
+  else if (cfun->machine->is_signal)
     {
-      len = strlen (name) + strlen (prefix);
-      string = alloca (len + 1);
-      sprintf (string, "%s%s", prefix, name);
-      DECL_SECTION_NAME (decl) = build_string (len, string);
+      if (strncmp (name, "__vector", strlen ("__vector")) != 0)
+        {
+           warning_at (DECL_SOURCE_LOCATION (decl), 0,
+                       "%qs appears to be a misspelled signal handler",
+                       name);
+        }
     }
-}
 
+  ASM_OUTPUT_TYPE_DIRECTIVE (file, name, "function");
+  ASM_OUTPUT_LABEL (file, name);
+}
 
 /* The routine used to output NUL terminated strings.  We use a special
    version of this for most svr4 targets because doing so makes the
    generated assembly code more compact (and thus faster to assemble)
    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;
+  const unsigned char *_limited_str = (const unsigned char *) str;
   unsigned ch;
   fprintf (file, "%s\"", STRING_ASM_OP);
   for (; (ch = *_limited_str); _limited_str++)
@@ -4570,10 +4682,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;
@@ -4595,7 +4704,7 @@ gas_output_ascii(file, str, length)
              fprintf (file, "\"\n");
              bytes_in_chunk = 0;
            }
-         gas_output_limited_string (file, (char*)_ascii_bytes);
+         gas_output_limited_string (file, (const char*)_ascii_bytes);
          _ascii_bytes = p;
        }
       else
@@ -4631,8 +4740,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);
 }
@@ -4653,19 +4761,19 @@ const struct attribute_spec avr_attribute_table[] =
   { "progmem",   0, 0, false, false, false,  avr_handle_progmem_attribute },
   { "signal",    0, 0, true,  false, false,  avr_handle_fndecl_attribute },
   { "interrupt", 0, 0, true,  false, false,  avr_handle_fndecl_attribute },
-  { "naked",     0, 0, true,  false, false,  avr_handle_fndecl_attribute },
+  { "naked",     0, 0, false, true,  true,   avr_handle_fntype_attribute },
+  { "OS_task",   0, 0, false, true,  true,   avr_handle_fntype_attribute },
+  { "OS_main",   0, 0, false, true,  true,   avr_handle_fntype_attribute },
   { NULL,        0, 0, false, false, false, NULL }
 };
 
 /* 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))
     {
@@ -4681,19 +4789,20 @@ avr_handle_progmem_attribute (node, name, args, flags, no_add_attrs)
          TYPE_MAIN_VARIANT (newtype) = TYPE_MAIN_VARIANT (type);
          TREE_TYPE (*node) = newtype;
          *no_add_attrs = true;
-        }
+       }
       else if (TREE_STATIC (*node) || DECL_EXTERNAL (*node))
        {
          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;
        }
     }
@@ -4703,17 +4812,32 @@ 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;
+    }
+
+  return NULL_TREE;
+}
+
+static tree
+avr_handle_fntype_attribute (tree *node, tree name,
+                             tree args ATTRIBUTE_UNUSED,
+                             int flags ATTRIBUTE_UNUSED,
+                             bool *no_add_attrs)
+{
+  if (TREE_CODE (*node) != FUNCTION_TYPE)
+    {
+      warning (OPT_Wattributes, "%qs attribute only applies to functions",
               IDENTIFIER_POINTER (name));
       *no_add_attrs = true;
     }
@@ -4725,8 +4849,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;
 
@@ -4734,7 +4857,7 @@ avr_progmem_p (decl)
     return 0;
 
   if (NULL_TREE
-      != lookup_attribute ("progmem", DECL_ATTRIBUTES (decl)))
+      != lookup_attribute ("progmem", attributes))
     return 1;
 
   a=decl;
@@ -4751,184 +4874,754 @@ avr_progmem_p (decl)
   return 0;
 }
 
-/* Encode section information about tree DECL */
-  
-void
-encode_section_info (decl)
-     tree decl;
+/* Add the section attribute if the variable is in progmem.  */
+
+static void
+avr_insert_attributes (tree node, tree *attributes)
 {
-  if (TREE_CODE (decl) == FUNCTION_DECL)
-    SYMBOL_REF_FLAG (XEXP (DECL_RTL (decl), 0)) = 1;
-  else if ((TREE_STATIC (decl) || DECL_EXTERNAL (decl))
-          && TREE_CODE (decl) == VAR_DECL
-          && avr_progmem_p (decl))
+  if (TREE_CODE (node) == VAR_DECL
+      && (TREE_STATIC (node) || DECL_EXTERNAL (node))
+      && avr_progmem_p (node, *attributes))
     {
-      static const char *const dsec = ".progmem.data";
-      DECL_SECTION_NAME (decl) = build_string (strlen (dsec), dsec);
-      TREE_READONLY (decl) = 1;
+      static const char dsec[] = ".progmem.data";
+      *attributes = tree_cons (get_identifier ("section"),
+               build_tree_list (NULL, build_string (strlen (dsec), dsec)),
+               *attributes);
+
+      /* ??? This seems sketchy.  Why can't the user declare the
+        thing const in the first place?  */
+      TREE_READONLY (node) = 1;
     }
-}   
+}
 
-/* Outputs to the stdio stream FILE some
-   appropriate text to go at the start of an assembler file.  */
+/* A get_unnamed_section callback for switching to progmem_section.  */
 
-void
-asm_file_start (file)
-     FILE *file;
+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_HAVE_JMP_CALL ? "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_HAVE_JMP_CALL ? 0 : SECTION_CODE,
+                                        avr_output_progmem_section_asm_op,
+                                        NULL);
+  readonly_data_section = data_section;
+}
+
+static unsigned int
+avr_section_type_flags (tree decl, const char *name, int reloc)
 {
-  output_file_directive (file, main_input_filename);
-  fprintf (file, "\t.arch %s\n", avr_mcu_name);
+  unsigned int flags = default_section_type_flags (decl, name, reloc);
+
+  if (strncmp (name, ".noinit", 7) == 0)
+    {
+      if (decl && TREE_CODE (decl) == VAR_DECL
+         && DECL_INITIAL (decl) == NULL_TREE)
+       flags |= SECTION_BSS;  /* @nobits */
+      else
+       warning (0, "only uninitialized variables can be placed in the "
+                ".noinit section");
+    }
+
+  return flags;
+}
+
+/* Outputs some appropriate text to go at the start of an assembler
+   file.  */
+
+static void
+avr_file_start (void)
+{
+  if (avr_current_arch->asm_only)
+    error ("MCU %qs supported for assembler only", avr_mcu_name);
+
+  default_file_start ();
+
+/*  fprintf (asm_out_file, "\t.arch %s\n", avr_mcu_name);*/
   fputs ("__SREG__ = 0x3f\n"
         "__SP_H__ = 0x3e\n"
-        "__SP_L__ = 0x3d\n", file);
+        "__SP_L__ = 0x3d\n", asm_out_file);
   
   fputs ("__tmp_reg__ = 0\n" 
-        "__zero_reg__ = 1\n", file);
-  
-  commands_in_file = 0;
-  commands_in_prologues = 0;
-  commands_in_epilogues = 0;
+         "__zero_reg__ = 1\n", asm_out_file);
+
+  /* FIXME: output these only if there is anything in the .data / .bss
+     sections - some code size could be saved by not linking in the
+     initialization code from libgcc if one or both sections are empty.  */
+  fputs ("\t.global __do_copy_data\n", asm_out_file);
+  fputs ("\t.global __do_clear_bss\n", asm_out_file);
 }
 
 /* Outputs to the stdio stream FILE some
    appropriate text to go at the end of an assembler file.  */
 
-void
-asm_file_end (file)
-     FILE *file;
-{
-  fprintf (file,
-          "/* File %s: code %4d = 0x%04x (%4d), prologues %3d, epilogues %3d */\n",
-          main_input_filename,
-          commands_in_file,
-          commands_in_file,
-          commands_in_file - commands_in_prologues - commands_in_epilogues,
-          commands_in_prologues, commands_in_epilogues);
-}
+static void
+avr_file_end (void)
+{
+}
+
+/* Choose the order in which to allocate hard registers for
+   pseudo-registers local to a basic block.
+
+   Store the desired register order in the array `reg_alloc_order'.
+   Element 0 should be the register to allocate first; element 1, the
+   next register; and so on.  */
+
+void
+order_regs_for_local_alloc (void)
+{
+  unsigned int i;
+  static const int order_0[] = {
+    24,25,
+    18,19,
+    20,21,
+    22,23,
+    30,31,
+    26,27,
+    28,29,
+    17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,
+    0,1,
+    32,33,34,35
+  };
+  static const int order_1[] = {
+    18,19,
+    20,21,
+    22,23,
+    24,25,
+    30,31,
+    26,27,
+    28,29,
+    17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,
+    0,1,
+    32,33,34,35
+  };
+  static const int order_2[] = {
+    25,24,
+    23,22,
+    21,20,
+    19,18,
+    30,31,
+    26,27,
+    28,29,
+    17,16,
+    15,14,13,12,11,10,9,8,7,6,5,4,3,2,
+    1,0,
+    32,33,34,35
+  };
+  
+  const int *order = (TARGET_ORDER_1 ? order_1 :
+                     TARGET_ORDER_2 ? order_2 :
+                     order_0);
+  for (i=0; i < ARRAY_SIZE (order_0); ++i)
+      reg_alloc_order[i] = order[i];
+}
+
+
+/* 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
+avr_operand_rtx_cost (rtx x, enum machine_mode mode, enum rtx_code outer,
+                     bool speed)
+{
+  enum rtx_code code = GET_CODE (x);
+  int total;
+
+  switch (code)
+    {
+    case REG:
+    case SUBREG:
+      return 0;
+
+    case CONST_INT:
+    case CONST_DOUBLE:
+      return COSTS_N_INSNS (GET_MODE_SIZE (mode));
+
+    default:
+      break;
+    }
+
+  total = 0;
+  avr_rtx_costs (x, code, outer, &total, speed);
+  return total;
+}
+
+/* The AVR backend's rtx_cost function.  X is rtx expression whose cost
+   is to be calculated.  Return true if the complete cost has been
+   computed, and false if subexpressions should be scanned.  In either
+   case, *TOTAL contains the cost result.  */
+
+static bool
+avr_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int *total,
+              bool speed)
+{
+  enum machine_mode mode = GET_MODE (x);
+  HOST_WIDE_INT val;
+
+  switch (code)
+    {
+    case CONST_INT:
+    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)
+       {
+       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;
+       }
+      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code, speed);
+      return true;
+
+    case ABS:
+      switch (mode)
+       {
+       case QImode:
+       case SFmode:
+         *total = COSTS_N_INSNS (1);
+         break;
+
+       default:
+         return false;
+       }
+      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code, speed);
+      return true;
+
+    case NOT:
+      *total = COSTS_N_INSNS (GET_MODE_SIZE (mode));
+      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code, speed);
+      return true;
+
+    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, speed);
+      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, speed);
+      return true;
+
+    case PLUS:
+      switch (mode)
+       {
+       case QImode:
+         *total = COSTS_N_INSNS (1);
+         if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+           *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code, speed);
+         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, speed);
+           }
+         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, speed);
+           }
+         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, speed);
+      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, speed);
+      if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+          *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code, speed);
+      return true;
+
+    case XOR:
+      *total = COSTS_N_INSNS (GET_MODE_SIZE (mode));
+      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code, speed);
+      *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code, speed);
+      return true;
+
+    case MULT:
+      switch (mode)
+       {
+       case QImode:
+         if (AVR_HAVE_MUL)
+           *total = COSTS_N_INSNS (!speed ? 3 : 4);
+         else if (!speed)
+           *total = COSTS_N_INSNS (AVR_HAVE_JMP_CALL ? 2 : 1);
+         else
+           return false;
+         break;
+
+       case HImode:
+         if (AVR_HAVE_MUL)
+           *total = COSTS_N_INSNS (!speed ? 7 : 10);
+         else if (!speed)
+           *total = COSTS_N_INSNS (AVR_HAVE_JMP_CALL ? 2 : 1);
+         else
+           return false;
+         break;
+
+       default:
+         return false;
+       }
+      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code, speed);
+      *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code, speed);
+      return true;
+
+    case DIV:
+    case MOD:
+    case UDIV:
+    case UMOD:
+      if (!speed)
+       *total = COSTS_N_INSNS (AVR_HAVE_JMP_CALL ? 2 : 1);
+      else
+       return false;
+      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code, speed);
+      *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code, speed);
+      return true;
+
+    case ROTATE:
+      switch (mode)
+       {
+       case QImode:
+         if (CONST_INT_P (XEXP (x, 1)) && INTVAL (XEXP (x, 1)) == 4)
+           *total = COSTS_N_INSNS (1);
+
+         break;
+
+       case HImode:
+         if (CONST_INT_P (XEXP (x, 1)) && INTVAL (XEXP (x, 1)) == 8)
+           *total = COSTS_N_INSNS (3);
+
+         break;
+
+       case SImode:
+         if (CONST_INT_P (XEXP (x, 1)))
+           switch (INTVAL (XEXP (x, 1)))
+             {
+             case 8:
+             case 24:
+               *total = COSTS_N_INSNS (5);
+               break;
+             case 16:
+               *total = COSTS_N_INSNS (AVR_HAVE_MOVW ? 4 : 6);
+               break;
+             }
+         break;
+
+       default:
+         return false;
+       }
+      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code, speed);
+      return true;    
+
+    case ASHIFT:
+      switch (mode)
+       {
+       case QImode:
+         if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+           {
+             *total = COSTS_N_INSNS (!speed ? 4 : 17);
+             *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code, speed);
+           }
+         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 (!speed ? 5 : 41);
+             *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code, speed);
+           }
+         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 (!speed ? 5 : 8);
+               break;
+             case 6:
+               *total = COSTS_N_INSNS (!speed ? 5 : 9);
+               break;
+             case 5:
+               *total = COSTS_N_INSNS (!speed ? 5 : 10);
+               break;
+             default:
+               *total = COSTS_N_INSNS (!speed ? 5 : 41);
+               *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code, speed);
+             }
+         break;
+
+       case SImode:
+         if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+           {
+             *total = COSTS_N_INSNS (!speed ? 7 : 113);
+             *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code, speed);
+           }
+         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 (!speed ? 7 : 8);
+               break;
+             default:
+               *total = COSTS_N_INSNS (!speed ? 7 : 113);
+               *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code, speed);
+             }
+         break;
+
+       default:
+         return false;
+       }
+      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code, speed);
+      return true;
 
-/* Choose the order in which to allocate hard registers for
-   pseudo-registers local to a basic block.
+    case ASHIFTRT:
+      switch (mode)
+       {
+       case QImode:
+         if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+           {
+             *total = COSTS_N_INSNS (!speed ? 4 : 17);
+             *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code, speed);
+           }
+         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;
 
-   Store the desired register order in the array `reg_alloc_order'.
-   Element 0 should be the register to allocate first; element 1, the
-   next register; and so on.  */
+       case HImode:
+         if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+           {
+             *total = COSTS_N_INSNS (!speed ? 5 : 41);
+             *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code, speed);
+           }
+         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 (!speed ? 5 : 6);
+               break;
+              case 12:
+                *total = COSTS_N_INSNS (!speed ? 5 : 7);
+               break;
+              case 6:
+             case 13:
+                *total = COSTS_N_INSNS (!speed ? 5 : 8);
+               break;
+             default:
+               *total = COSTS_N_INSNS (!speed ? 5 : 41);
+               *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code, speed);
+             }
+         break;
 
-void
-order_regs_for_local_alloc ()
-{
-  unsigned int i;
-  static const int order_0[] = {
-    24,25,
-    18,19,
-    20,21,
-    22,23,
-    30,31,
-    26,27,
-    28,29,
-    17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,
-    0,1,
-    32,33,34,35
-  };
-  static const int order_1[] = {
-    18,19,
-    20,21,
-    22,23,
-    24,25,
-    30,31,
-    26,27,
-    28,29,
-    17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,
-    0,1,
-    32,33,34,35
-  };
-  static const int order_2[] = {
-    25,24,
-    23,22,
-    21,20,
-    19,18,
-    30,31,
-    26,27,
-    28,29,
-    17,16,
-    15,14,13,12,11,10,9,8,7,6,5,4,3,2,
-    1,0,
-    32,33,34,35
-  };
-  
-  const int *order = (TARGET_ORDER_1 ? order_1 :
-                     TARGET_ORDER_2 ? order_2 :
-                     order_0);
-  for (i=0; i < ARRAY_SIZE (order_0); ++i)
-      reg_alloc_order[i] = order[i];
-}
+       case SImode:
+         if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+           {
+             *total = COSTS_N_INSNS (!speed ? 7 : 113);
+             *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code, speed);
+           }
+         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 (!speed ? 7 : 8);
+               break;
+             case 31:
+               *total = COSTS_N_INSNS (AVR_HAVE_MOVW ? 4 : 5);
+               break;
+             default:
+               *total = COSTS_N_INSNS (!speed ? 7 : 113);
+               *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code, speed);
+             }
+         break;
 
-/* Calculate the cost of X code of the expression in which it is contained,
-   found in OUTER_CODE */
+       default:
+         return false;
+       }
+      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code, speed);
+      return true;
 
-int
-default_rtx_costs (X, code, outer_code)
-     rtx X;
-     enum rtx_code code;
-     enum rtx_code outer_code;
-{
-  int cost=0;
-  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 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)
+    case LSHIFTRT:
+      switch (mode)
        {
-         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)));
+       case QImode:
+         if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+           {
+             *total = COSTS_N_INSNS (!speed ? 4 : 17);
+             *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code, speed);
+           }
+         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 (!speed ? 5 : 41);
+             *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code, speed);
+           }
+         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 (!speed ? 5 : 6);
+               break;
+             case 4:
+               *total = COSTS_N_INSNS (!speed ? 5 : 7);
+               break;
+             case 5:
+             case 6:
+               *total = COSTS_N_INSNS (!speed ? 5 : 9);
+               break;
+             default:
+               *total = COSTS_N_INSNS (!speed ? 5 : 41);
+               *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code, speed);
+             }
+         break;
+
+       case SImode:
+         if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+           {
+             *total = COSTS_N_INSNS (!speed ? 7 : 113);
+             *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code, speed);
+           }
          else
-           cost = GET_MODE_SIZE (GET_MODE (X));
+           switch (INTVAL (XEXP (x, 1)))
+             {
+             case 0:
+               *total = 0;
+               break;
+             case 1:
+               *total = COSTS_N_INSNS (4);
+               break;
+             case 2:
+               *total = COSTS_N_INSNS (!speed ? 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 (!speed ? 7 : 113);
+               *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code, speed);
+             }
+         break;
+
+       default:
+         return false;
        }
-      break;
+      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code, speed);
+      return true;
+
     case COMPARE:
-      if (GET_CODE (XEXP (X,1)) == CONST_INT)
-       cost = GET_MODE_SIZE (GET_MODE (XEXP (X,0)));
-      break;
+      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, speed);
+         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, speed);
+         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, speed);
+         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, speed);
+      return true;
+
     default:
       break;
     }
-  return cost;
+  return false;
 }
 
-/* Calculate the cost of a memory address */
+/* Calculate the cost of a memory address */
 
-int
-avr_address_cost (x)
-     rtx x;
+static int
+avr_address_cost (rtx x, bool speed ATTRIBUTE_UNUSED)
 {
   if (GET_CODE (x) == PLUS
       && GET_CODE (XEXP (x,1)) == CONST_INT
@@ -4937,66 +5630,50 @@ avr_address_cost (x)
     return 18;
   if (CONSTANT_ADDRESS_P (x))
     {
-      if (io_address_p (x, 1))
+      if (optimize > 0 && io_address_operand (x, QImode))
        return 2;
       return 4;
     }
   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)
     {
@@ -5009,19 +5686,18 @@ avr_normalize_condition (condition)
     case LEU:
       return LTU;
     default:
-      abort ();
+      gcc_unreachable ();
     }
 }
 
-/* This fnction optimizes conditional jumps */
+/* This function optimizes conditional jumps.  */
 
-void
-machine_dependent_reorg (first_insn)
-     rtx first_insn;
+static void
+avr_reorg (void)
 {
   rtx insn, pattern;
   
-  for (insn = first_insn; insn; insn = NEXT_INSN (insn))
+  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
     {
       if (! (GET_CODE (insn) == INSN
             || GET_CODE (insn) == CALL_INSN
@@ -5039,7 +5715,7 @@ machine_dependent_reorg (first_insn)
        {
          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
@@ -5065,7 +5741,7 @@ machine_dependent_reorg (first_insn)
                  rtx t = XEXP (src,0);
                  enum machine_mode mode = GET_MODE (XEXP (pattern, 0));
 
-                 if (avr_simplify_comparision_p (mode, GET_CODE (t), x))
+                 if (avr_simplify_comparison_p (mode, GET_CODE (t), x))
                    {
                      XEXP (pattern, 1) = gen_int_mode (INTVAL (x) + 1, mode);
                      PUT_CODE (t, avr_normalize_condition (GET_CODE (t)));
@@ -5083,9 +5759,8 @@ machine_dependent_reorg (first_insn)
              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_COMPARE (GET_MODE (SET_SRC (pattern)), const0_rtx,
+                                              SET_SRC (pattern));
              INSN_CODE (next) = -1;
              INSN_CODE (insn) = -1;
            }
@@ -5096,31 +5771,30 @@ machine_dependent_reorg (first_insn)
 /* 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 (const_tree type, 
+                   const_tree func ATTRIBUTE_UNUSED, 
+                   bool outgoing ATTRIBUTE_UNUSED)
 {
   unsigned int offs;
   
@@ -5135,85 +5809,42 @@ 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 non-zero 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 rclass)
 {
-  return class;
+  return rclass;
 }
 
 int
-test_hard_reg_class (class, x)
-     enum reg_class class;
-     rtx x;
+test_hard_reg_class (enum reg_class rclass, rtx x)
 {
   int regno = true_regnum (x);
   if (regno < 0)
     return 0;
 
-  if (TEST_HARD_REG_CLASS (class, regno))
+  if (TEST_HARD_REG_CLASS (rclass, regno))
     return 1;
 
   return 0;
 }
 
-void
-debug_hard_reg_set (set)
-     HARD_REG_SET set;
-{
-  int i;
-  for (i=0; i < FIRST_PSEUDO_REGISTER; ++i)
-    {
-      if (TEST_HARD_REG_BIT (set, i))
-       {
-         fprintf (stderr, "r%-2d ", i);
-       }
-    }
-  fprintf (stderr, "\n");
-}
 
 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)
                      : dest);
   int jump_addr = INSN_ADDRESSES (INSN_UID (insn));
   int dest_addr = INSN_ADDRESSES (uid);
-  return dest_addr - jump_addr == 2;
+  return dest_addr - jump_addr == get_attr_length (insn) + 1;
 }
 
 /* Returns 1 if a value of mode MODE can be stored starting with hard
@@ -5222,75 +5853,33 @@ 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)
+  /* Disallow QImode in stack pointer regs.  */
+  if ((regno == REG_SP || regno == (REG_SP + 1)) && mode == QImode)
     return 0;
 
-  if (mode == QImode)
+  /* The only thing that can go into registers r28:r29 is a Pmode.  */
+  if (regno == REG_Y && mode == Pmode)
     return 1;
-  /*  if (regno < 24 && !AVR_ENHANCED)
-      return 1;*/
-  return !(regno & 1);
-}
-
-/* Returns 1 if we know register operand OP was 0 before INSN.  */
-
-static int
-reg_was_0 (insn, op)
-     rtx insn;
-     rtx op;
-{
-  rtx link;
-  return (optimize > 0 && insn && op && REG_P (op)
-         && (link = find_reg_note (insn, REG_WAS_0, 0))
-         /* Make sure the insn that stored the 0 is still present.  */
-         && ! INSN_DELETED_P (XEXP (link, 0))
-         && GET_CODE (XEXP (link, 0)) != NOTE
-         /* Make sure cross jumping didn't happen here.  */
-         && no_labels_between_p (XEXP (link, 0), insn)
-         /* Make sure the reg hasn't been clobbered.  */
-         && ! reg_set_between_p (op, XEXP (link, 0), insn));
-}
 
-/* Returns 1 if X is a valid address for an I/O register of size SIZE
-   (1 or 2).  Used for lds/sts -> in/out optimization.  */
+  /* 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;
 
-static int
-io_address_p (x, size)
-     rtx x;
-     int size;
-{
-  return (optimize > 0 && GET_CODE (x) == CONST_INT
-         && INTVAL (x) >= 0x20 && INTVAL (x) <= 0x60 - size);
-}
+  if (mode == QImode)
+    return 1;
 
-/* Returns nonzero (bit number + 1) if X, or -X, is a constant power of 2.  */
+  /* Modes larger than QImode occupy consecutive registers.  */
+  if (regno + GET_MODE_SIZE (mode) > FIRST_PSEUDO_REGISTER)
+    return 0;
 
-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;
+  /* All modes larger than QImode should start in an even register.  */
+  return !(regno & 1);
 }
 
 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)
@@ -5330,10 +5919,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);
@@ -5383,9 +5969,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";
 
@@ -5395,38 +5979,149 @@ 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)
 {
-  if (AVR_MEGA)
-    fprintf (stream, "\t.word pm(.L%d)\n", value);
+  switch_to_section (progmem_section);
+  if (AVR_HAVE_JMP_CALL)
+    fprintf (stream, "\t.word gs(.L%d)\n", value);
   else
     fprintf (stream, "\trjmp .L%d\n", value);
-
-  jump_tables_size++;
 }
 
-/* Returns 1 if SCRATCH are safe to be allocated as a scratch
+/* Returns true if SCRATCH are safe to be allocated as a scratch
    registers (for a define_peephole2) in the current function.  */
 
+bool
+avr_hard_regno_scratch_ok (unsigned int regno)
+{
+  /* Interrupt functions can only use registers that have already been saved
+     by the prologue, even if they would normally be call-clobbered.  */
+
+  if ((cfun->machine->is_interrupt || cfun->machine->is_signal)
+      && !df_regs_ever_live_p (regno))
+    return false;
+
+  return true;
+}
+
+/* Return nonzero if register OLD_REG can be renamed to register NEW_REG.  */
+
 int
-avr_peep2_scratch_safe (scratch)
-     rtx scratch;
+avr_hard_regno_rename_ok (unsigned int old_reg ATTRIBUTE_UNUSED,
+                         unsigned int new_reg)
 {
-  if ((interrupt_function_p (current_function_decl)
-       || signal_function_p (current_function_decl))
-      && leaf_function_p ())
-    {
-      int first_reg = true_regnum (scratch);
-      int last_reg = first_reg + GET_MODE_SIZE (GET_MODE (scratch)) - 1;
-      int reg;
+  /* Interrupt functions can only use registers that have already been
+     saved by the prologue, even if they would normally be
+     call-clobbered.  */
+
+  if ((cfun->machine->is_interrupt || cfun->machine->is_signal)
+      && !df_regs_ever_live_p (new_reg))
+    return 0;
+
+  return 1;
+}
+
+/* Output a branch that tests a single bit of a register (QI, HI or SImode)
+   or memory location in the I/O space (QImode only).
+
+   Operand 0: comparison operator (must be EQ or NE, compare bit to zero).
+   Operand 1: register operand to test, or CONST_INT memory address.
+   Operand 2: bit number (for QImode operand) or mask (HImode, SImode).
+   Operand 3: label to jump to if the test is true.  */
+
+const char *
+avr_out_sbxx_branch (rtx insn, rtx operands[])
+{
+  enum rtx_code comp = GET_CODE (operands[0]);
+  int long_jump = (get_attr_length (insn) >= 4);
+  int reverse = long_jump || jump_over_one_insn_p (insn, operands[3]);
+
+  if (comp == GE)
+    comp = EQ;
+  else if (comp == LT)
+    comp = NE;
 
-      for (reg = first_reg; reg <= last_reg; reg++)
+  if (reverse)
+    comp = reverse_condition (comp);
+
+  if (GET_CODE (operands[1]) == CONST_INT)
+    {
+      if (INTVAL (operands[1]) < 0x40)
        {
-         if (!regs_ever_live[reg])
-           return 0;
+         if (comp == EQ)
+           output_asm_insn (AS2 (sbis,%1-0x20,%2), operands);
+         else
+           output_asm_insn (AS2 (sbic,%1-0x20,%2), operands);
+       }
+      else
+       {
+         output_asm_insn (AS2 (in,__tmp_reg__,%1-0x20), operands);
+         if (comp == EQ)
+           output_asm_insn (AS2 (sbrs,__tmp_reg__,%2), operands);
+         else
+           output_asm_insn (AS2 (sbrc,__tmp_reg__,%2), operands);
        }
     }
-  return 1;
+  else  /* GET_CODE (operands[1]) == REG */
+    {
+      if (GET_MODE (operands[1]) == QImode)
+       {
+         if (comp == EQ)
+           output_asm_insn (AS2 (sbrs,%1,%2), operands);
+         else
+           output_asm_insn (AS2 (sbrc,%1,%2), operands);
+       }
+      else  /* HImode or SImode */
+       {
+         static char buf[] = "sbrc %A1,0";
+         int bit_nr = exact_log2 (INTVAL (operands[2])
+                                  & GET_MODE_MASK (GET_MODE (operands[1])));
+
+         buf[3] = (comp == EQ) ? 's' : 'c';
+         buf[6] = 'A' + (bit_nr >> 3);
+         buf[9] = '0' + (bit_nr & 7);
+         output_asm_insn (buf, operands);
+       }
+    }
+
+  if (long_jump)
+    return (AS1 (rjmp,.+4) CR_TAB
+           AS1 (jmp,%3));
+  if (!reverse)
+    return AS1 (rjmp,%3);
+  return "";
+}
+
+/* Worker function for TARGET_ASM_CONSTRUCTOR.  */
+
+static void
+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 (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 (const_tree type, const_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"