X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gcc%2Fconfig%2Favr%2Favr.c;h=e1d77758c3cdcf8ad189384787bc63e4e122402d;hb=4c75f709287a6fd3bcf95ab1b845528574855266;hp=d222a53d3c07f29f1a1dcbdfa9d5082e17d63717;hpb=dd6d1f8c3f8cd06fa2aa436de20a88c46a84d33c;p=platform%2Fupstream%2Fgcc.git diff --git a/gcc/config/avr/avr.c b/gcc/config/avr/avr.c index d222a53..e1d7775 100644 --- a/gcc/config/avr/avr.c +++ b/gcc/config/avr/avr.c @@ -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 + . */ #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,23 +51,24 @@ 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); static const char *cond_string (enum rtx_code); static int avr_num_arg_regs (enum machine_mode, tree); -static int out_adj_frame_ptr (FILE *, int); -static int out_set_stack_ptr (FILE *, int, int); + static RTX_CODE compare_condition (rtx insn); static int compare_sign_p (rtx insn); static tree avr_handle_progmem_attribute (tree *, tree, tree, int, bool *); static tree avr_handle_fndecl_attribute (tree *, tree, tree, int, bool *); +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); static void avr_file_end (void); -static void avr_output_function_prologue (FILE *, HOST_WIDE_INT); -static void avr_output_function_epilogue (FILE *, HOST_WIDE_INT); +static void avr_asm_function_end_prologue (FILE *); +static void avr_asm_function_begin_epilogue (FILE *); 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); @@ -78,8 +79,8 @@ 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 @@ -95,30 +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; - -/* 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; - /* 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; @@ -129,22 +114,36 @@ 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, 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" } }; -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, 1, 0, "__AVR_ARCH__=3" }, - { 0, 1, 0, 1, "__AVR_ARCH__=4" }, - { 0, 1, 1, 1, "__AVR_ARCH__=5" }, - { 0, 0, 0, 1, "__AVR_ARCH__=25"} +/* These names are used as the index into the avr_arch_types[] table + above. */ + +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 { @@ -164,97 +163,127 @@ struct mcu_type_s { static const struct mcu_type_s avr_mcu_types[] = { /* Classic, <= 8K. */ - { "avr2", 2, NULL }, - { "at90s2313", 2, "__AVR_AT90S2313__" }, - { "at90s2323", 2, "__AVR_AT90S2323__" }, - { "at90s2333", 2, "__AVR_AT90S2333__" }, - { "at90s2343", 2, "__AVR_AT90S2343__" }, - { "attiny22", 2, "__AVR_ATtiny22__" }, - { "attiny26", 2, "__AVR_ATtiny26__" }, - { "at90s4414", 2, "__AVR_AT90S4414__" }, - { "at90s4433", 2, "__AVR_AT90S4433__" }, - { "at90s4434", 2, "__AVR_AT90S4434__" }, - { "at90s8515", 2, "__AVR_AT90S8515__" }, - { "at90c8534", 2, "__AVR_AT90C8534__" }, - { "at90s8535", 2, "__AVR_AT90S8535__" }, + { "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", 6, NULL }, - { "attiny13", 6, "__AVR_ATtiny13__" }, - { "attiny2313", 6, "__AVR_ATtiny2313__" }, - { "attiny24", 6, "__AVR_ATtiny24__" }, - { "attiny44", 6, "__AVR_ATtiny44__" }, - { "attiny84", 6, "__AVR_ATtiny84__" }, - { "attiny25", 6, "__AVR_ATtiny25__" }, - { "attiny45", 6, "__AVR_ATtiny45__" }, - { "attiny85", 6, "__AVR_ATtiny85__" }, - { "attiny261", 6, "__AVR_ATtiny261__" }, - { "attiny461", 6, "__AVR_ATtiny461__" }, - { "attiny861", 6, "__AVR_ATtiny861__" }, - { "at86rf401", 6, "__AVR_AT86RF401__" }, - /* Classic, > 8K. */ - { "avr3", 3, NULL }, - { "atmega103", 3, "__AVR_ATmega103__" }, - { "atmega603", 3, "__AVR_ATmega603__" }, - { "at43usb320", 3, "__AVR_AT43USB320__" }, - { "at43usb355", 3, "__AVR_AT43USB355__" }, - { "at76c711", 3, "__AVR_AT76C711__" }, + { "avr25", ARCH_AVR25, NULL }, + { "attiny13", ARCH_AVR25, "__AVR_ATtiny13__" }, + { "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__" }, + { "attiny48", ARCH_AVR25, "__AVR_ATtiny48__" }, + { "attiny88", ARCH_AVR25, "__AVR_ATtiny88__" }, + { "at86rf401", ARCH_AVR25, "__AVR_AT86RF401__" }, + /* Classic, > 8K, <= 64K. */ + { "avr3", ARCH_AVR3, NULL }, + { "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", 4, NULL }, - { "atmega8", 4, "__AVR_ATmega8__" }, - { "atmega48", 4, "__AVR_ATmega48__" }, - { "atmega88", 4, "__AVR_ATmega88__" }, - { "atmega8515", 4, "__AVR_ATmega8515__" }, - { "atmega8535", 4, "__AVR_ATmega8535__" }, - { "at90pwm1", 4, "__AVR_AT90PWM1__" }, - { "at90pwm2", 4, "__AVR_AT90PWM2__" }, - { "at90pwm3", 4, "__AVR_AT90PWM3__" }, - /* Enhanced, > 8K. */ - { "avr5", 5, NULL }, - { "atmega16", 5, "__AVR_ATmega16__" }, - { "atmega161", 5, "__AVR_ATmega161__" }, - { "atmega162", 5, "__AVR_ATmega162__" }, - { "atmega163", 5, "__AVR_ATmega163__" }, - { "atmega164p",5, "__AVR_ATmega164P__" }, - { "atmega165", 5, "__AVR_ATmega165__" }, - { "atmega165p",5, "__AVR_ATmega165P__" }, - { "atmega168", 5, "__AVR_ATmega168__" }, - { "atmega169", 5, "__AVR_ATmega169__" }, - { "atmega169p",5, "__AVR_ATmega169P__" }, - { "atmega32", 5, "__AVR_ATmega32__" }, - { "atmega323", 5, "__AVR_ATmega323__" }, - { "atmega324p",5, "__AVR_ATmega324P__" }, - { "atmega325", 5, "__AVR_ATmega325__" }, - { "atmega3250", 5, "__AVR_ATmega3250__" }, - { "atmega329", 5, "__AVR_ATmega329__" }, - { "atmega3290", 5, "__AVR_ATmega3290__" }, - { "atmega406", 5, "__AVR_ATmega406__" }, - { "atmega64", 5, "__AVR_ATmega64__" }, - { "atmega640", 5, "__AVR_ATmega640__" }, - { "atmega644", 5, "__AVR_ATmega644__" }, - { "atmega644p",5, "__AVR_ATmega644P__" }, - { "atmega645", 5, "__AVR_ATmega645__" }, - { "atmega6450", 5, "__AVR_ATmega6450__" }, - { "atmega649", 5, "__AVR_ATmega649__" }, - { "atmega6490", 5, "__AVR_ATmega6490__" }, - { "atmega128", 5, "__AVR_ATmega128__" }, - { "atmega1280",5, "__AVR_ATmega1280__" }, - { "atmega1281",5, "__AVR_ATmega1281__" }, - { "at90can32", 5, "__AVR_AT90CAN32__" }, - { "at90can64", 5, "__AVR_AT90CAN64__" }, - { "at90can128", 5, "__AVR_AT90CAN128__" }, - { "at90usb646", 5, "__AVR_AT90USB646__" }, - { "at90usb647", 5, "__AVR_AT90USB647__" }, - { "at90usb1286", 5, "__AVR_AT90USB1286__" }, - { "at90usb1287", 5, "__AVR_AT90USB1287__" }, - { "at94k", 5, "__AVR_AT94K__" }, + { "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__" }, + { "at90pwm3b", ARCH_AVR4, "__AVR_AT90PWM3B__" }, + /* 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__" }, + { "atmega32hvb", ARCH_AVR5, "__AVR_ATmega32HVB__" }, + { "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__" }, + { "at90can32", ARCH_AVR5, "__AVR_AT90CAN32__" }, + { "at90can64", ARCH_AVR5, "__AVR_AT90CAN64__" }, + { "at90pwm216", ARCH_AVR5, "__AVR_AT90PWM216__" }, + { "at90pwm316", ARCH_AVR5, "__AVR_AT90PWM316__" }, + { "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__" }, + { "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", 1, NULL }, - { "at90s1200", 1, "__AVR_AT90S1200__" }, - { "attiny11", 1, "__AVR_ATtiny11__" }, - { "attiny12", 1, "__AVR_ATtiny12__" }, - { "attiny15", 1, "__AVR_ATtiny15__" }, - { "attiny28", 1, "__AVR_ATtiny28__" }, - { NULL, 0, NULL } + { "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; @@ -277,10 +306,10 @@ int avr_case_values_threshold = 30000; #undef TARGET_ASM_FILE_END #define TARGET_ASM_FILE_END avr_file_end -#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_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_ATTRIBUTE_TABLE #define TARGET_ATTRIBUTE_TABLE avr_attribute_table #undef TARGET_ASM_FUNCTION_RODATA_SECTION @@ -310,6 +339,8 @@ avr_override_options (void) const struct mcu_type_s *t; const struct base_arch_s *base; + flag_delete_null_pointer_checks = 0; + for (t = avr_mcu_types; t->name; t++) if (strcmp (t->name, avr_mcu_name) == 0) break; @@ -322,19 +353,22 @@ 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); + + init_machine_status = avr_init_machine_status; } /* return register class from register number. */ @@ -353,6 +387,15 @@ static const int reg_class_tab[]={ STACK_REG,STACK_REG /* SPL,SPH */ }; +/* Function to set up the backend function structure. */ + +static struct machine_function * +avr_init_machine_status (void) +{ + return ((struct machine_function *) + ggc_alloc_cleared (sizeof (struct machine_function))); +} + /* Return register class for register R. */ enum reg_class @@ -372,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; } @@ -406,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. */ @@ -415,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++) @@ -432,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))))) @@ -456,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; } } @@ -473,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)); } @@ -490,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; @@ -502,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; @@ -510,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; @@ -526,388 +586,374 @@ sequent_regs_live (void) return (cur_seq == live_seq) ? live_seq : 0; } +/* Output function prologue. */ -/* 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 *file, int adj) +void +expand_prologue (void) { - int size = 0; + 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 (adj) + 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); + + /* Prologue: naked. */ + if (cfun->machine->is_naked) { - if (TARGET_TINY_STACK) - { - if (adj < -63 || adj > 63) - warning (0, "large frame pointer change (%d) with -mtiny-stack", adj); - - /* The high byte (r29) doesn't change - prefer "subi" (1 cycle) - over "sbiw" (2 cycles, same size). */ - - 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; } - return size; -} - - -/* Output to FILE the asm instructions to copy r29:r28 to SPH:SPL, - handling various cases of interrupt enable flag state BEFORE and AFTER - (0=disabled, 1=enabled, -1=unknown/unchanged) and target_flags. - Returns the number of instructions generated. */ -static int -out_set_stack_ptr (FILE *file, int before, int after) -{ - int do_sph, do_cli, do_save, do_sei, lock_sph, size; - - /* The logic here is so that -mno-interrupts actually means - "it is safe to write SPH in one instruction, then SPL in the - next instruction, without disabling interrupts first". - The after != -1 case (interrupt/signal) is not affected. */ - - do_sph = !TARGET_TINY_STACK; - lock_sph = do_sph && !TARGET_NO_INTERRUPTS; - do_cli = (before != 0 && (after == 0 || lock_sph)); - do_save = (do_cli && before == -1 && after == -1); - do_sei = ((do_cli || before != 1) && after == 1); - size = 1; - - if (do_save) - { - fprintf (file, AS2 (in, __tmp_reg__, __SREG__) CR_TAB); - size++; - } + 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 + && live_seq); - if (do_cli) + if (cfun->machine->is_interrupt || cfun->machine->is_signal) { - fprintf (file, "cli" 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; - /* Do SPH first - maybe this will disable interrupts for one instruction - someday (a suggestion has been sent to avr@atmel.com for consideration - in future devices - that would make -mno-interrupts always safe). */ - if (do_sph) - { - fprintf (file, AS2 (out, __SP_H__, r29) CR_TAB); - size++; + /* Prevent any attempt to delete the setting of ZERO_REG! */ + emit_insn (gen_rtx_USE (VOIDmode, zero_reg_rtx)); } - - /* 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) + if (minimize && (frame_pointer_needed || live_seq > 6)) { - fprintf (file, AS2 (out, __SREG__, __tmp_reg__) 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 if (do_sei) + else { - fprintf (file, "sei" CR_TAB); - size++; - } - - fprintf (file, AS2 (out, __SP_L__, r28) "\n"); + 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) + { + /* Push frame pointer. */ + insn = emit_move_insn (pushword, frame_pointer_rtx); + RTX_FRAME_RELATED_P (insn) = 1; + } - return size; + 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; + /* First method. */ + if (TARGET_TINY_STACK) + { + if (size < -63 || size > 63) + warning (0, "large frame pointer change (%d) with -mtiny-stack", size); + + /* 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; + } + /* Calculate length. */ + int method1_length; + method1_length = + get_attr_length (gen_move_insn (frame_pointer_rtx, stack_pointer_rtx)); + method1_length += + get_attr_length (gen_move_insn (myfp, + gen_rtx_PLUS (GET_MODE(myfp), myfp, + gen_int_mode (-size, + GET_MODE(myfp))))); + method1_length += + get_attr_length (gen_move_insn (stack_pointer_rtx, frame_pointer_rtx)); + + /* Method 2-Adjust Stack pointer. */ + int sp_plus_length = 0; + if (size <= 6) + { + sp_plus_length = + get_attr_length (gen_move_insn (stack_pointer_rtx, + gen_rtx_PLUS (HImode, stack_pointer_rtx, + gen_int_mode (-size, + HImode)))); + sp_plus_length += + get_attr_length (gen_move_insn (frame_pointer_rtx, stack_pointer_rtx)); + } + /* Use shortest method. */ + if (size <= 6 && (sp_plus_length < method1_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; + insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx); + RTX_FRAME_RELATED_P (insn) = 1; + } + else + { + 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; + insn = emit_move_insn ( stack_pointer_rtx, frame_pointer_rtx); + RTX_FRAME_RELATED_P (insn) = 1; + } + } + } + } } - -/* Output function prologue. */ +/* Output summary at end of function prologue. */ static void -avr_output_function_prologue (FILE *file, HOST_WIDE_INT size) +avr_asm_function_end_prologue (FILE *file) { - int reg; - int interrupt_func_p; - int signal_func_p; - int main_p; - int live_seq; - int minimize; - - last_insn_address = 0; - jump_tables_size = 0; - prologue_size = 0; - fprintf (file, "/* prologue: frame size=" HOST_WIDE_INT_PRINT_DEC " */\n", - size); - - if (avr_naked_function_p (current_function_decl)) + if (cfun->machine->is_naked) { fputs ("/* prologue: naked */\n", file); - goto out; - } - - interrupt_func_p = interrupt_function_p (current_function_decl); - signal_func_p = signal_function_p (current_function_decl); - 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); - - 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" - AS1 (ldi,r28) ",lo8(%s - " HOST_WIDE_INT_PRINT_DEC ")" CR_TAB - AS1 (ldi,r29) ",hi8(%s - " HOST_WIDE_INT_PRINT_DEC ")" 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)) + else { - fprintf (file, ("\t" - AS1 (ldi, r26) ",lo8(" HOST_WIDE_INT_PRINT_DEC ")" CR_TAB - AS1 (ldi, r27) ",hi8(" HOST_WIDE_INT_PRINT_DEC ")" CR_TAB), size, size); - - fputs ((AS2 (ldi,r30,pm_lo8(1f)) CR_TAB - AS2 (ldi,r31,pm_hi8(1f)) CR_TAB), file); - - prologue_size += 4; - - if (AVR_MEGA) - { - fprintf (file, AS1 (jmp,__prologue_saves__+%d) "\n", - (18 - live_seq) * 2); - prologue_size += 2; - } + if (cfun->machine->is_interrupt) + { + fputs ("/* prologue: Interrupt */\n", file); + } + else if (cfun->machine->is_signal) + { + fputs ("/* prologue: Signal */\n", file); + } else - { - fprintf (file, AS1 (rjmp,__prologue_saves__+%d) "\n", - (18 - live_seq) * 2); - ++prologue_size; - } - fputs ("1:\n", file); + fputs ("/* prologue: function */\n", file); } - else - { - HARD_REG_SET set; + fprintf (file, "/* frame size = " HOST_WIDE_INT_PRINT_DEC " */\n", + get_frame_size()); +} - prologue_size += avr_regs_to_save (&set); - for (reg = 0; reg < 32; ++reg) - { - if (TEST_HARD_REG_BIT (set, reg)) - { - fprintf (file, "\t" AS1 (push,%s) "\n", avr_regnames[reg]); - } - } - 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); - } - } - } - } +/* Implement EPILOGUE_USES. */ - out: - fprintf (file, "/* prologue end (size=%d) */\n", prologue_size); +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 function epilogue. */ +/* Output RTL epilogue. */ -static void -avr_output_function_epilogue (FILE *file, HOST_WIDE_INT size) +void +expand_epilogue (void) { int reg; - int interrupt_func_p; - int signal_func_p; - int main_p; - int function_size; int live_seq; + HARD_REG_SET set; int minimize; - rtx last = get_last_nonnote_insn (); - - function_size = jump_tables_size; - if (last) - { - rtx first = get_first_nonnote_insn (); - function_size += (INSN_ADDRESSES (INSN_UID (last)) - - INSN_ADDRESSES (INSN_UID (first))); - function_size += get_attr_length (last); - } - - fprintf (file, "/* epilogue: frame size=" HOST_WIDE_INT_PRINT_DEC " */\n", size); - epilogue_size = 0; - - if (avr_naked_function_p (current_function_decl)) - { - fputs ("/* epilogue: naked */\n", file); - goto out; - } - - if (last && GET_CODE (last) == BARRIER) + HOST_WIDE_INT size = get_frame_size(); + + /* epilogue: naked */ + if (cfun->machine->is_naked) { - fputs ("/* epilogue: noreturn */\n", file); - goto out; + emit_jump_insn (gen_return ()); + return; } - interrupt_func_p = interrupt_function_p (current_function_decl); - signal_func_p = signal_function_p (current_function_decl); - main_p = MAIN_NAME_P (DECL_NAME (current_function_decl)); + 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 + && live_seq); - if (main_p) + if (minimize && (frame_pointer_needed || live_seq > 4)) { - /* Return value from main() is already in the correct registers - (r25:r24) as the exit() argument. */ - if (AVR_MEGA) - { - fputs ("\t" AS1 (jmp,exit) "\n", file); - epilogue_size += 2; - } - else - { - fputs ("\t" AS1 (rjmp,exit) "\n", file); - ++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 { - HARD_REG_SET set; - if (frame_pointer_needed) { if (size) { - fputs ("\t", file); - epilogue_size += out_adj_frame_ptr (file, -size); - - if (interrupt_func_p || signal_func_p) - { - epilogue_size += out_set_stack_ptr (file, -1, 0); - } - else - { - epilogue_size += out_set_stack_ptr (file, -1, -1); - } + /* Try two methods to adjust stack and select shortest. */ + int fp_plus_length; + /* Method 1-Adjust frame pointer. */ + fp_plus_length = + get_attr_length (gen_move_insn (frame_pointer_rtx, + gen_rtx_PLUS (HImode, frame_pointer_rtx, + gen_int_mode (size, + HImode)))); + /* Copy to stack pointer. */ + fp_plus_length += + get_attr_length (gen_move_insn (stack_pointer_rtx, frame_pointer_rtx)); + + /* Method 2-Adjust Stack pointer. */ + int sp_plus_length = 0; + if (size <= 5) + { + sp_plus_length = + get_attr_length (gen_move_insn (stack_pointer_rtx, + gen_rtx_PLUS (HImode, stack_pointer_rtx, + gen_int_mode (size, + HImode)))); + } + /* Use shortest method. */ + if (size <= 5 && (sp_plus_length < fp_plus_length)) + { + emit_move_insn (stack_pointer_rtx, + gen_rtx_PLUS (HImode, stack_pointer_rtx, + gen_int_mode (size, HImode))); + } + else + { + emit_move_insn (frame_pointer_rtx, + gen_rtx_PLUS (HImode, frame_pointer_rtx, + gen_int_mode (size, HImode))); + /* Copy to stack pointer. */ + emit_move_insn (stack_pointer_rtx, frame_pointer_rtx); + } + } + if(!cfun->machine->is_OS_task) + { + /* Restore previous frame_pointer. */ + emit_insn (gen_pophi (frame_pointer_rtx)); } - fprintf (file, "\t" - AS1 (pop,r29) CR_TAB - AS1 (pop,r28) "\n"); - epilogue_size += 2; } - - epilogue_size += avr_regs_to_save (&set); + /* Restore used registers. */ for (reg = 31; reg >= 0; --reg) - { - if (TEST_HARD_REG_BIT (set, reg)) - { - fprintf (file, "\t" AS1 (pop,%s) "\n", avr_regnames[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); } - } - 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; - } + /* Restore SREG using tmp reg as scratch. */ + emit_insn (gen_popqi (tmp_reg_rtx)); + + emit_move_insn (gen_rtx_MEM(QImode, GEN_INT(SREG_ADDR)), + tmp_reg_rtx); + + /* Restore tmp REG. */ + emit_insn (gen_popqi (tmp_reg_rtx)); - out: - 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; + /* Restore zero REG. */ + emit_insn (gen_popqi (zero_reg_rtx)); + } + + emit_jump_insn (gen_return ()); + } } +/* 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. */ @@ -1019,7 +1065,7 @@ ptrreg_to_str (int regno) case REG_Y: return "Y"; case REG_Z: return "Z"; default: - gcc_unreachable (); + output_operand_lossage ("address operand requires constraint for X, Y, or Z register"); } return NULL; } @@ -1079,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 ,")"); } @@ -1101,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) @@ -1271,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; @@ -1627,13 +1678,28 @@ output_movhi (rtx insn, rtx operands[], int *l) *l = 1; return AS2 (out,__SP_L__,%A1); } - else if (TARGET_NO_INTERRUPTS) - { - *l = 2; - return (AS2 (out,__SP_H__,%B1) CR_TAB - AS2 (out,__SP_L__,%A1)); - } - + /* Use simple load of stack pointer if no interrupts are used + or inside main or signal function prologue where they disabled. */ + else if (TARGET_NO_INTERRUPTS + || (reload_completed + && cfun->machine->is_signal + && prologue_epilogue_contains (insn))) + { + *l = 2; + return (AS2 (out,__SP_H__,%B1) CR_TAB + AS2 (out,__SP_L__,%A1)); + } + /* In interrupt prolog we know interrupts are enabled. */ + else if (reload_completed + && cfun->machine->is_interrupt + && prologue_epilogue_contains (insn)) + { + *l = 4; + return ("cli" CR_TAB + AS2 (out,__SP_H__,%B1) CR_TAB + "sei" CR_TAB + AS2 (out,__SP_L__,%A1)); + } *l = 5; return (AS2 (in,__tmp_reg__,__SREG__) CR_TAB "cli" CR_TAB @@ -1774,7 +1840,12 @@ out_movqi_r_mr (rtx insn, rtx op[], int *l) if (CONSTANT_ADDRESS_P (x)) { - if (avr_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); @@ -1962,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 @@ -2457,7 +2528,12 @@ out_movqi_mr_r (rtx insn, rtx op[], int *l) if (CONSTANT_ADDRESS_P (x)) { - if (avr_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); @@ -2536,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 @@ -2661,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); } @@ -4403,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; @@ -4421,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++) @@ -4474,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 @@ -4531,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 } }; @@ -4595,7 +4672,7 @@ avr_handle_fndecl_attribute (tree *node, tree name, } else { - const char *func_name = IDENTIFIER_POINTER (DECL_NAME (*node)); + const char *func_name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (*node)); const char *attr = IDENTIFIER_POINTER (name); /* If the function has the 'signal' or 'interrupt' attribute, test to @@ -4623,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. */ @@ -4679,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"); } @@ -4689,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; @@ -4737,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 @@ -4749,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 @@ -4986,17 +5067,19 @@ 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; case HImode: if (AVR_HAVE_MUL) *total = COSTS_N_INSNS (optimize_size ? 7 : 10); else if (optimize_size) - *total = COSTS_N_INSNS (AVR_MEGA ? 2 : 1); + *total = COSTS_N_INSNS (AVR_HAVE_JMP_CALL ? 2 : 1); else return false; + break; default: return false; @@ -5010,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); @@ -5381,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; } @@ -5527,7 +5610,7 @@ avr_ret_register (void) return 24; } -/* Ceate an RTX representing the place where a +/* Create an RTX representing the place where a library function returns a value of mode MODE. */ rtx @@ -5543,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; @@ -5604,6 +5687,10 @@ jump_over_one_insn_p (rtx insn, rtx dest) int avr_hard_regno_mode_ok (int regno, enum machine_mode mode) { + /* Disallow QImode in stack pointer regs. */ + if ((regno == REG_SP || regno == (REG_SP + 1)) && mode == QImode) + return 0; + /* The only thing that can go into registers r28:r29 is a Pmode. */ if (regno == REG_Y && mode == Pmode) return 1; @@ -5623,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) { @@ -5738,12 +5814,10 @@ 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); - - jump_tables_size++; } /* Returns 1 if SCRATCH are safe to be allocated as a scratch @@ -5762,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; } } @@ -5861,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) {