avr.h (machine_function): Add 'is_leaf' field.
[platform/upstream/gcc.git] / gcc / config / avr / avr.c
index 950777c..e1d7775 100644 (file)
@@ -1,5 +1,5 @@
 /* Subroutines for insn-output.c for ATMEL AVR micro controllers
-   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007
+   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2008
    Free Software Foundation, Inc.
    Contributed by Denis Chertykov (denisc@overta.ru)
 
@@ -7,7 +7,7 @@
 
    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.
    
    GCC is distributed in the hope that it will be useful,
@@ -16,9 +16,8 @@
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with GCC; see the file COPYING.  If not, write to
-   the Free Software Foundation, 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301, USA.  */
+   along with GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
@@ -44,6 +43,7 @@
 #include "tm_p.h"
 #include "target.h"
 #include "target-def.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))
@@ -51,6 +51,7 @@
 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_regs_to_save (HARD_REG_SET *);
 static int sequent_regs_live (void);
 static const char *ptrreg_to_str (int);
@@ -61,6 +62,7 @@ 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 (rtx, unsigned int, int);
 static void avr_file_start (void);
@@ -77,7 +79,7 @@ static void avr_asm_out_dtor (rtx, int);
 static int avr_operand_rtx_cost (rtx, enum machine_mode, enum rtx_code);
 static bool avr_rtx_costs (rtx, int, int, int *);
 static int avr_address_cost (rtx);
-static bool avr_return_in_memory (tree, tree);
+static bool avr_return_in_memory (const_tree, const_tree);
 static struct machine_function * avr_init_machine_status (void);
 /* Allocate registers from r25 to r8 for parameters for function calls.  */
 #define FIRST_CUM_REG 26
@@ -94,23 +96,14 @@ 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;
-
 /* Preprocessor macros to define depending on MCU type.  */
 const char *avr_base_arch_macro;
 const char *avr_extra_arch_macro;
 
-section *progmem_section;
+/* Current architecture.  */
+const struct base_arch_s *avr_current_arch;
 
-/* More than 8K of program memory: use "call" and "jmp".  */
-int avr_mega_p = 0;
+section *progmem_section;
 
 /* Core have 'MUL*' instructions.  */
 int avr_have_mul_p = 0;
@@ -121,22 +114,18 @@ int avr_asm_only_p = 0;
 /* Core have 'MOVW' and 'LPM Rx,Z' instructions.  */
 int avr_have_movw_lpmx_p = 0;
 
