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 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);
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
/* 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;
#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
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. */
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
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;
+ 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_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)
{
- 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;
+ live_seq = sequent_regs_live ();
+ minimize = (TARGET_CALL_PROLOGUES
+ && !(cfun->machine->is_interrupt || cfun->machine->is_signal)
+ && live_seq);
- if (do_save)
+ if (cfun->machine->is_interrupt || cfun->machine->is_signal)
{
- fprintf (file, AS2 (in, __tmp_reg__, __SREG__) 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;
+
+ /* Clear zero reg. */
+ insn = emit_move_insn (zero_reg_rtx, const0_rtx);
+ RTX_FRAME_RELATED_P (insn) = 1;
- if (do_cli)
- {
- fprintf (file, "cli" CR_TAB);
- size++;
+ /* Prevent any attempt to delete the setting of ZERO_REG! */
+ emit_insn (gen_rtx_USE (VOIDmode, zero_reg_rtx));
}
-
- /* Do SPH first - maybe this will disable interrupts for one instruction
- someday (a suggestion has been sent to avr@atmel.com for consideration
- in future devices - that would make -mno-interrupts always safe). */
- if (do_sph)
+ if (cfun->machine->is_main)
{
- fprintf (file, AS2 (out, __SP_H__, r29) CR_TAB);
- size++;
+ 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;
}
-
- /* 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)
+ else if (minimize && (frame_pointer_needed || live_seq > 6))
{
- fprintf (file, AS2 (out, __SREG__, __tmp_reg__) CR_TAB);
- size++;
+ 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 if (do_sei)
+ else
{
- fprintf (file, "sei" CR_TAB);
- size++;
+ HARD_REG_SET set;
+ avr_regs_to_save (&set);
+ 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)
+ {
+ /* 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;
+ }
+ }
+ }
}
-
- fprintf (file, AS2 (out, __SP_L__, r28) "\n");
-
- return size;
}
-
-/* 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 if (cfun->machine->is_main)
+ {
+ fputs ("/* prologue: main */\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;
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();
+ rtx insn;
+
+ /* epilogue: naked */
+ if (cfun->machine->is_naked)
{
- fputs ("/* epilogue: noreturn */\n", file);
- goto out;
+ insn = emit_jump_insn (gen_return ());
+ RTX_FRAME_RELATED_P (insn) = 1;
+ 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 (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);
- }
- 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. */
+ 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, 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;
- 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. */
+ 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;
+ }
}
+/* 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. */
*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
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;
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;
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
(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")
(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"))]
}
}")
+(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")
[(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
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
(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)]
""
(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;
+ }")