/* 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)
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,
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"
#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))
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 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 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
/* 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;
/* 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
ARCH_AVR2,
ARCH_AVR25,
ARCH_AVR3,
+ ARCH_AVR31,
+ ARCH_AVR35,
ARCH_AVR4,
- ARCH_AVR5
+ ARCH_AVR5,
+ ARCH_AVR51,
+ ARCH_AVR6
};
struct mcu_type_s {
{ "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__" },
{ "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__" },
{ "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__" },
{ "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__" },
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);
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;
}
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. */
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++)
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)))))
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;
}
}
&& ! 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));
}
{
if (!call_used_regs[reg])
{
- if (regs_ever_live[reg])
+ if (df_regs_ever_live_p (reg))
{
++live_seq;
++cur_seq;
if (!frame_pointer_needed)
{
- if (regs_ever_live[REG_Y])
+ if (df_regs_ever_live_p (REG_Y))
{
++live_seq;
++cur_seq;
else
cur_seq = 0;
- if (regs_ever_live[REG_Y+1])
+ if (df_regs_ever_live_p (REG_Y+1))
{
++live_seq;
++cur_seq;
expand_prologue (void)
{
int live_seq;
+ HARD_REG_SET set;
int minimize;
HOST_WIDE_INT size = get_frame_size();
/* Define templates for push instructions. */
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)
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)
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;
/* 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)
{
}
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);
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);
{
fputs ("/* prologue: Signal */\n", file);
}
- else if (cfun->machine->is_main)
- {
- fputs ("/* prologue: main */\n", file);
- }
else
fputs ("/* prologue: function */\n", file);
}
{
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
{
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 +=
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 ());
}
}
&& ((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 ,")");
}
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)
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;
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)))
{
*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);
}
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
*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);
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
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);
}
&& ((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;
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++)
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
{ "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 }
};
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. */
{
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");
}
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;
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
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
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;
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;
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);
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;
}
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;
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)
{
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);
}
for (reg = first_reg; reg <= last_reg; reg++)
{
- if (!regs_ever_live[reg])
+ if (!df_regs_ever_live_p (reg))
return 0;
}
}
/* 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)
{