-struct base_arch_s {
-  int asm_only;
-  int have_mul;
-  int mega;
-  int have_movw_lpmx;
-  const char *const macro;
-};
-
 static const struct base_arch_s avr_arch_types[] = {
-  { 1, 0, 0, 0,  NULL },  /* unknown device specified */
-  { 1, 0, 0, 0, "__AVR_ARCH__=1" },
-  { 0, 0, 0, 0, "__AVR_ARCH__=2" },
-  { 0, 0, 0, 1, "__AVR_ARCH__=25"},
-  { 0, 0, 1, 0, "__AVR_ARCH__=3" },
-  { 0, 1, 0, 1, "__AVR_ARCH__=4" },
-  { 0, 1, 1, 1, "__AVR_ARCH__=5" }
+  { 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"   }
 };
 
 /* These names are used as the index into the avr_arch_types[] table 
@@ -149,8 +138,12 @@ enum avr_arch
   ARCH_AVR2,
   ARCH_AVR25,
   ARCH_AVR3,
+  ARCH_AVR31,
+  ARCH_AVR35,
   ARCH_AVR4,
-  ARCH_AVR5
+  ARCH_AVR5,
+  ARCH_AVR51,
+  ARCH_AVR6
 };
 
 struct mcu_type_s {
@@ -196,26 +189,38 @@ static const struct mcu_type_s avr_mcu_types[] = {
   { "attiny261",    ARCH_AVR25, "__AVR_ATtiny261__" },
   { "attiny461",    ARCH_AVR25, "__AVR_ATtiny461__" },
   { "attiny861",    ARCH_AVR25, "__AVR_ATtiny861__" },
+  { "attiny43u",    ARCH_AVR25, "__AVR_ATtiny43U__" },
+  { "attiny48",     ARCH_AVR25, "__AVR_ATtiny48__" },
+  { "attiny88",     ARCH_AVR25, "__AVR_ATtiny88__" },
   { "at86rf401",    ARCH_AVR25, "__AVR_AT86RF401__" },
-    /* Classic, > 8K.  */
+    /* Classic, > 8K, <= 64K.  */
   { "avr3",         ARCH_AVR3, NULL },
-  { "atmega103",    ARCH_AVR3, "__AVR_ATmega103__" },
-  { "atmega603",    ARCH_AVR3, "__AVR_ATmega603__" },
   { "at43usb320",   ARCH_AVR3, "__AVR_AT43USB320__" },
   { "at43usb355",   ARCH_AVR3, "__AVR_AT43USB355__" },
   { "at76c711",     ARCH_AVR3, "__AVR_AT76C711__" },
+    /* Classic, == 128K.  */
+  { "avr31",        ARCH_AVR31, NULL },
+  { "atmega103",    ARCH_AVR31, "__AVR_ATmega103__" },
+    /* Classic + MOVW + JMP/CALL.  */
+  { "avr35",        ARCH_AVR35, NULL },
+  { "at90usb82",    ARCH_AVR35, "__AVR_AT90USB82__" },
+  { "at90usb162",   ARCH_AVR35, "__AVR_AT90USB162__" },
     /* Enhanced, <= 8K.  */
   { "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__" },
   { "at90pwm1",     ARCH_AVR4, "__AVR_AT90PWM1__" },
   { "at90pwm2",     ARCH_AVR4, "__AVR_AT90PWM2__" },
+  { "at90pwm2b",    ARCH_AVR4, "__AVR_AT90PWM2B__" },
   { "at90pwm3",     ARCH_AVR4, "__AVR_AT90PWM3__" },
-    /* Enhanced, > 8K.  */
+  { "at90pwm3b",    ARCH_AVR4, "__AVR_AT90PWM3B__" },
+    /* Enhanced, > 8K, <= 64K.  */
   { "avr5",         ARCH_AVR5, NULL },
   { "atmega16",     ARCH_AVR5, "__AVR_ATmega16__" },
   { "atmega161",    ARCH_AVR5, "__AVR_ATmega161__" },
@@ -225,6 +230,7 @@ static const struct mcu_type_s avr_mcu_types[] = {
   { "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__" },
@@ -234,10 +240,12 @@ static const struct mcu_type_s avr_mcu_types[] = {
   { "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__" },
+  { "atmega32hvb",  ARCH_AVR5, "__AVR_ATmega32HVB__" },
   { "atmega406",    ARCH_AVR5, "__AVR_ATmega406__" },
   { "atmega64",     ARCH_AVR5, "__AVR_ATmega64__" },
   { "atmega640",    ARCH_AVR5, "__AVR_ATmega640__" },
@@ -247,20 +255,27 @@ static const struct mcu_type_s avr_mcu_types[] = {
   { "atmega6450",   ARCH_AVR5, "__AVR_ATmega6450__" },
   { "atmega649",    ARCH_AVR5, "__AVR_ATmega649__" },
   { "atmega6490",   ARCH_AVR5, "__AVR_ATmega6490__" },
-  { "atmega128",    ARCH_AVR5, "__AVR_ATmega128__" },
-  { "atmega1280",   ARCH_AVR5, "__AVR_ATmega1280__" },
-  { "atmega1281",   ARCH_AVR5, "__AVR_ATmega1281__" },
   { "atmega16hva",  ARCH_AVR5, "__AVR_ATmega16HVA__" },
   { "at90can32",    ARCH_AVR5, "__AVR_AT90CAN32__" },
   { "at90can64",    ARCH_AVR5, "__AVR_AT90CAN64__" },
-  { "at90can128",   ARCH_AVR5, "__AVR_AT90CAN128__" },
-  { "at90usb82",    ARCH_AVR5, "__AVR_AT90USB82__" },
-  { "at90usb162",   ARCH_AVR5, "__AVR_AT90USB162__" },
+  { "at90pwm216",   ARCH_AVR5, "__AVR_AT90PWM216__" },
+  { "at90pwm316",   ARCH_AVR5, "__AVR_AT90PWM316__" },
   { "at90usb646",   ARCH_AVR5, "__AVR_AT90USB646__" },
   { "at90usb647",   ARCH_AVR5, "__AVR_AT90USB647__" },
-  { "at90usb1286",  ARCH_AVR5, "__AVR_AT90USB1286__" },
-  { "at90usb1287",  ARCH_AVR5, "__AVR_AT90USB1287__" },
   { "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__" },
+  { "at90can128",   ARCH_AVR51, "__AVR_AT90CAN128__" },
+  { "at90usb1286",  ARCH_AVR51, "__AVR_AT90USB1286__" },
+  { "at90usb1287",  ARCH_AVR51, "__AVR_AT90USB1287__" },
+    /* 3-Byte PC.  */
+  { "avr6",         ARCH_AVR6, NULL },
+  { "atmega2560",   ARCH_AVR6, "__AVR_ATmega2560__" },
+  { "atmega2561",   ARCH_AVR6, "__AVR_ATmega2561__" },
     /* Assembler only.  */
   { "avr1",         ARCH_AVR1, NULL },
   { "at90s1200",    ARCH_AVR1, "__AVR_AT90S1200__" },
@@ -338,16 +353,17 @@ avr_override_options (void)
        fprintf (stderr,"   %s\n", t->name);
     }
 
+  avr_current_arch = &avr_arch_types[t->arch];
   base = &avr_arch_types[t->arch];
   avr_asm_only_p = base->asm_only;
   avr_have_mul_p = base->have_mul;
-  avr_mega_p = base->mega;
   avr_have_movw_lpmx_p = base->have_movw_lpmx;
   avr_base_arch_macro = base->macro;
   avr_extra_arch_macro = t->macro;
 
   if (optimize && !TARGET_NO_TABLEJUMP)
-    avr_case_values_threshold = (!AVR_MEGA || TARGET_CALL_PROLOGUES) ? 8 : 17;
+    avr_case_values_threshold = 
+      (!AVR_HAVE_JMP_CALL || TARGET_CALL_PROLOGUES) ? 8 : 17;
 
   tmp_reg_rtx  = gen_rtx_REG (QImode, TMP_REGNO);
   zero_reg_rtx = gen_rtx_REG (QImode, ZERO_REGNO);
@@ -399,7 +415,7 @@ avr_naked_function_p (tree func)
 
   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;
 }
 
@@ -433,6 +449,19 @@ signal_function_p (tree func)
   return a != NULL_TREE;
 }
 
+/* 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 the number of hard registers to push/pop in the prologue/epilogue
    of the current function, and optionally store these registers in SET.  */
 
@@ -442,14 +471,18 @@ 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));
-  int leaf_func_p = leaf_function_p ();
+
+  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.  */
-  if (TREE_THIS_VOLATILE (current_function_decl))
+  /* No need to save any registers if the function never returns or 
+     is have "OS_task" attribute.  */
+  if (TREE_THIS_VOLATILE (current_function_decl)
+      || cfun->machine->is_OS_task)
     return 0;
 
   for (reg = 0; reg < 32; reg++)
