avr-protos.h (expand_prologue, [...]): Add declaration.
* config/avr/avr-protos.h (expand_prologue, expand_epilogue, avr_epilogue_uses) : Add declaration. * config/avr/predicates.md (avr_sp_immediate_operand): New predicate. * config/avr/constraints.md (R): New constraint. config/avr/avr.md (SREG_ADDR, UNSPEC_SEI, UNSPEC_CLI, UNSPECV_PROLOGUE_SAVES, UNSPECV_EPILOGUE_RESTORES): New constants. (*pop1, *pop2, *pop3, *pop4, *pop5): Combine into ... (*addhi3_sp_R_pc2, *addhi3_sp_R_pc3): ... these patterns. (*movhi_sp, popqi, pophi, enable_interrupt, disable_interrupt, call_prologue_saves, epilogue_restores, return_from_epilogue, return_from_main_epilogue, return_from_interrupt_epilogue, return_from_naked_epilogue, prologue, epilogue): New patterns. (jump): Handle symbol reference. * config/avr/avr.c (out_adj_frame_ptr, out_set_stack_ptr, avr_output_function_prologue, avr_output_function_epilogue): Remove functions. (avr_init_machine_status, expand_prologue, expand_epilogue, avr_asm_function_end_prologue, avr_epilogue_uses, avr_asm_function_begin_epilogue): New functions. (prologue_size, epilogue_size, jump_tables_size): Remove global variables. (TARGET_ASM_FUNCTION_PROLOGUE, TARGET_ASM_FUNCTION_EPILOGUE): Remove. (TARGET_ASM_FUNCTION_END_PROLOGUE): Define. (TARGET_ASM_FUNCTION_BEGIN_EPILOGUE): Define. (avr_override_options): Initialise init_machine_status. (output_movhi): Handle all stack pointer loads. (out_movqi_r_mr, out_movqi_mr_r): Handle SREG_ADDR address. (avr_output_addr_vec_elt): Do not use variable jump_tables_size. * config/avr/avr.h (AVR_2_BYTE_PC, AVR_3_BYTE_PC): New. (EPILOGUE_USES) Redefine. (machine_function) Declare. Co-Authored-By: Anatoly Sokolov <aesok@dol.ru> From-SVN: r124854
This commit is contained in:
parent
6de3644168
commit
4fc2b4ff18
7 changed files with 754 additions and 399 deletions
|
@ -1,3 +1,38 @@
|
|||
2007-05-19 Andy Hutchinson <HutchinsonAndy@netscape.net>
|
||||
Anatoly Sokolov <aesok@dol.ru>
|
||||
|
||||
* config/avr/avr-protos.h (expand_prologue, expand_epilogue,
|
||||
avr_epilogue_uses) : Add declaration.
|
||||
* config/avr/predicates.md (avr_sp_immediate_operand): New predicate.
|
||||
* config/avr/constraints.md (R): New constraint.
|
||||
config/avr/avr.md (SREG_ADDR, UNSPEC_SEI, UNSPEC_CLI,
|
||||
UNSPECV_PROLOGUE_SAVES, UNSPECV_EPILOGUE_RESTORES): New constants.
|
||||
(*pop1, *pop2, *pop3, *pop4, *pop5): Combine into ...
|
||||
(*addhi3_sp_R_pc2, *addhi3_sp_R_pc3): ... these patterns.
|
||||
(*movhi_sp, popqi, pophi, enable_interrupt, disable_interrupt,
|
||||
call_prologue_saves, epilogue_restores, return_from_epilogue,
|
||||
return_from_main_epilogue, return_from_interrupt_epilogue,
|
||||
return_from_naked_epilogue, prologue, epilogue): New patterns.
|
||||
(jump): Handle symbol reference.
|
||||
* config/avr/avr.c (out_adj_frame_ptr, out_set_stack_ptr,
|
||||
avr_output_function_prologue, avr_output_function_epilogue): Remove
|
||||
functions.
|
||||
(avr_init_machine_status, expand_prologue, expand_epilogue,
|
||||
avr_asm_function_end_prologue, avr_epilogue_uses,
|
||||
avr_asm_function_begin_epilogue): New functions.
|
||||
(prologue_size, epilogue_size, jump_tables_size): Remove global
|
||||
variables.
|
||||
(TARGET_ASM_FUNCTION_PROLOGUE, TARGET_ASM_FUNCTION_EPILOGUE): Remove.
|
||||
(TARGET_ASM_FUNCTION_END_PROLOGUE): Define.
|
||||
(TARGET_ASM_FUNCTION_BEGIN_EPILOGUE): Define.
|
||||
(avr_override_options): Initialise init_machine_status.
|
||||
(output_movhi): Handle all stack pointer loads.
|
||||
(out_movqi_r_mr, out_movqi_mr_r): Handle SREG_ADDR address.
|
||||
(avr_output_addr_vec_elt): Do not use variable jump_tables_size.
|
||||
* config/avr/avr.h (AVR_2_BYTE_PC, AVR_3_BYTE_PC): New.
|
||||
(EPILOGUE_USES) Redefine.
|
||||
(machine_function) Declare.
|
||||
|
||||
2007-05-19 Richard Sandiford <richard@codesourcery.com>
|
||||
|
||||
* config/mips/mips.c (mips_offset_within_alignment_p): Tweak comment.
|
||||
|
|
|
@ -87,6 +87,10 @@ extern const char *lshrqi3_out (rtx insn, rtx operands[], int *len);
|
|||
extern const char *lshrhi3_out (rtx insn, rtx operands[], int *len);
|
||||
extern const char *lshrsi3_out (rtx insn, rtx operands[], int *len);
|
||||
|
||||
extern void expand_prologue (void);
|
||||
extern void expand_epilogue (void);
|
||||
extern int avr_epilogue_uses (int regno);
|
||||
|
||||
extern void avr_output_bld (rtx operands[], int bit_nr);
|
||||
extern void avr_output_addr_vec_elt (FILE *stream, int value);
|
||||
extern const char *avr_out_sbxx_branch (rtx insn, rtx operands[]);
|
||||
|
|
|
@ -56,8 +56,7 @@ 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 *);
|
||||
|
@ -66,8 +65,8 @@ 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);
|
||||
|
@ -79,7 +78,7 @@ 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 struct machine_function * avr_init_machine_status (void);
|
||||
/* Allocate registers from r25 to r8 for parameters for function calls. */
|
||||
#define FIRST_CUM_REG 26
|
||||
|
||||
|
@ -104,13 +103,6 @@ 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;
|
||||
|
@ -299,10 +291,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
|
||||
|
@ -359,6 +351,8 @@ avr_override_options (void)
|
|||
|
||||
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. */
|
||||
|
@ -377,6 +371,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
|
||||
|
@ -550,388 +553,382 @@ 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;
|
||||
|
||||
if (adj)
|
||||
{
|
||||
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 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++;
|
||||
}
|
||||
|
||||
if (do_cli)
|
||||
{
|
||||
fprintf (file, "cli" CR_TAB);
|
||||
size++;
|
||||
}
|
||||
|
||||
/* 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++;
|
||||
}
|
||||
|
||||
/* Set/restore the I flag now - interrupts will be really enabled only
|
||||
after the next instruction. This is not clearly documented, but
|
||||
believed to be true for all AVR devices. */
|
||||
if (do_save)
|
||||
{
|
||||
fprintf (file, AS2 (out, __SREG__, __tmp_reg__) CR_TAB);
|
||||
size++;
|
||||
}
|
||||
else if (do_sei)
|
||||
{
|
||||
fprintf (file, "sei" CR_TAB);
|
||||
size++;
|
||||
}
|
||||
|
||||
fprintf (file, AS2 (out, __SP_L__, r28) "\n");
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
/* Output function prologue. */
|
||||
|
||||
static void
|
||||
avr_output_function_prologue (FILE *file, HOST_WIDE_INT size)
|
||||
{
|
||||
int reg;
|
||||
int interrupt_func_p;
|
||||
int signal_func_p;
|
||||
int main_p;
|
||||
int live_seq;
|
||||
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;
|
||||
|
||||
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))
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Prologue: naked. */
|
||||
if (cfun->machine->is_naked)
|
||||
{
|
||||
fputs ("/* prologue: naked */\n", file);
|
||||
goto out;
|
||||
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));
|
||||
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)
|
||||
&& live_seq);
|
||||
|
||||
if (interrupt_func_p)
|
||||
if (cfun->machine->is_interrupt || cfun->machine->is_signal)
|
||||
{
|
||||
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);
|
||||
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;
|
||||
|
||||
prologue_size += 4;
|
||||
/* 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)
|
||||
{
|
||||
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);
|
||||
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))
|
||||
{
|
||||
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;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (file, AS1 (rjmp,__prologue_saves__+%d) "\n",
|
||||
(18 - live_seq) * 2);
|
||||
++prologue_size;
|
||||
}
|
||||
fputs ("1:\n", file);
|
||||
insn =
|
||||
emit_insn (gen_call_prologue_saves (gen_int_mode (size, HImode),
|
||||
gen_int_mode (live_seq, HImode)));
|
||||
RTX_FRAME_RELATED_P (insn) = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
HARD_REG_SET set;
|
||||
|
||||
prologue_size += avr_regs_to_save (&set);
|
||||
avr_regs_to_save (&set);
|
||||
int reg;
|
||||
for (reg = 0; reg < 32; ++reg)
|
||||
{
|
||||
if (TEST_HARD_REG_BIT (set, reg))
|
||||
{
|
||||
fprintf (file, "\t" AS1 (push,%s) "\n", avr_regnames[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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
/* 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);
|
||||
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), frame_pointer_rtx,
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
fprintf (file, "/* prologue end (size=%d) */\n", prologue_size);
|
||||
}
|
||||
|
||||
/* Output function epilogue. */
|
||||
/* Output summary at end of function prologue. */
|
||||
|
||||
static void
|
||||
avr_output_function_epilogue (FILE *file, HOST_WIDE_INT size)
|
||||
avr_asm_function_end_prologue (FILE *file)
|
||||
{
|
||||
if (cfun->machine->is_naked)
|
||||
{
|
||||
fputs ("/* prologue: naked */\n", file);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cfun->machine->is_interrupt)
|
||||
{
|
||||
fputs ("/* prologue: Interrupt */\n", file);
|
||||
}
|
||||
else if (cfun->machine->is_signal)
|
||||
{
|
||||
fputs ("/* prologue: Signal */\n", file);
|
||||
}
|
||||
else if (cfun->machine->is_main)
|
||||
{
|
||||
fputs ("/* prologue: main */\n", file);
|
||||
}
|
||||
else
|
||||
fputs ("/* prologue: function */\n", file);
|
||||
}
|
||||
fprintf (file, "/* frame size = " HOST_WIDE_INT_PRINT_DEC " */\n",
|
||||
get_frame_size());
|
||||
}
|
||||
|
||||
|
||||
/* Implement EPILOGUE_USES. */
|
||||
|
||||
int
|
||||
avr_epilogue_uses (int regno ATTRIBUTE_UNUSED)
|
||||
{
|
||||
if (reload_completed
|
||||
&& cfun->machine
|
||||
&& (cfun->machine->is_interrupt || cfun->machine->is_signal))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Output RTL epilogue. */
|
||||
|
||||
void
|
||||
expand_epilogue (void)
|
||||
{
|
||||
int reg;
|
||||
int interrupt_func_p;
|
||||
int signal_func_p;
|
||||
int main_p;
|
||||
int function_size;
|
||||
int live_seq;
|
||||
int minimize;
|
||||
rtx last = get_last_nonnote_insn ();
|
||||
|
||||
function_size = jump_tables_size;
|
||||
if (last)
|
||||
HOST_WIDE_INT size = get_frame_size();
|
||||
rtx insn;
|
||||
|
||||
/* epilogue: naked */
|
||||
if (cfun->machine->is_naked)
|
||||
{
|
||||
rtx first = get_first_nonnote_insn ();
|
||||
function_size += (INSN_ADDRESSES (INSN_UID (last)) -
|
||||
INSN_ADDRESSES (INSN_UID (first)));
|
||||
function_size += get_attr_length (last);
|
||||
insn = emit_jump_insn (gen_return ());
|
||||
RTX_FRAME_RELATED_P (insn) = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
fputs ("/* epilogue: noreturn */\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);
|
||||
&& !(cfun->machine->is_interrupt || cfun->machine->is_signal)
|
||||
&& live_seq);
|
||||
|
||||
if (main_p)
|
||||
if (cfun->machine->is_main)
|
||||
{
|
||||
/* 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;
|
||||
}
|
||||
(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))
|
||||
{
|
||||
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);
|
||||
/* 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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (file, AS1 (rjmp,__epilogue_restores__+%d) "\n",
|
||||
(18 - live_seq) * 2);
|
||||
++epilogue_size;
|
||||
insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
|
||||
RTX_FRAME_RELATED_P (insn) = 1;
|
||||
}
|
||||
|
||||
insn =
|
||||
emit_insn (gen_epilogue_restores (gen_int_mode (live_seq, HImode)));
|
||||
RTX_FRAME_RELATED_P (insn) = 1;
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
fprintf (file, "\t"
|
||||
AS1 (pop,r29) CR_TAB
|
||||
AS1 (pop,r28) "\n");
|
||||
epilogue_size += 2;
|
||||
/* 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))
|
||||
{
|
||||
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;
|
||||
}
|
||||
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;
|
||||
/* Copy to stack pointer. */
|
||||
insn = emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
|
||||
RTX_FRAME_RELATED_P (insn) = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Restore previous frame_pointer. */
|
||||
insn = emit_insn (gen_pophi (frame_pointer_rtx));
|
||||
RTX_FRAME_RELATED_P (insn) = 1;
|
||||
}
|
||||
|
||||
epilogue_size += avr_regs_to_save (&set);
|
||||
/* 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))
|
||||
{
|
||||
fprintf (file, "\t" AS1 (pop,%s) "\n", avr_regnames[reg]);
|
||||
}
|
||||
}
|
||||
{
|
||||
if (TEST_HARD_REG_BIT (set, reg))
|
||||
{
|
||||
insn = emit_insn (gen_popqi (gen_rtx_REG (QImode, reg)));
|
||||
RTX_FRAME_RELATED_P (insn) = 1;
|
||||
}
|
||||
}
|
||||
if (cfun->machine->is_interrupt || cfun->machine->is_signal)
|
||||
{
|
||||
|
||||
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. */
|
||||
insn = emit_insn (gen_popqi (tmp_reg_rtx));
|
||||
RTX_FRAME_RELATED_P (insn) = 1;
|
||||
|
||||
insn = emit_move_insn (gen_rtx_MEM(QImode, GEN_INT(SREG_ADDR)),
|
||||
tmp_reg_rtx);
|
||||
RTX_FRAME_RELATED_P (insn) = 1;
|
||||
|
||||
/* Restore tmp REG. */
|
||||
insn = emit_insn (gen_popqi (tmp_reg_rtx));
|
||||
RTX_FRAME_RELATED_P (insn) = 1;
|
||||
|
||||
/* Restore zero REG. */
|
||||
insn = emit_insn (gen_popqi (zero_reg_rtx));
|
||||
RTX_FRAME_RELATED_P (insn) = 1;
|
||||
}
|
||||
|
||||
insn = emit_jump_insn (gen_return ());
|
||||
RTX_FRAME_RELATED_P (insn) = 1;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
|
@ -1651,13 +1648,31 @@ 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_main
|
||||
&& prologue_epilogue_contains (insn))
|
||||
|| (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
|
||||
|
@ -1798,6 +1813,11 @@ out_movqi_r_mr (rtx insn, rtx op[], int *l)
|
|||
|
||||
if (CONSTANT_ADDRESS_P (x))
|
||||
{
|
||||
if (CONST_INT_P (x) && INTVAL (x) == SREG_ADDR)
|
||||
{
|
||||
*l = 1;
|
||||
return AS2 (in,%0,__SREG__);
|
||||
}
|
||||
if (avr_io_address_p (x, 1))
|
||||
{
|
||||
*l = 1;
|
||||
|
@ -2481,6 +2501,11 @@ out_movqi_mr_r (rtx insn, rtx op[], int *l)
|
|||
|
||||
if (CONSTANT_ADDRESS_P (x))
|
||||
{
|
||||
if (CONST_INT_P (x) && INTVAL (x) == SREG_ADDR)
|
||||
{
|
||||
*l = 1;
|
||||
return AS2 (out,__SREG__,%1);
|
||||
}
|
||||
if (avr_io_address_p (x, 1))
|
||||
{
|
||||
*l = 1;
|
||||
|
@ -5772,8 +5797,6 @@ avr_output_addr_vec_elt (FILE *stream, int value)
|
|||
fprintf (stream, "\t.word pm(.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
|
||||
|
|
|
@ -63,6 +63,9 @@ extern GTY(()) section *progmem_section;
|
|||
#define AVR_HAVE_MOVW (avr_have_movw_lpmx_p)
|
||||
#define AVR_HAVE_LPMX (avr_have_movw_lpmx_p)
|
||||
|
||||
#define AVR_2_BYTE_PC 1
|
||||
#define AVR_3_BYTE_PC 0
|
||||
|
||||
#define TARGET_VERSION fprintf (stderr, " (GNU assembler syntax)");
|
||||
|
||||
#define OVERRIDE_OPTIONS avr_override_options ()
|
||||
|
@ -338,7 +341,7 @@ extern int avr_reg_order[];
|
|||
|
||||
#define DEFAULT_PCC_STRUCT_RETURN 0
|
||||
|
||||
#define EPILOGUE_USES(REGNO) 0
|
||||
#define EPILOGUE_USES(REGNO) avr_epilogue_uses(REGNO)
|
||||
|
||||
#define HAVE_POST_INCREMENT 1
|
||||
#define HAVE_PRE_DECREMENT 1
|
||||
|
@ -933,3 +936,22 @@ mmcu=*:-mmcu=%*}"
|
|||
#define DWARF2_ADDR_SIZE 4
|
||||
|
||||
#define OBJECT_FORMAT_ELF
|
||||
|
||||
/* A C structure for machine-specific, per-function data.
|
||||
This is added to the cfun structure. */
|
||||
struct machine_function GTY(())
|
||||
{
|
||||
/* 'true' - if current function is a 'main' function. */
|
||||
int is_main;
|
||||
|
||||
/* 'true' - if current function is a naked function. */
|
||||
int is_naked;
|
||||
|
||||
/* 'true' - if current function is an interrupt function
|
||||
as specified by the "interrupt" attribute. */
|
||||
int is_interrupt;
|
||||
|
||||
/* 'true' - if current function is a signal function
|
||||
as specified by the "signal" attribute. */
|
||||
int is_signal;
|
||||
};
|
||||
|
|
|
@ -46,8 +46,16 @@
|
|||
(REG_SP 32)
|
||||
(TMP_REGNO 0) ; temporary register r0
|
||||
(ZERO_REGNO 1) ; zero register r1
|
||||
|
||||
(SREG_ADDR 0x5F)
|
||||
|
||||
(UNSPEC_STRLEN 0)
|
||||
(UNSPEC_INDEX_JMP 1)])
|
||||
(UNSPEC_INDEX_JMP 1)
|
||||
(UNSPEC_SEI 2)
|
||||
(UNSPEC_CLI 3)
|
||||
|
||||
(UNSPECV_PROLOGUE_SAVES 0)
|
||||
(UNSPECV_EPILOGUE_RESTORES 1)])
|
||||
|
||||
(include "predicates.md")
|
||||
(include "constraints.md")
|
||||
|
@ -104,46 +112,6 @@
|
|||
(const_int 2))]
|
||||
(const_int 2)))
|
||||
|
||||
(define_insn "*pop1"
|
||||
[(set (reg:HI 32) (plus:HI (reg:HI 32) (const_int 1)))]
|
||||
""
|
||||
"pop __tmp_reg__"
|
||||
[(set_attr "length" "1")])
|
||||
|
||||
(define_insn "*pop2"
|
||||
[(set (reg:HI 32) (plus:HI (reg:HI 32) (const_int 2)))]
|
||||
""
|
||||
"pop __tmp_reg__
|
||||
pop __tmp_reg__"
|
||||
[(set_attr "length" "2")])
|
||||
|
||||
(define_insn "*pop3"
|
||||
[(set (reg:HI 32) (plus:HI (reg:HI 32) (const_int 3)))]
|
||||
""
|
||||
"pop __tmp_reg__
|
||||
pop __tmp_reg__
|
||||
pop __tmp_reg__"
|
||||
[(set_attr "length" "3")])
|
||||
|
||||
(define_insn "*pop4"
|
||||
[(set (reg:HI 32) (plus:HI (reg:HI 32) (const_int 4)))]
|
||||
""
|
||||
"pop __tmp_reg__
|
||||
pop __tmp_reg__
|
||||
pop __tmp_reg__
|
||||
pop __tmp_reg__"
|
||||
[(set_attr "length" "4")])
|
||||
|
||||
(define_insn "*pop5"
|
||||
[(set (reg:HI 32) (plus:HI (reg:HI 32) (const_int 5)))]
|
||||
""
|
||||
"pop __tmp_reg__
|
||||
pop __tmp_reg__
|
||||
pop __tmp_reg__
|
||||
pop __tmp_reg__
|
||||
pop __tmp_reg__"
|
||||
[(set_attr "length" "5")])
|
||||
|
||||
(define_insn "*pushqi"
|
||||
[(set (mem:QI (post_dec (reg:HI REG_SP)))
|
||||
(match_operand:QI 0 "reg_or_0_operand" "r,L"))]
|
||||
|
@ -252,6 +220,14 @@
|
|||
}
|
||||
}")
|
||||
|
||||
(define_insn "*movhi_sp"
|
||||
[(set (match_operand:HI 0 "register_operand" "=q,r")
|
||||
(match_operand:HI 1 "register_operand" "r,q"))]
|
||||
"((stack_register_operand(operands[0], HImode) && register_operand (operands[1], HImode))
|
||||
|| (register_operand (operands[0], HImode) && stack_register_operand(operands[1], HImode)))"
|
||||
"* return output_movhi (insn, operands, NULL);"
|
||||
[(set_attr "length" "5,2")
|
||||
(set_attr "cc" "none,none")])
|
||||
|
||||
(define_peephole2
|
||||
[(match_scratch:QI 2 "d")
|
||||
|
@ -622,6 +598,143 @@
|
|||
[(set_attr "length" "3")
|
||||
(set_attr "cc" "set_n")])
|
||||
|
||||
(define_insn "*addhi3_sp_R_pc2"
|
||||
[(set (match_operand:HI 1 "stack_register_operand" "=q")
|
||||
(plus:HI (match_operand:HI 2 "stack_register_operand" "q")
|
||||
(match_operand:HI 0 "avr_sp_immediate_operand" "R")))]
|
||||
"AVR_2_BYTE_PC"
|
||||
"*{
|
||||
if (CONST_INT_P (operands[0]))
|
||||
{
|
||||
switch(INTVAL (operands[0]))
|
||||
{
|
||||
case -6:
|
||||
return \"rcall .\" CR_TAB
|
||||
\"rcall .\" CR_TAB
|
||||
\"rcall .\";
|
||||
case -5:
|
||||
return \"rcall .\" CR_TAB
|
||||
\"rcall .\" CR_TAB
|
||||
\"push __tmp_reg__\";
|
||||
case -4:
|
||||
return \"rcall .\" CR_TAB
|
||||
\"rcall .\";
|
||||
case -3:
|
||||
return \"rcall .\" CR_TAB
|
||||
\"push __tmp_reg__\";
|
||||
case -2:
|
||||
return \"rcall .\";
|
||||
case -1:
|
||||
return \"push __tmp_reg__\";
|
||||
case 0:
|
||||
return \"\";
|
||||
case 1:
|
||||
return \"pop __tmp_reg__\";
|
||||
case 2:
|
||||
return \"pop __tmp_reg__\" CR_TAB
|
||||
\"pop __tmp_reg__\";
|
||||
case 3:
|
||||
return \"pop __tmp_reg__\" CR_TAB
|
||||
\"pop __tmp_reg__\" CR_TAB
|
||||
\"pop __tmp_reg__\";
|
||||
case 4:
|
||||
return \"pop __tmp_reg__\" CR_TAB
|
||||
\"pop __tmp_reg__\" CR_TAB
|
||||
\"pop __tmp_reg__\" CR_TAB
|
||||
\"pop __tmp_reg__\";
|
||||
case 5:
|
||||
return \"pop __tmp_reg__\" CR_TAB
|
||||
\"pop __tmp_reg__\" CR_TAB
|
||||
\"pop __tmp_reg__\" CR_TAB
|
||||
\"pop __tmp_reg__\" CR_TAB
|
||||
\"pop __tmp_reg__\";
|
||||
}
|
||||
}
|
||||
return \"bug\";
|
||||
}"
|
||||
[(set (attr "length")
|
||||
(cond [(eq (const_int -6) (symbol_ref "INTVAL (operands[0])")) (const_int 3)
|
||||
(eq (const_int -5) (symbol_ref "INTVAL (operands[0])")) (const_int 3)
|
||||
(eq (const_int -4) (symbol_ref "INTVAL (operands[0])")) (const_int 2)
|
||||
(eq (const_int -3) (symbol_ref "INTVAL (operands[0])")) (const_int 2)
|
||||
(eq (const_int -2) (symbol_ref "INTVAL (operands[0])")) (const_int 1)
|
||||
(eq (const_int -1) (symbol_ref "INTVAL (operands[0])")) (const_int 1)
|
||||
(eq (const_int 0) (symbol_ref "INTVAL (operands[0])")) (const_int 0)
|
||||
(eq (const_int 1) (symbol_ref "INTVAL (operands[0])")) (const_int 1)
|
||||
(eq (const_int 2) (symbol_ref "INTVAL (operands[0])")) (const_int 2)
|
||||
(eq (const_int 3) (symbol_ref "INTVAL (operands[0])")) (const_int 3)
|
||||
(eq (const_int 4) (symbol_ref "INTVAL (operands[0])")) (const_int 4)
|
||||
(eq (const_int 5) (symbol_ref "INTVAL (operands[0])")) (const_int 5)]
|
||||
(const_int 0)))])
|
||||
|
||||
(define_insn "*addhi3_sp_R_pc3"
|
||||
[(set (match_operand:HI 1 "stack_register_operand" "=q")
|
||||
(plus:HI (match_operand:HI 2 "stack_register_operand" "q")
|
||||
(match_operand:QI 0 "avr_sp_immediate_operand" "R")))]
|
||||
"AVR_3_BYTE_PC"
|
||||
"*{
|
||||
if (CONST_INT_P (operands[0]))
|
||||
{
|
||||
switch(INTVAL (operands[0]))
|
||||
{
|
||||
case -6:
|
||||
return \"rcall .\" CR_TAB
|
||||
\"rcall .\";
|
||||
case -5:
|
||||
return \"rcall .\" CR_TAB
|
||||
\"push __tmp_reg__\" CR_TAB
|
||||
\"push __tmp_reg__\";
|
||||
case -4:
|
||||
return \"rcall .\" CR_TAB
|
||||
\"push __tmp_reg__\";
|
||||
case -3:
|
||||
return \"rcall .\";
|
||||
case -2:
|
||||
return \"push __tmp_reg__\" CR_TAB
|
||||
\"push __tmp_reg__\";
|
||||
case -1:
|
||||
return \"push __tmp_reg__\";
|
||||
case 0:
|
||||
return \"\";
|
||||
case 1:
|
||||
return \"pop __tmp_reg__\";
|
||||
case 2:
|
||||
return \"pop __tmp_reg__\" CR_TAB
|
||||
\"pop __tmp_reg__\";
|
||||
case 3:
|
||||
return \"pop __tmp_reg__\" CR_TAB
|
||||
\"pop __tmp_reg__\" CR_TAB
|
||||
\"pop __tmp_reg__\";
|
||||
case 4:
|
||||
return \"pop __tmp_reg__\" CR_TAB
|
||||
\"pop __tmp_reg__\" CR_TAB
|
||||
\"pop __tmp_reg__\" CR_TAB
|
||||
\"pop __tmp_reg__\";
|
||||
case 5:
|
||||
return \"pop __tmp_reg__\" CR_TAB
|
||||
\"pop __tmp_reg__\" CR_TAB
|
||||
\"pop __tmp_reg__\" CR_TAB
|
||||
\"pop __tmp_reg__\" CR_TAB
|
||||
\"pop __tmp_reg__\";
|
||||
}
|
||||
}
|
||||
return \"bug\";
|
||||
}"
|
||||
[(set (attr "length")
|
||||
(cond [(eq (const_int -6) (symbol_ref "INTVAL (operands[0])")) (const_int 2)
|
||||
(eq (const_int -5) (symbol_ref "INTVAL (operands[0])")) (const_int 3)
|
||||
(eq (const_int -4) (symbol_ref "INTVAL (operands[0])")) (const_int 2)
|
||||
(eq (const_int -3) (symbol_ref "INTVAL (operands[0])")) (const_int 1)
|
||||
(eq (const_int -2) (symbol_ref "INTVAL (operands[0])")) (const_int 2)
|
||||
(eq (const_int -1) (symbol_ref "INTVAL (operands[0])")) (const_int 1)
|
||||
(eq (const_int 0) (symbol_ref "INTVAL (operands[0])")) (const_int 0)
|
||||
(eq (const_int 1) (symbol_ref "INTVAL (operands[0])")) (const_int 1)
|
||||
(eq (const_int 2) (symbol_ref "INTVAL (operands[0])")) (const_int 2)
|
||||
(eq (const_int 3) (symbol_ref "INTVAL (operands[0])")) (const_int 3)
|
||||
(eq (const_int 4) (symbol_ref "INTVAL (operands[0])")) (const_int 4)
|
||||
(eq (const_int 5) (symbol_ref "INTVAL (operands[0])")) (const_int 5)]
|
||||
(const_int 0)))])
|
||||
|
||||
(define_insn "*addhi3"
|
||||
[(set (match_operand:HI 0 "register_operand" "=r,!w,!w,d,r,r")
|
||||
(plus:HI
|
||||
|
@ -2095,10 +2208,14 @@
|
|||
return AS1 (rjmp,%0);
|
||||
}"
|
||||
[(set (attr "length")
|
||||
(if_then_else (and (ge (minus (pc) (match_dup 0)) (const_int -2047))
|
||||
(le (minus (pc) (match_dup 0)) (const_int 2047)))
|
||||
(const_int 1)
|
||||
(const_int 2)))
|
||||
(if_then_else (match_operand 0 "symbol_ref_operand" "")
|
||||
(if_then_else (eq_attr "mcu_mega" "no")
|
||||
(const_int 1)
|
||||
(const_int 2))
|
||||
(if_then_else (and (ge (minus (pc) (match_dup 0)) (const_int -2047))
|
||||
(le (minus (pc) (match_dup 0)) (const_int 2047)))
|
||||
(const_int 1)
|
||||
(const_int 2))))
|
||||
(set_attr "cc" "none")])
|
||||
|
||||
;; call
|
||||
|
@ -2193,13 +2310,6 @@
|
|||
(const_int 1))
|
||||
(const_int 3)])])
|
||||
|
||||
(define_insn "return"
|
||||
[(return)]
|
||||
"reload_completed && avr_simple_epilogue ()"
|
||||
"ret"
|
||||
[(set_attr "cc" "none")
|
||||
(set_attr "length" "1")])
|
||||
|
||||
(define_insn "nop"
|
||||
[(const_int 0)]
|
||||
""
|
||||
|
@ -2555,3 +2665,154 @@
|
|||
(pc)))]
|
||||
"jump_over_one_insn_p (insn, operands[2])"
|
||||
"cpse %0,%1")
|
||||
|
||||
;;pppppppppppppppppppppppppppppppppppppppppppppppppppp
|
||||
;;prologue/epilogue support instructions
|
||||
|
||||
(define_insn "popqi"
|
||||
[(set (match_operand:QI 0 "register_operand" "=r")
|
||||
(mem:QI (post_inc (reg:HI REG_SP))))]
|
||||
""
|
||||
"pop %0"
|
||||
[(set_attr "cc" "none")
|
||||
(set_attr "length" "1")])
|
||||
|
||||
(define_insn "pophi"
|
||||
[(set (match_operand:HI 0 "register_operand" "=r")
|
||||
(mem:HI (post_inc (reg:HI REG_SP))))]
|
||||
""
|
||||
"pop %A0\;pop %B0"
|
||||
[(set_attr "cc" "none")
|
||||
(set_attr "length" "2")])
|
||||
|
||||
;; Enable Interrupts
|
||||
(define_insn "enable_interrupt"
|
||||
[(unspec [(const_int 0)] UNSPEC_SEI)]
|
||||
""
|
||||
"sei"
|
||||
[(set_attr "length" "1")
|
||||
(set_attr "cc" "none")
|
||||
])
|
||||
|
||||
;; Disable Interrupts
|
||||
(define_insn "disable_interrupt"
|
||||
[(unspec [(const_int 0)] UNSPEC_CLI)]
|
||||
""
|
||||
"cli"
|
||||
[(set_attr "length" "1")
|
||||
(set_attr "cc" "none")
|
||||
])
|
||||
|
||||
;; Library prologue saves
|
||||
(define_insn "call_prologue_saves"
|
||||
[(unspec_volatile:HI [(const_int 0)] UNSPECV_PROLOGUE_SAVES)
|
||||
(set (reg:HI REG_SP) (minus:HI
|
||||
(reg:HI REG_SP)
|
||||
(match_operand:HI 0 "immediate_operand" "")))
|
||||
(set (reg:HI REG_SP) (minus:HI
|
||||
(reg:HI REG_SP)
|
||||
(match_operand:HI 1 "immediate_operand" "")))
|
||||
(set (reg:HI REG_X) (match_dup 0))
|
||||
(clobber (reg:HI REG_Z))]
|
||||
""
|
||||
"ldi r26,lo8(%0)
|
||||
ldi r27,hi8(%0)
|
||||
ldi r30,pm_lo8(1f)
|
||||
ldi r31,pm_hi8(1f)
|
||||
%~jmp __prologue_saves__+((18 - %1) * 2)
|
||||
1:"
|
||||
[(set_attr_alternative "length"
|
||||
[(if_then_else (eq_attr "mcu_mega" "yes")
|
||||
(const_int 6)
|
||||
(const_int 5))])
|
||||
(set_attr "cc" "clobber")
|
||||
])
|
||||
|
||||
; epilogue restores using library
|
||||
(define_insn "epilogue_restores"
|
||||
[(unspec_volatile:QI [(const_int 0)] UNSPECV_EPILOGUE_RESTORES)
|
||||
(set (reg:HI REG_Y ) (plus:HI
|
||||
(reg:HI REG_Y)
|
||||
(match_operand:HI 0 "immediate_operand" "")))
|
||||
(set (reg:HI REG_SP) (reg:HI REG_Y))
|
||||
(clobber (reg:QI REG_Z))]
|
||||
""
|
||||
"ldi r30, lo8(%0)
|
||||
%~jmp __epilogue_restores__ + ((18 - %0) * 2)"
|
||||
[(set_attr_alternative "length"
|
||||
[(if_then_else (eq_attr "mcu_mega" "yes")
|
||||
(const_int 3)
|
||||
(const_int 2))])
|
||||
(set_attr "cc" "clobber")
|
||||
])
|
||||
|
||||
; return
|
||||
(define_insn "return"
|
||||
[(return)]
|
||||
"reload_completed && avr_simple_epilogue ()"
|
||||
"ret"
|
||||
[(set_attr "cc" "none")
|
||||
(set_attr "length" "1")])
|
||||
|
||||
(define_insn "return_from_epilogue"
|
||||
[(return)]
|
||||
"(reload_completed
|
||||
&& cfun->machine
|
||||
&& !cfun->machine->is_main
|
||||
&& !(cfun->machine->is_interrupt || cfun->machine->is_signal)
|
||||
&& !cfun->machine->is_naked)"
|
||||
"ret"
|
||||
[(set_attr "cc" "none")
|
||||
(set_attr "length" "1")])
|
||||
|
||||
(define_insn "return_from_main_epilogue"
|
||||
[(return)]
|
||||
"(reload_completed
|
||||
&& cfun->machine
|
||||
&& cfun->machine->is_main
|
||||
&& !cfun->machine->is_naked)"
|
||||
"%~jmp exit"
|
||||
[(set_attr_alternative "length"
|
||||
[(if_then_else (eq_attr "mcu_mega" "yes")
|
||||
(const_int 2)
|
||||
(const_int 1))])
|
||||
(set_attr "cc" "none")
|
||||
])
|
||||
|
||||
(define_insn "return_from_interrupt_epilogue"
|
||||
[(return)]
|
||||
"(reload_completed
|
||||
&& cfun->machine
|
||||
&& !cfun->machine->is_main
|
||||
&& (cfun->machine->is_interrupt || cfun->machine->is_signal)
|
||||
&& !cfun->machine->is_naked)"
|
||||
"reti"
|
||||
[(set_attr "cc" "none")
|
||||
(set_attr "length" "1")])
|
||||
|
||||
(define_insn "return_from_naked_epilogue"
|
||||
[(return)]
|
||||
"(reload_completed
|
||||
&& cfun->machine
|
||||
&& cfun->machine->is_naked)"
|
||||
""
|
||||
[(set_attr "cc" "none")
|
||||
(set_attr "length" "0")])
|
||||
|
||||
(define_expand "prologue"
|
||||
[(const_int 0)]
|
||||
""
|
||||
"
|
||||
{
|
||||
expand_prologue ();
|
||||
DONE;
|
||||
}")
|
||||
|
||||
(define_expand "epilogue"
|
||||
[(const_int 0)]
|
||||
""
|
||||
"
|
||||
{
|
||||
expand_epilogue ();
|
||||
DONE;
|
||||
}")
|
||||
|
|
|
@ -99,6 +99,11 @@
|
|||
(and (match_code "const_double")
|
||||
(match_test "op == CONST0_RTX (SFmode)")))
|
||||
|
||||
(define_constraint "R"
|
||||
"Integer constant in the range -6 @dots{} 5."
|
||||
(and (match_code "const_int")
|
||||
(match_test "ival >= -6 && ival <= 5")))
|
||||
|
||||
(define_memory_constraint "Q"
|
||||
"A memory address based on X or Y pointer with displacement."
|
||||
(and (match_code "mem")
|
||||
|
|
|
@ -78,7 +78,12 @@
|
|||
(define_predicate "single_zero_operand"
|
||||
(and (match_code "const_int")
|
||||
(match_test "exact_log2(~INTVAL (op) & GET_MODE_MASK (mode)) >= 0")))
|
||||
|
||||
|
||||
;;
|
||||
(define_predicate "avr_sp_immediate_operand"
|
||||
(and (match_code "const_int")
|
||||
(match_test "INTVAL (op) >= -6 && INTVAL (op) <= 5")))
|
||||
|
||||
;; True for EQ & NE
|
||||
(define_predicate "eqne_operator"
|
||||
(match_code "eq,ne"))
|
||||
|
|
Loading…
Add table
Reference in a new issue