----- Original Message ----- From: "Denis Chertykov" <[EMAIL PROTECTED]> To: "Anatoly Sokolov" <[EMAIL PROTECTED]> Cc: <[email protected]>; <[email protected]>; "Denis Chertykov" <[EMAIL PROTECTED]>; <[EMAIL PROTECTED]> Sent: Monday, June 26, 2006 6:51 PM Subject: Re: [avr-libc-dev] [AVR] RTL prologue/epilogue
>> > >> > Attached is modifed Andy Hutchinson patch that changes AVR GCC to use RTL >> > prologue/epilogue generation. >> > Original patch: http://gcc.gnu.org/ml/gcc/2005-03/msg00923.html >> > >> > New pach is for GCC 4.2. > It is necessary to do: > This patch seems wrong for me: > 2. insn "incstackhi" (Now - "subhi3_sp_1", "subhi3_sp_2", ..., "subhi3_sp_6") > must be part of addhi > (even more I would to have addhi sp, > -1 push > -2 rcall > -3 push + rcall > -4 rcall + rcall > -5 rcall + rcall + push > -6 rcall + rcall + rcall); Anatoly. Index: gcc/config/avr/avr-protos.h =================================================================== --- gcc/config/avr/avr-protos.h (revision 115874) +++ gcc/config/avr/avr-protos.h (working copy) @@ -88,6 +88,10 @@ 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[]); Index: gcc/config/avr/avr.md =================================================================== --- gcc/config/avr/avr.md (revision 115874) +++ gcc/config/avr/avr.md (working copy) @@ -43,10 +43,19 @@ (REG_Y 28) (REG_Z 30) (REG_W 24) + (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 "constraints.md") @@ -142,6 +151,48 @@ pop __tmp_reg__" [(set_attr "length" "5")]) +(define_insn "*subhi3_sp_1" + [(set (reg:HI 32) (minus:HI (reg:HI 32) (const_int 1)))] + "" + "push __tmp_reg__" + [(set_attr "length" "1")]) + +(define_insn "*subhi3_sp_2" + [(set (reg:HI 32) (minus:HI (reg:HI 32) (const_int 2)))] + "AVR_2_BYTE_PC" + "rcall ." + [(set_attr "length" "1")]) + +(define_insn "*subhi3_sp_3" + [(set (reg:HI 32) (minus:HI (reg:HI 32) (const_int 3)))] + "AVR_2_BYTE_PC" + "rcall . + push __tmp_reg__" + [(set_attr "length" "2")]) + +(define_insn "*subhi3_sp_4" + [(set (reg:HI 32) (minus:HI (reg:HI 32) (const_int 4)))] + "AVR_2_BYTE_PC" + "rcall . + rcall ." + [(set_attr "length" "2")]) + +(define_insn "*subhi3_sp_5" + [(set (reg:HI 32) (minus:HI (reg:HI 32) (const_int 5)))] + "AVR_2_BYTE_PC" + "rcall . + rcall . + push __tmp_reg__" + [(set_attr "length" "3")]) + +(define_insn "*subhi3_sp_6" + [(set (reg:HI 32) (minus:HI (reg:HI 32) (const_int 6)))] + "AVR_2_BYTE_PC" + "rcall . + rcall . + rcall ." + [(set_attr "length" "3")]) + (define_insn "*pushqi" [(set (mem:QI (post_dec (reg:HI 32))) (match_operand:QI 0 "nonmemory_operand" "r,L"))] @@ -179,7 +230,23 @@ push %B0 push %A0" [(set_attr "length" "4")]) - + +(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")]) + ;;======================================================================== ;; move byte ;; The last alternative (any immediate constant to any register) is @@ -2058,6 +2125,10 @@ ;; ************************************************************************** ;; Unconditional and other jump instructions. +;; Returns 1 if OP is a SYMBOL_REF. +(define_predicate "symbol_ref_operand" + (match_code "symbol_ref")) + (define_insn "jump" [(set (pc) (label_ref (match_operand 0 "" "")))] @@ -2068,10 +2139,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 @@ -2166,13 +2241,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)] "" @@ -2536,3 +2604,138 @@ (pc)))] "jump_over_one_insn_p (insn, operands[2])" "cpse %0,%1") + +;;pppppppppppppppppppppppppppppppppppppppppppppppppppp +;;prologue/epilogue support instructions + +;; 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 32 ) (minus:HI + (reg:HI 32) + (match_operand:HI 0 "immediate_operand" ""))) + (set (reg:HI 32 ) (minus:HI + (reg:HI 32) + (match_operand:HI 1 "immediate_operand" ""))) + (set (reg:HI 26) (match_dup 0)) + (clobber (reg:HI 30))] + "" + "* + { + return (AS2 (ldi,r26,lo8(%0)) CR_TAB + AS2 (ldi,r27,hi8(%0)) CR_TAB + AS2 (ldi,r30,pm_lo8(1f)) CR_TAB + AS2 (ldi,r31,pm_hi8(1f)) CR_TAB + AS1 (%~jmp,__prologue_saves__+(%1)) \"\\n\" + \"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 28 ) (plus:HI + (reg:HI 28) + (match_operand:HI 0 "immediate_operand" ""))) + (set (reg:HI 32) (reg:HI 28)) + (clobber (reg:QI 30))] + "" + "* + { + rtx ops[4]; + ops[0]=operands[0]; + ops[1]=gen_int_mode((18 - INTVAL(operands[0])) * 2,HImode); + + output_asm_insn(AS2 (ldi,r30,lo8(%0)),ops); + output_asm_insn(AS1 (%~jmp,__epilogue_restores__+(%1)),ops); + + return \"\"; + }" + [(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 + && !MAIN_NAME_P (DECL_NAME (current_function_decl)) + && cfun->machine + && !cfun->machine->interrupt_handler)" + "ret" + [(set_attr "cc" "none") + (set_attr "length" "1")]) + +(define_insn "return_from_main_epilogue" + [(return)] + "(reload_completed + && MAIN_NAME_P (DECL_NAME (current_function_decl)))" + "%~jmp _exit" + [(set_attr_alternative "length" + [(if_then_else (eq_attr "mcu_mega" "yes") + (const_int 2) + (const_int 1))]) + (set_attr "cc" "clobber") + ]) + +(define_insn "return_from_interrupt_epilogue" + [(return)] + "(reload_completed + && !MAIN_NAME_P (DECL_NAME (current_function_decl)) + && cfun->machine + && cfun->machine->interrupt_handler)" + "reti" + [(set_attr "cc" "none") + (set_attr "length" "1")]) + +(define_expand "prologue" + [(const_int 0)] + "" + " + { + expand_prologue (); + DONE; + }") + +(define_expand "epilogue" + [(const_int 0)] + "" + " + { + expand_epilogue (); + DONE; + }") Index: gcc/config/avr/avr.c =================================================================== --- gcc/config/avr/avr.c (revision 115874) +++ gcc/config/avr/avr.c (working copy) @@ -56,8 +56,7 @@ 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 @@ 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,6 +78,7 @@ static bool avr_rtx_costs (rtx, int, int, int *); static int avr_address_cost (rtx); static bool avr_return_in_memory (tree, tree); +static bool is_prologue_epilogue_insn(rtx insn); /* Allocate registers from r25 to r8 for parameters for function calls. */ #define FIRST_CUM_REG 26 @@ -107,9 +107,12 @@ /* Prologue/Epilogue size in words */ static int prologue_size; static int epilogue_size; +/* Flag is true if we are building prologue/epilogue */ +static bool building_prologue_epilogue; /* Size of all jump tables in the current function, in words. */ static int jump_tables_size; +static int function_size; /* Preprocessor macros to define depending on MCU type. */ const char *avr_base_arch_macro; @@ -276,10 +279,10 @@ #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 @@ -303,6 +306,14 @@ struct gcc_target targetm = TARGET_INITIALIZER; + +static struct machine_function * +avr_init_machine_status (void) +{ + return ((struct machine_function *) + ggc_alloc_cleared (sizeof (struct machine_function))); +} + void avr_override_options (void) { @@ -334,6 +345,8 @@ 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. */ @@ -526,254 +539,289 @@ } -/* 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) +static int size_of_insn(rtx insn) { - 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; + int l=get_attr_length (insn); + l= adjust_insn_length (insn,l); + return l; } -/* 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) +/* Return true if insn is part of prologue or epilogue.*/ +static bool is_prologue_epilogue_insn(rtx insn) { - int do_sph, do_cli, do_save, do_sei, lock_sph, size; + return (building_prologue_epilogue || prologue_epilogue_contains(insn)); +} - /* 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; +/* Placeholders for prologue saving of tmp/zero regs in ISR. */ +/* Unused - potential future enhancement to avoid save/restores. */ +static int uses_zero_reg =true; +static int uses_tmp_reg = true; +static int uses_status_reg = true; - 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 [EMAIL PROTECTED] 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) +/* Output function prologue. */ +void +expand_prologue (void) { - 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(); + building_prologue_epilogue=true; last_insn_address = 0; jump_tables_size = 0; prologue_size = 0; - fprintf (file, "/* prologue: frame size=" HOST_WIDE_INT_PRINT_DEC " */\n", - 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 (avr_naked_function_p (current_function_decl)) { - fputs ("/* prologue: naked */\n", file); + /* prologue: naked */ 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->interrupt_handler = (interrupt_func_p || signal_func_p); - 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 (interrupt_func_p) + { + /* enable interrupts */ + insn = emit_insn (gen_enable_interrupt ()); + RTX_FRAME_RELATED_P (insn) = 1; + prologue_size +=size_of_insn (insn); + } + /* Push tmp, zero regs and SREG status. */ + if (uses_tmp_reg) + { + insn = emit_move_insn (pushbyte,tmp_reg_rtx); + RTX_FRAME_RELATED_P (insn) = 1; + prologue_size += size_of_insn (insn); + } + if (uses_status_reg) + { + /* push SREG */ + insn = emit_move_insn (tmp_reg_rtx, + gen_rtx_MEM(QImode, GEN_INT(SREG_ADDR))); + RTX_FRAME_RELATED_P (insn) = 1; + prologue_size += size_of_insn (insn); + insn=emit_move_insn (pushbyte, tmp_reg_rtx); + RTX_FRAME_RELATED_P (insn) = 1; + prologue_size += size_of_insn (insn); + } + if (uses_zero_reg) + { + insn = emit_move_insn (pushbyte,zero_reg_rtx); + RTX_FRAME_RELATED_P (insn) = 1; + prologue_size += size_of_insn (insn); + + insn = emit_move_insn (zero_reg_rtx, const0_rtx); + RTX_FRAME_RELATED_P (insn) = 1; + prologue_size += size_of_insn (insn); + + /* Prevent any attempt to delete the setting of ZERO_REG! */ + emit_insn (gen_rtx_USE (VOIDmode, zero_reg_rtx)); + } } 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; + 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; + prologue_size += size_of_insn (insn); + insn=emit_move_insn (stack_pointer_rtx, frame_pointer_rtx); + RTX_FRAME_RELATED_P (insn) = 1; + prologue_size += size_of_insn (insn); } 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 ((18 - live_seq) * 2, HImode))); + RTX_FRAME_RELATED_P (insn) = 1; + prologue_size += size_of_insn (insn); + /* Label for body */ + emit_label (gen_label_rtx ()); } 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; + prologue_size +=size_of_insn (insn); + } + } 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); + { + /* Push frame pointer. */ + insn = emit_move_insn (pushword, frame_pointer_rtx); + RTX_FRAME_RELATED_P (insn) = 1; + prologue_size += size_of_insn (insn); + if (!size) + { + insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx); + RTX_FRAME_RELATED_P (insn) = 1; + prologue_size += size_of_insn (insn); + } + 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 ("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 = size_of_insn (gen_move_insn ( + frame_pointer_rtx, stack_pointer_rtx)); + method1_length += size_of_insn (gen_move_insn (myfp, + gen_rtx_PLUS (GET_MODE(myfp), myfp, + gen_int_mode (-size,GET_MODE(myfp))))); + /* output_movhi() takes care of variants*/ + method1_length += size_of_insn(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 = size_of_insn (gen_move_insn ( + stack_pointer_rtx, + gen_rtx_MINUS (HImode, stack_pointer_rtx, + gen_int_mode (size, HImode)))); + sp_plus_length += size_of_insn (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_MINUS (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; + prologue_size += sp_plus_length; + } + 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; + prologue_size += method1_length; + } + } + } + } + out: + building_prologue_epilogue=false; +} - 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); - } - } - } +/* Output summary at end of function prologue. */ +static void +avr_asm_function_end_prologue (FILE *file) +{ + if (avr_naked_function_p (current_function_decl)) + { + fputs ("/* prologue: naked */\n", file); } + else + { + if (interrupt_function_p (current_function_decl)) + { + fputs ("/* prologue: Interrupt */\n", file); + } + else if (signal_function_p (current_function_decl)) + { + fputs ("/* prologue: Signal */\n", file); + } + else if (MAIN_NAME_P (DECL_NAME (current_function_decl))) + { + fputs ("/* prologue: main */\n", file); + } + else + fputs ("/* prologue: function */\n", file); + } + fprintf (file, "/* frame size=" HOST_WIDE_INT_PRINT_DEC + " prologue size %d */\n", + get_frame_size(), prologue_size); +} - out: - fprintf (file, "/* prologue end (size=%d) */\n", prologue_size); + +/* Implement EPILOGUE_USES. */ +int +avr_epilogue_uses (int regno) +{ + if (cfun->machine && cfun->machine->interrupt_handler && reload_completed) + 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 (); - + HOST_WIDE_INT size = get_frame_size(); + building_prologue_epilogue=true; + rtx insn; function_size = jump_tables_size; if (last) { @@ -782,19 +830,18 @@ 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); + /* epilogue: naked */ goto out; } if (last && GET_CODE (last) == BARRIER) { - fputs ("/* epilogue: noreturn */\n", file); + /* epilogue: noreturn */ goto out; } @@ -808,106 +855,155 @@ if (main_p) { /* 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; + epilogue_size += size_of_insn (insn); } 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; + epilogue_size += size_of_insn (insn); } else { - fprintf (file, (AS2 (in , r28, __SP_L__) CR_TAB - AS2 (in , r29, __SP_H__) CR_TAB)); - epilogue_size += 2; + insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx); + RTX_FRAME_RELATED_P (insn) = 1; + epilogue_size += size_of_insn (insn); } - - 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_insn (gen_epilogue_restores( + gen_int_mode (live_seq, HImode))); + RTX_FRAME_RELATED_P (insn) = 1; + epilogue_size+=size_of_insn (insn); } 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 =size_of_insn (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 += size_of_insn (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 = size_of_insn (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; + epilogue_size += sp_plus_length; + } + 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; + epilogue_size += fp_plus_length; + } + } + + /* Restore previous frame_pointer. */ + insn = emit_insn (gen_pophi (frame_pointer_rtx)); + RTX_FRAME_RELATED_P (insn) = 1; + epilogue_size += size_of_insn (insn); } - - 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; + epilogue_size += size_of_insn (insn); + } + } + if (interrupt_func_p || signal_func_p) + { + if (uses_zero_reg) + { + insn = emit_insn (gen_popqi (zero_reg_rtx)); + RTX_FRAME_RELATED_P (insn) = 1; + epilogue_size += size_of_insn (insn); + } + if (uses_status_reg) + { + /* Restore SREG using tmp reg as scratch. */ + insn = emit_insn (gen_popqi (tmp_reg_rtx)); + RTX_FRAME_RELATED_P (insn) = 1; + epilogue_size += size_of_insn (insn); + + insn = emit_move_insn (gen_rtx_MEM(QImode, GEN_INT(SREG_ADDR)), + tmp_reg_rtx); + RTX_FRAME_RELATED_P (insn) = 1; + epilogue_size += size_of_insn (insn); + } + if (uses_tmp_reg) + { + insn = emit_insn (gen_popqi (tmp_reg_rtx)); + RTX_FRAME_RELATED_P (insn) = 1; + epilogue_size += size_of_insn (insn); + } + } - 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; + insn = emit_jump_insn (gen_return ()); + RTX_FRAME_RELATED_P (insn) = 1; + epilogue_size += size_of_insn (insn); } 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; + building_prologue_epilogue=false; } +/* Output summary messages at beginning of function epilogue. */ +static void +avr_asm_function_begin_epilogue (FILE *file) +{ + fprintf (file, "/* function %s size %d (%d) */\n", current_function_name (), + prologue_size + function_size + epilogue_size, function_size); + fprintf (file, "/* epilogue start (size=%d) */\n", epilogue_size); + rtx last = get_last_nonnote_insn (); + if (last && GET_CODE (last) == BARRIER) + { + fputs ("/* epilogue: noreturn */\n", file); + } +} + + /* Return nonzero if X (an RTX) is a legitimate memory address on the target machine for a memory operand of mode MODE. */ @@ -1642,13 +1738,32 @@ *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 + && MAIN_NAME_P (DECL_NAME (current_function_decl)) + && is_prologue_epilogue_insn (insn)) + || (reload_completed + && signal_function_p (current_function_decl) + && is_prologue_epilogue_insn (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 + && interrupt_function_p (current_function_decl) + && is_prologue_epilogue_insn (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 @@ -1796,6 +1911,11 @@ if (CONSTANT_ADDRESS_P (x)) { + if (GET_CODE (x) == CONST_INT && INTVAL (x) == SREG_ADDR) + { + *l = 1; + return AS2 (in,%0,__SREG__); + } if (avr_io_address_p (x, 1)) { *l = 1; @@ -2479,6 +2599,11 @@ if (CONSTANT_ADDRESS_P (x)) { + if (GET_CODE (x) == CONST_INT && INTVAL (x) == SREG_ADDR) + { + *l = 1; + return AS2 (out,__SREG__,%1); + } if (avr_io_address_p (x, 1)) { *l = 1; Index: gcc/config/avr/avr.h =================================================================== --- gcc/config/avr/avr.h (revision 115874) +++ gcc/config/avr/avr.h (working copy) @@ -21,6 +21,9 @@ the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +/* Offset from the frame pointer register value to the top of the stack. */ +#define FRAME_POINTER_CFA_OFFSET(FNDECL) 0 + /* Names to predefine in the preprocessor for this target machine. */ #define TARGET_CPU_CPP_BUILTINS() \ @@ -60,6 +63,8 @@ #define AVR_ENHANCED (avr_enhanced_p) #define AVR_HAVE_MOVW (avr_have_movw_lpmx_p) +#define AVR_2_BYTE_PC 1 + #define TARGET_VERSION fprintf (stderr, " (GNU assembler syntax)"); #define OVERRIDE_OPTIONS avr_override_options () @@ -332,7 +337,7 @@ #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 @@ -913,3 +918,10 @@ #define CR_TAB "\n\t" #define PREFERRED_DEBUGGING_TYPE DBX_DEBUG + +/* A C structure for machine-specific, per-function data. + This is added to the cfun structure. */ +struct machine_function GTY(()) +{ + int interrupt_handler; +};
_______________________________________________ AVR-libc-dev mailing list [email protected] http://lists.nongnu.org/mailman/listinfo/avr-libc-dev
