From df3d6232299393f4c995d54e13ae47611bc8d823 Mon Sep 17 00:00:00 2001 From: aesok Date: Sat, 19 May 2007 10:59:17 +0000 Subject: * 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@124854 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/config/avr/avr-protos.h | 4 + gcc/config/avr/avr.c | 703 ++++++++++++++++++++++-------------------- gcc/config/avr/avr.h | 24 +- gcc/config/avr/avr.md | 365 ++++++++++++++++++---- gcc/config/avr/constraints.md | 5 + gcc/config/avr/predicates.md | 7 +- 6 files changed, 714 insertions(+), 394 deletions(-) (limited to 'gcc/config/avr') diff --git a/gcc/config/avr/avr-protos.h b/gcc/config/avr/avr-protos.h index ef084f06593..50dbd12cc26 100644 --- a/gcc/config/avr/avr-protos.h +++ b/gcc/config/avr/avr-protos.h @@ -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[]); diff --git a/gcc/config/avr/avr.c b/gcc/config/avr/avr.c index df6fe106fe7..950777c7c15 100644 --- a/gcc/config/avr/avr.c +++ b/gcc/config/avr/avr.c @@ -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; + 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. */ @@ -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 diff --git a/gcc/config/avr/avr.h b/gcc/config/avr/avr.h index a7216f4d70c..9c80f536d27 100644 --- a/gcc/config/avr/avr.h +++ b/gcc/config/avr/avr.h @@ -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; +}; diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md index a71e76c9f56..34dc7034ee0 100644 --- a/gcc/config/avr/avr.md +++ b/gcc/config/avr/avr.md @@ -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; + }") diff --git a/gcc/config/avr/constraints.md b/gcc/config/avr/constraints.md index eca5cbef292..f3ff9e962cc 100644 --- a/gcc/config/avr/constraints.md +++ b/gcc/config/avr/constraints.md @@ -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") diff --git a/gcc/config/avr/predicates.md b/gcc/config/avr/predicates.md index 914ad9bd47b..acc82f6d20e 100755 --- a/gcc/config/avr/predicates.md +++ b/gcc/config/avr/predicates.md @@ -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")) -- cgit v1.2.1