@@ -459,8 +492,8 @@ avr_regs_to_save (HARD_REG_SET *set)
       if (fixed_regs[reg])
        continue;
 
-      if ((int_or_sig_p && !leaf_func_p && call_used_regs[reg])
-         || (regs_ever_live[reg]
+      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)))))
@@ -483,9 +516,10 @@ initial_elimination_offset (int from, int to)
   else
     {
       int offset = frame_pointer_needed ? 2 : 0;
+      int avr_pc_size = AVR_HAVE_EIJMP_EICALL ? 3 : 2;
 
       offset += avr_regs_to_save (NULL);
-      return get_frame_size () + 2 + 1 + offset;
+      return get_frame_size () + (avr_pc_size) + 1 + offset;
     }
 }
 
@@ -500,7 +534,6 @@ avr_simple_epilogue (void)
          && ! interrupt_function_p (current_function_decl)
          && ! signal_function_p (current_function_decl)
          && ! avr_naked_function_p (current_function_decl)
-         && ! MAIN_NAME_P (DECL_NAME (current_function_decl))
          && ! TREE_THIS_VOLATILE (current_function_decl));
 }
 
@@ -517,7 +550,7 @@ sequent_regs_live (void)
     {
       if (!call_used_regs[reg])
        {
-         if (regs_ever_live[reg])
+         if (df_regs_ever_live_p (reg))
            {
              ++live_seq;
              ++cur_seq;
@@ -529,7 +562,7 @@ sequent_regs_live (void)
 
   if (!frame_pointer_needed)
     {
-      if (regs_ever_live[REG_Y])
+      if (df_regs_ever_live_p (REG_Y))
        {
          ++live_seq;
          ++cur_seq;
@@ -537,7 +570,7 @@ sequent_regs_live (void)
       else
        cur_seq = 0;
 
-      if (regs_ever_live[REG_Y+1])
+      if (df_regs_ever_live_p (REG_Y+1))
        {
          ++live_seq;
          ++cur_seq;
@@ -559,6 +592,7 @@ void
 expand_prologue (void)
 {
   int live_seq;
+  HARD_REG_SET set;
   int minimize;
   HOST_WIDE_INT size = get_frame_size();
   /* Define templates for push instructions.  */
@@ -571,10 +605,10 @@ expand_prologue (void)
   last_insn_address = 0;
   
   /* Init cfun->machine.  */
-  cfun->machine->is_main = MAIN_NAME_P (DECL_NAME (current_function_decl));
   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);
   
   /* Prologue: naked.  */
   if (cfun->machine->is_naked)
@@ -582,9 +616,12 @@ expand_prologue (void)
       return;
     }
 
+  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_interrupt
+             && !cfun->machine->is_signal
+             && !cfun->machine->is_OS_task
              && live_seq);
 
   if (cfun->machine->is_interrupt || cfun->machine->is_signal)
@@ -610,7 +647,18 @@ expand_prologue (void)
       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;
@@ -618,28 +666,19 @@ expand_prologue (void)
       /* Prevent any attempt to delete the setting of ZERO_REG!  */
       emit_insn (gen_rtx_USE (VOIDmode, zero_reg_rtx));
     }
-  if (cfun->machine->is_main)
+  if (minimize && (frame_pointer_needed || live_seq > 6)) 
     {
-      char buffer[40];
-      sprintf (buffer, "%s - %d", avr_init_stack, (int) size);
-      rtx sym = gen_rtx_SYMBOL_REF (HImode, ggc_strdup (buffer));
-      /*  Initialise stack pointer using frame pointer.  */
-      insn = emit_move_insn (frame_pointer_rtx, sym);
+      insn = emit_move_insn (gen_rtx_REG (HImode, REG_X), 
+                             gen_int_mode (size, HImode));
       RTX_FRAME_RELATED_P (insn) = 1;
-      insn = emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
-      RTX_FRAME_RELATED_P (insn) = 1;
-    }
-  else if (minimize && (frame_pointer_needed || live_seq > 6)) 
-    {
+
       insn = 
-        emit_insn (gen_call_prologue_saves (gen_int_mode (size, HImode),
-                                            gen_int_mode (live_seq, HImode)));
+        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
     {
-      HARD_REG_SET set;
-      avr_regs_to_save (&set);
       int reg;
       for (reg = 0; reg < 32; ++reg)
         {
@@ -652,9 +691,13 @@ expand_prologue (void)
         }
       if (frame_pointer_needed)
         {
-          /* Push frame pointer.  */
-         insn = emit_move_insn (pushword, frame_pointer_rtx);
-          RTX_FRAME_RELATED_P (insn) = 1;
+         if(!cfun->machine->is_OS_task)
+           {
+              /* Push frame pointer.  */
+             insn = emit_move_insn (pushword, frame_pointer_rtx);
+              RTX_FRAME_RELATED_P (insn) = 1;
+           }
+
           if (!size)
             {
               insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
@@ -728,7 +771,7 @@ expand_prologue (void)
                   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), frame_pointer_rtx
+                                         gen_rtx_PLUS (GET_MODE(myfp), myfp
                                                        gen_int_mode (-size, GET_MODE(myfp))));
                   RTX_FRAME_RELATED_P (insn) = 1;
                   insn = emit_move_insn ( stack_pointer_rtx, frame_pointer_rtx);
@@ -758,10 +801,6 @@ avr_asm_function_end_prologue (FILE *file)
         {
           fputs ("/* prologue: Signal */\n", file);
         }
-      else if (cfun->machine->is_main)
-        {
-          fputs ("/* prologue: main */\n", file);
-        }
       else
         fputs ("/* prologue: function */\n", file);
     }
@@ -789,50 +828,40 @@ expand_epilogue (void)
 {
   int reg;
   int live_seq;
+  HARD_REG_SET set;      
   int minimize;
   HOST_WIDE_INT size = get_frame_size();
-  rtx insn;
   
   /* epilogue: naked  */
   if (cfun->machine->is_naked)
     {
-      insn = emit_jump_insn (gen_return ());
-      RTX_FRAME_RELATED_P (insn) = 1;
+      emit_jump_insn (gen_return ());
       return;
     }
 
+  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_interrupt
+             && !cfun->machine->is_signal
+             && !cfun->machine->is_OS_task
              && live_seq);
   
-  if (cfun->machine->is_main)
-    {
-      /* Return value from main() is already in the correct registers
-         (r25:r24) as the exit() argument.  */
-      insn = emit_jump_insn (gen_return ());
-      RTX_FRAME_RELATED_P (insn) = 1;
-    }
-  else if (minimize && (frame_pointer_needed || live_seq > 4))
+  if (minimize && (frame_pointer_needed || live_seq > 4))
     {
       if (frame_pointer_needed)
        {
           /*  Get rid of frame.  */
-          insn = 
-           emit_move_insn(frame_pointer_rtx,
-                           gen_rtx_PLUS (HImode, frame_pointer_rtx, 
-                                         gen_int_mode (size, HImode)));
-          RTX_FRAME_RELATED_P (insn) = 1;
+         emit_move_insn(frame_pointer_rtx,
+                         gen_rtx_PLUS (HImode, frame_pointer_rtx,
+                                       gen_int_mode (size, HImode)));
        }
       else
        {
-          insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
-          RTX_FRAME_RELATED_P (insn) = 1;
+          emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
        }
        
-      insn = 
-        emit_insn (gen_epilogue_restores (gen_int_mode (live_seq, HImode)));
-      RTX_FRAME_RELATED_P (insn) = 1;
+      emit_insn (gen_epilogue_restores (gen_int_mode (live_seq, HImode)));
     }
   else
     {
@@ -846,7 +875,7 @@ expand_epilogue (void)
               fp_plus_length = 
                get_attr_length (gen_move_insn (frame_pointer_rtx,
                                                 gen_rtx_PLUS (HImode, frame_pointer_rtx,
-                                                              gen_int_mode (size, 
+                                                              gen_int_mode (size,
                                                                            HImode))));
               /* Copy to stack pointer.  */
               fp_plus_length += 
@@ -859,66 +888,62 @@ expand_epilogue (void)
                   sp_plus_length = 
                    get_attr_length (gen_move_insn (stack_pointer_rtx,
                                                     gen_rtx_PLUS (HImode, stack_pointer_rtx,
-                                                                  gen_int_mode (size, 
+                                                                  gen_int_mode (size,
                                                                                HImode))));
                 }
               /* Use shortest method.  */
               if (size <= 5 && (sp_plus_length < fp_plus_length))
                 {
-                  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;
+                  emit_move_insn (stack_pointer_rtx,
+                                  gen_rtx_PLUS (HImode, stack_pointer_rtx,
+                                                gen_int_mode (size, HImode)));
                 }
               else
                 {
-                  insn = emit_move_insn (frame_pointer_rtx,
-                                         gen_rtx_PLUS (HImode, frame_pointer_rtx,
-                                                       gen_int_mode (size, HImode)));
-                 RTX_FRAME_RELATED_P (insn) = 1;          
+                  emit_move_insn (frame_pointer_rtx,
+                                  gen_rtx_PLUS (HImode, frame_pointer_rtx,
+                                                gen_int_mode (size, HImode)));
                   /* Copy to stack pointer.  */
-                  insn = emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
-                 RTX_FRAME_RELATED_P (insn) = 1;
+                  emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
                 }
             }
-        
-          /* Restore previous frame_pointer.  */
-         insn = emit_insn (gen_pophi (frame_pointer_rtx));
-          RTX_FRAME_RELATED_P (insn) = 1;
+         if(!cfun->machine->is_OS_task)
+           {
+              /* Restore previous frame_pointer.  */
+             emit_insn (gen_pophi (frame_pointer_rtx));
+           }
        }
       /* Restore used registers.  */
-      HARD_REG_SET set;      
-      avr_regs_to_save (&set);
       for (reg = 31; reg >= 0; --reg)
         {
           if (TEST_HARD_REG_BIT (set, reg))
-            {
-              insn = emit_insn (gen_popqi (gen_rtx_REG (QImode, reg)));
-              RTX_FRAME_RELATED_P (insn) = 1;
-            }
+              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.  */
-          insn = emit_insn (gen_popqi (tmp_reg_rtx));
-          RTX_FRAME_RELATED_P (insn) = 1;
+          emit_insn (gen_popqi (tmp_reg_rtx));
       
-          insn = emit_move_insn (gen_rtx_MEM(QImode, GEN_INT(SREG_ADDR)), 
-                                tmp_reg_rtx);
-          RTX_FRAME_RELATED_P (insn) = 1;
+          emit_move_insn (gen_rtx_MEM(QImode, GEN_INT(SREG_ADDR)), 
+                         tmp_reg_rtx);
 
           /* Restore tmp REG.  */
-          insn = emit_insn (gen_popqi (tmp_reg_rtx));
-          RTX_FRAME_RELATED_P (insn) = 1;
+          emit_insn (gen_popqi (tmp_reg_rtx));
 
           /* Restore zero REG.  */
-          insn = emit_insn (gen_popqi (zero_reg_rtx));
-         RTX_FRAME_RELATED_P (insn) = 1;
+          emit_insn (gen_popqi (zero_reg_rtx));
         }
 
-      insn = emit_jump_insn (gen_return ());
-      RTX_FRAME_RELATED_P (insn) = 1;
+      emit_jump_insn (gen_return ());
     }
 }
 
@@ -1100,7 +1125,7 @@ print_operand_address (FILE *file, rtx addr)
          && ((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 ,")");
        }
@@ -1122,9 +1147,14 @@ print_operand (FILE *file, rtx x, int 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)
@@ -1292,7 +1322,7 @@ avr_jump_mode (rtx x, rtx 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;
@@ -1652,9 +1682,6 @@ output_movhi (rtx insn, rtx operands[], int *l)
               or inside main or signal function prologue where they disabled.  */
              else if (TARGET_NO_INTERRUPTS 
                         || (reload_completed 
-                            && cfun->machine->is_main 
-                            && prologue_epilogue_contains (insn))
-                        || (reload_completed 
                             && cfun->machine->is_signal 
                             && prologue_epilogue_contains (insn)))
                 {
@@ -1818,7 +1845,7 @@ out_movqi_r_mr (rtx insn, rtx op[], int *l)
          *l = 1;
          return AS2 (in,%0,__SREG__);
        }
-      if (avr_io_address_p (x, 1))
+      if (optimize > 0 && io_address_operand (x, QImode))
        {
          *l = 1;
          return AS2 (in,%0,%1-0x20);
@@ -2006,7 +2033,7 @@ out_movhi_r_mr (rtx insn, rtx op[], int *l)
     }
   else if (CONSTANT_ADDRESS_P (base))
     {
-      if (avr_io_address_p (base, 2))
+      if (optimize > 0 && io_address_operand (base, HImode))
        {
          *l = 2;
          return (AS2 (in,%A0,%A1-0x20) CR_TAB
@@ -2506,7 +2533,7 @@ out_movqi_mr_r (rtx insn, rtx op[], int *l)
          *l = 1;
          return AS2 (out,__SREG__,%1);
        }
-      if (avr_io_address_p (x, 1))
+      if (optimize > 0 && io_address_operand (x, QImode))
        {
          *l = 1;
          return AS2 (out,%0-0x20,%1);
@@ -2585,7 +2612,7 @@ out_movhi_mr_r (rtx insn, rtx op[], int *l)
     l = &tmp;
   if (CONSTANT_ADDRESS_P (base))
     {
-      if (avr_io_address_p (base, 2))
+      if (optimize > 0 && io_address_operand (base, HImode))
        {
          *l = 2;
          return (AS2 (out,%B0-0x20,%B1) CR_TAB
@@ -2710,8 +2737,8 @@ out_movhi_mr_r (rtx insn, rtx op[], int *l)
 int
 frame_pointer_required_p (void)
 {
-  return (current_function_calls_alloca
-         || current_function_args_info.nregs == 0
+  return (cfun->calls_alloca
+         || crtl->args.info.nregs == 0
          || get_frame_size () > 0);
 }
 
@@ -4452,7 +4479,7 @@ avr_assemble_integer (rtx x, unsigned int size, int aligned_p)
       && ((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;
@@ -4470,7 +4497,7 @@ avr_assemble_integer (rtx x, unsigned int size, int aligned_p)
 void
 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++)
@@ -4523,7 +4550,7 @@ gas_output_ascii(FILE *file, const char *str, size_t 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
@@ -4580,7 +4607,8 @@ 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 },
   { NULL,        0, 0, false, false, false, NULL }
 };
 
@@ -4672,6 +4700,22 @@ avr_handle_fndecl_attribute (tree *node, tree name,
   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;
+    }
+
+  return NULL_TREE;
+}
+
 /* Look for attribute `progmem' in DECL
    if found return 1, otherwise 0.  */
 
@@ -4728,7 +4772,7 @@ avr_output_progmem_section_asm_op (const void *arg ATTRIBUTE_UNUSED)
 {
   fprintf (asm_out_file,
           "\t.section .progmem.gcc_sw_table, \"%s\", @progbits\n",
-          AVR_MEGA ? "a" : "ax");
+          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");
 }
@@ -4738,7 +4782,7 @@ avr_output_progmem_section_asm_op (const void *arg ATTRIBUTE_UNUSED)
 static void
 avr_asm_init_sections (void)
 {
-  progmem_section = get_unnamed_section (AVR_MEGA ? 0 : SECTION_CODE,
+  progmem_section = get_unnamed_section (AVR_HAVE_JMP_CALL ? 0 : SECTION_CODE,
                                         avr_output_progmem_section_asm_op,
                                         NULL);
   readonly_data_section = data_section;
@@ -4786,10 +4830,6 @@ avr_file_start (void)
      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);
-
-  commands_in_file = 0;
-  commands_in_prologues = 0;
-  commands_in_epilogues = 0;
 }
 
 /* Outputs to the stdio stream FILE some
@@ -4798,14 +4838,6 @@ avr_file_start (void)
 static void
 avr_file_end (void)
 {
-  fputs ("/* File ", asm_out_file);
-  output_quoted_string (asm_out_file, main_input_filename);
-  fprintf (asm_out_file,
-          ": code %4d = 0x%04x (%4d), prologues %3d, epilogues %3d */\n",
-          commands_in_file,
-          commands_in_file,
-          commands_in_file - commands_in_prologues - commands_in_epilogues,
-          commands_in_prologues, commands_in_epilogues);
 }
 
 /* Choose the order in which to allocate hard registers for
@@ -5035,7 +5067,7 @@ avr_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int *total)
          if (AVR_HAVE_MUL)
            *total = COSTS_N_INSNS (optimize_size ? 3 : 4);
          else if (optimize_size)
-           *total = COSTS_N_INSNS (AVR_MEGA ? 2 : 1);
+           *total = COSTS_N_INSNS (AVR_HAVE_JMP_CALL ? 2 : 1);
          else
            return false;
          break;
@@ -5044,7 +5076,7 @@ avr_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int *total)
          if (AVR_HAVE_MUL)
            *total = COSTS_N_INSNS (optimize_size ? 7 : 10);
          else if (optimize_size)
-           *total = COSTS_N_INSNS (AVR_MEGA ? 2 : 1);
+           *total = COSTS_N_INSNS (AVR_HAVE_JMP_CALL ? 2 : 1);
          else
            return false;
          break;
@@ -5061,7 +5093,7 @@ avr_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int *total)
     case UDIV:
     case UMOD:
       if (optimize_size)
-       *total = COSTS_N_INSNS (AVR_MEGA ? 2 : 1);
+       *total = COSTS_N_INSNS (AVR_HAVE_JMP_CALL ? 2 : 1);
       else
        return false;
       *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
@@ -5432,7 +5464,7 @@ avr_address_cost (rtx x)
     return 18;
   if (CONSTANT_ADDRESS_P (x))
     {
-      if (avr_io_address_p (x, 1))
+      if (optimize > 0 && io_address_operand (x, QImode))
        return 2;
       return 4;
     }
@@ -5594,7 +5626,7 @@ avr_libcall_value (enum machine_mode mode)
    function returns a value of data type VALTYPE.  */
 
 rtx
-avr_function_value (tree type, tree func ATTRIBUTE_UNUSED)
+avr_function_value (const_tree type, const_tree func ATTRIBUTE_UNUSED)
 {
   unsigned int offs;
   
@@ -5678,17 +5710,6 @@ avr_hard_regno_mode_ok (int regno, enum machine_mode mode)
   return !(regno & 1);
 }
 
-/* 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.  Add 0x20 to SIZE
-   to check for the lower half of I/O space (for cbi/sbi/sbic/sbis).  */
-
-int
-avr_io_address_p (rtx x, int size)
-{
-  return (optimize > 0 && GET_CODE (x) == CONST_INT
-         && INTVAL (x) >= 0x20 && INTVAL (x) <= 0x60 - size);
-}
-
 const char *
 output_reload_inhi (rtx insn ATTRIBUTE_UNUSED, rtx *operands, int *len)
 {
@@ -5793,8 +5814,8 @@ void
 avr_output_addr_vec_elt (FILE *stream, int value)
 {
   switch_to_section (progmem_section);
-  if (AVR_MEGA)
-    fprintf (stream, "\t.word pm(.L%d)\n", value);
+  if (AVR_HAVE_JMP_CALL)
+    fprintf (stream, "\t.word gs(.L%d)\n", value);
   else
     fprintf (stream, "\trjmp .L%d\n", value);
 }
@@ -5815,7 +5836,7 @@ avr_peep2_scratch_safe (rtx scratch)
 
       for (reg = first_reg; reg <= last_reg; reg++)
        {
-         if (!regs_ever_live[reg])
+         if (!df_regs_ever_live_p (reg))
            return 0;
        }
     }
@@ -5914,7 +5935,7 @@ avr_asm_out_dtor (rtx symbol, int priority)
 /* Worker function for TARGET_RETURN_IN_MEMORY.  */
 
 static bool
-avr_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
+avr_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
 {
   if (TYPE_MODE (type) == BLKmode)
     {