From bdfe906f8c3dcce2fe349c97eb1b9d448b0f495e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 22 Mar 2011 09:02:51 -0700 Subject: [PATCH] avr.c (TARGET_EXCEPT_UNWIND_INFO): New. * config/avr/avr.c (TARGET_EXCEPT_UNWIND_INFO): New. (avr_incoming_return_addr_rtx): New. (emit_push_byte): New. (expand_prologue): Use it. Remove incorrect dwarf annotation for SREG, RAMPZ, zero register. Push frame pointer by bytes. Add dwarf annotation for __prologue_saves__. Fixup dwarf annotation for CFA. (emit_pop_byte): New. (expand_epilogue): Use it. Pop frame pointer by bytes. * config/avr/avr.h (FRAME_POINTER_CFA_OFFSET): Remove. (INCOMING_RETURN_ADDR_RTX): New. (INCOMING_FRAME_SP_OFFSET): New. (ARG_POINTER_CFA_OFFSET): New. * config/avr/avr.md (*pushqi): Fix mode of auto-inc. (*pushhi, *pushsi, *pushsf, popqi): Likewise. (pophi): Remove. From-SVN: r171295 --- gcc/ChangeLog | 18 +++ gcc/config/avr/avr-protos.h | 1 + gcc/config/avr/avr.c | 295 +++++++++++++++++++++--------------- gcc/config/avr/avr.h | 10 +- gcc/config/avr/avr.md | 19 +-- 5 files changed, 207 insertions(+), 136 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 4413aa625aa..396c8be7a84 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,21 @@ +2011-03-22 Richard Henderson + + * config/avr/avr.c (TARGET_EXCEPT_UNWIND_INFO): New. + (avr_incoming_return_addr_rtx): New. + (emit_push_byte): New. + (expand_prologue): Use it. Remove incorrect dwarf annotation for + SREG, RAMPZ, zero register. Push frame pointer by bytes. Add dwarf + annotation for __prologue_saves__. Fixup dwarf annotation for CFA. + (emit_pop_byte): New. + (expand_epilogue): Use it. Pop frame pointer by bytes. + * config/avr/avr.h (FRAME_POINTER_CFA_OFFSET): Remove. + (INCOMING_RETURN_ADDR_RTX): New. + (INCOMING_FRAME_SP_OFFSET): New. + (ARG_POINTER_CFA_OFFSET): New. + * config/avr/avr.md (*pushqi): Fix mode of auto-inc. + (*pushhi, *pushsi, *pushsf, popqi): Likewise. + (pophi): Remove. + 2011-03-22 Nathan Froyd * tree.c (build_call_1): New function. diff --git a/gcc/config/avr/avr-protos.h b/gcc/config/avr/avr-protos.h index 67e915a569e..3882429adb1 100644 --- a/gcc/config/avr/avr-protos.h +++ b/gcc/config/avr/avr-protos.h @@ -108,6 +108,7 @@ extern RTX_CODE avr_normalize_condition (RTX_CODE condition); extern int compare_eq_p (rtx insn); extern void out_shift_with_cnt (const char *templ, rtx insn, rtx operands[], int *len, int t_len); +extern rtx avr_incoming_return_addr_rtx (void); #endif /* RTX_CODE */ #ifdef HAVE_MACHINE_MODES diff --git a/gcc/config/avr/avr.c b/gcc/config/avr/avr.c index f9211886be5..9a32b973c9a 100644 --- a/gcc/config/avr/avr.c +++ b/gcc/config/avr/avr.c @@ -246,6 +246,9 @@ static const struct default_options avr_option_optimization_table[] = #undef TARGET_HELP #define TARGET_HELP avr_help +#undef TARGET_EXCEPT_UNWIND_INFO +#define TARGET_EXCEPT_UNWIND_INFO sjlj_except_unwind_info + struct gcc_target targetm = TARGET_INITIALIZER; static void @@ -597,6 +600,35 @@ get_sequence_length (rtx insns) return length; } +/* Implement INCOMING_RETURN_ADDR_RTX. */ + +rtx +avr_incoming_return_addr_rtx (void) +{ + /* The return address is at the top of the stack. Note that the push + was via post-decrement, which means the actual address is off by one. */ + return gen_frame_mem (HImode, plus_constant (stack_pointer_rtx, 1)); +} + +/* Helper for expand_prologue. Emit a push of a byte register. */ + +static void +emit_push_byte (unsigned regno, bool frame_related_p) +{ + rtx mem, reg, insn; + + mem = gen_rtx_POST_DEC (HImode, stack_pointer_rtx); + mem = gen_frame_mem (QImode, mem); + reg = gen_rtx_REG (QImode, regno); + + insn = emit_insn (gen_rtx_SET (VOIDmode, mem, reg)); + if (frame_related_p) + RTX_FRAME_RELATED_P (insn) = 1; + + cfun->machine->stack_usage++; +} + + /* Output function prologue. */ void @@ -606,11 +638,6 @@ expand_prologue (void) HARD_REG_SET set; 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; /* Init cfun->machine. */ @@ -638,46 +665,34 @@ expand_prologue (void) if (cfun->machine->is_interrupt || cfun->machine->is_signal) { + /* Enable interrupts. */ if (cfun->machine->is_interrupt) - { - /* Enable interrupts. */ - insn = emit_insn (gen_enable_interrupt ()); - RTX_FRAME_RELATED_P (insn) = 1; - } + emit_insn (gen_enable_interrupt ()); /* Push zero reg. */ - insn = emit_move_insn (pushbyte, zero_reg_rtx); - RTX_FRAME_RELATED_P (insn) = 1; - cfun->machine->stack_usage++; + emit_push_byte (ZERO_REGNO, true); /* Push tmp reg. */ - insn = emit_move_insn (pushbyte, tmp_reg_rtx); - RTX_FRAME_RELATED_P (insn) = 1; - cfun->machine->stack_usage++; + emit_push_byte (TMP_REGNO, true); /* 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; - cfun->machine->stack_usage++; + /* ??? There's no dwarf2 column reserved for SREG. */ + emit_move_insn (tmp_reg_rtx, gen_rtx_MEM (QImode, GEN_INT (SREG_ADDR))); + emit_push_byte (TMP_REGNO, false); /* Push RAMPZ. */ - if(AVR_HAVE_RAMPZ - && (TEST_HARD_REG_BIT (set, REG_Z) && TEST_HARD_REG_BIT (set, REG_Z + 1))) + /* ??? There's no dwarf2 column reserved for RAMPZ. */ + if (AVR_HAVE_RAMPZ + && TEST_HARD_REG_BIT (set, REG_Z) + && TEST_HARD_REG_BIT (set, REG_Z + 1)) { - insn = emit_move_insn (tmp_reg_rtx, - gen_rtx_MEM (QImode, GEN_INT (RAMPZ_ADDR))); - RTX_FRAME_RELATED_P (insn) = 1; - insn = emit_move_insn (pushbyte, tmp_reg_rtx); - RTX_FRAME_RELATED_P (insn) = 1; - cfun->machine->stack_usage++; + emit_move_insn (tmp_reg_rtx, + gen_rtx_MEM (QImode, GEN_INT (RAMPZ_ADDR))); + emit_push_byte (TMP_REGNO, false); } /* Clear zero reg. */ - insn = emit_move_insn (zero_reg_rtx, const0_rtx); - RTX_FRAME_RELATED_P (insn) = 1; + emit_move_insn (zero_reg_rtx, const0_rtx); /* Prevent any attempt to delete the setting of ZERO_REG! */ emit_use (zero_reg_rtx); @@ -686,37 +701,63 @@ expand_prologue (void) || (AVR_2_BYTE_PC && live_seq > 6) || live_seq > 7)) { - insn = emit_move_insn (gen_rtx_REG (HImode, REG_X), - gen_int_mode (size, HImode)); - RTX_FRAME_RELATED_P (insn) = 1; + int first_reg, reg, offset; + + emit_move_insn (gen_rtx_REG (HImode, REG_X), + gen_int_mode (size, HImode)); - insn = - emit_insn (gen_call_prologue_saves (gen_int_mode (live_seq, HImode), - gen_int_mode (size + live_seq, HImode))); + insn = emit_insn (gen_call_prologue_saves + (gen_int_mode (live_seq, HImode), + gen_int_mode (size + live_seq, HImode))); RTX_FRAME_RELATED_P (insn) = 1; + + /* Describe the effect of the unspec_volatile call to prologue_saves. + Note that this formulation assumes that add_reg_note pushes the + notes to the front. Thus we build them in the reverse order of + how we want dwarf2out to process them. */ + + /* The function does always set frame_pointer_rtx, but whether that + is going to be permanent in the function is frame_pointer_needed. */ + add_reg_note (insn, REG_CFA_ADJUST_CFA, + gen_rtx_SET (VOIDmode, + (frame_pointer_needed + ? frame_pointer_rtx : stack_pointer_rtx), + plus_constant (stack_pointer_rtx, + -(size + live_seq)))); + + /* Note that live_seq always contains r28+r29, but the other + registers to be saved are all below 18. */ + first_reg = 18 - (live_seq - 2); + + for (reg = 29, offset = -live_seq + 1; + reg >= first_reg; + reg = (reg == 28 ? 17 : reg - 1), ++offset) + { + rtx m, r; + + m = gen_rtx_MEM (QImode, plus_constant (stack_pointer_rtx, offset)); + r = gen_rtx_REG (QImode, reg); + add_reg_note (insn, REG_CFA_OFFSET, gen_rtx_SET (VOIDmode, m, r)); + } + cfun->machine->stack_usage += size + live_seq; } else { 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; - cfun->machine->stack_usage++; - } - } + if (TEST_HARD_REG_BIT (set, reg)) + emit_push_byte (reg, true); + if (frame_pointer_needed) { if (!(cfun->machine->is_OS_task || cfun->machine->is_OS_main)) { - /* Push frame pointer. */ - insn = emit_move_insn (pushword, frame_pointer_rtx); - RTX_FRAME_RELATED_P (insn) = 1; - cfun->machine->stack_usage += 2; + /* Push frame pointer. Always be consistent about the + ordering of pushes -- epilogue_restores expects the + register pair to be pushed low byte first. */ + emit_push_byte (REG_Y, true); + emit_push_byte (REG_Y + 1, true); } if (!size) @@ -739,13 +780,12 @@ expand_prologue (void) is selected. */ rtx myfp; rtx fp_plus_insns; - rtx sp_plus_insns = NULL_RTX; if (AVR_HAVE_8BIT_SP) { - /* 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)); + /* The high byte (r29) doesn't change. Prefer 'subi' + (1 cycle) over 'sbiw' (2 cycles, same size). */ + myfp = gen_rtx_REG (QImode, FRAME_POINTER_REGNUM); } else { @@ -756,41 +796,43 @@ expand_prologue (void) /* Method 1-Adjust frame pointer. */ start_sequence (); - insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx); - RTX_FRAME_RELATED_P (insn) = 1; + /* Normally the dwarf2out frame-related-expr interpreter does + not expect to have the CFA change once the frame pointer is + set up. Thus we avoid marking the move insn below and + instead indicate that the entire operation is complete after + the frame pointer subtraction is done. */ - insn = - emit_move_insn (myfp, - gen_rtx_PLUS (GET_MODE(myfp), myfp, - gen_int_mode (-size, - GET_MODE(myfp)))); - RTX_FRAME_RELATED_P (insn) = 1; + emit_move_insn (frame_pointer_rtx, stack_pointer_rtx); - /* Copy to stack pointer. */ + insn = emit_move_insn (myfp, plus_constant (myfp, -size)); + RTX_FRAME_RELATED_P (insn) = 1; + add_reg_note (insn, REG_CFA_ADJUST_CFA, + gen_rtx_SET (VOIDmode, frame_pointer_rtx, + plus_constant (stack_pointer_rtx, + -size))); + + /* Copy to stack pointer. Note that since we've already + changed the CFA to the frame pointer this operation + need not be annotated at all. */ if (AVR_HAVE_8BIT_SP) { - insn = emit_move_insn (stack_pointer_rtx, frame_pointer_rtx); - RTX_FRAME_RELATED_P (insn) = 1; + emit_move_insn (stack_pointer_rtx, frame_pointer_rtx); } else if (TARGET_NO_INTERRUPTS || cfun->machine->is_signal || cfun->machine->is_OS_main) { - insn = - emit_insn (gen_movhi_sp_r_irq_off (stack_pointer_rtx, - frame_pointer_rtx)); - RTX_FRAME_RELATED_P (insn) = 1; + emit_insn (gen_movhi_sp_r_irq_off (stack_pointer_rtx, + frame_pointer_rtx)); } else if (cfun->machine->is_interrupt) { - insn = emit_insn (gen_movhi_sp_r_irq_on (stack_pointer_rtx, - frame_pointer_rtx)); - RTX_FRAME_RELATED_P (insn) = 1; + emit_insn (gen_movhi_sp_r_irq_on (stack_pointer_rtx, + frame_pointer_rtx)); } else { - insn = emit_move_insn (stack_pointer_rtx, frame_pointer_rtx); - RTX_FRAME_RELATED_P (insn) = 1; + emit_move_insn (stack_pointer_rtx, frame_pointer_rtx); } fp_plus_insns = get_insns (); @@ -799,30 +841,30 @@ expand_prologue (void) /* Method 2-Adjust Stack pointer. */ if (size <= 6) { + rtx sp_plus_insns; + start_sequence (); - insn = - emit_move_insn (stack_pointer_rtx, - gen_rtx_PLUS (HImode, - stack_pointer_rtx, - gen_int_mode (-size, - HImode))); + insn = plus_constant (stack_pointer_rtx, -size); + insn = emit_move_insn (stack_pointer_rtx, insn); RTX_FRAME_RELATED_P (insn) = 1; - insn = - emit_move_insn (frame_pointer_rtx, stack_pointer_rtx); + insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx); RTX_FRAME_RELATED_P (insn) = 1; sp_plus_insns = get_insns (); end_sequence (); - } - /* Use shortest method. */ - if (size <= 6 && (get_sequence_length (sp_plus_insns) - < get_sequence_length (fp_plus_insns))) - emit_insn (sp_plus_insns); - else + /* Use shortest method. */ + if (get_sequence_length (sp_plus_insns) + < get_sequence_length (fp_plus_insns)) + emit_insn (sp_plus_insns); + else + emit_insn (fp_plus_insns); + } + else emit_insn (fp_plus_insns); + cfun->machine->stack_usage += size; } } @@ -876,6 +918,20 @@ avr_epilogue_uses (int regno ATTRIBUTE_UNUSED) return 0; } +/* Helper for expand_epilogue. Emit a pop of a byte register. */ + +static void +emit_pop_byte (unsigned regno) +{ + rtx mem, reg; + + mem = gen_rtx_PRE_INC (HImode, stack_pointer_rtx); + mem = gen_frame_mem (QImode, mem); + reg = gen_rtx_REG (QImode, regno); + + emit_insn (gen_rtx_SET (VOIDmode, reg, mem)); +} + /* Output RTL epilogue. */ void @@ -928,13 +984,12 @@ expand_epilogue (void) /* Try two methods to adjust stack and select shortest. */ rtx myfp; rtx fp_plus_insns; - rtx sp_plus_insns = NULL_RTX; - + if (AVR_HAVE_8BIT_SP) { /* 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)); + myfp = gen_rtx_REG (QImode, FRAME_POINTER_REGNUM); } else { @@ -945,10 +1000,7 @@ expand_epilogue (void) /* Method 1-Adjust frame pointer. */ start_sequence (); - emit_move_insn (myfp, - gen_rtx_PLUS (GET_MODE (myfp), myfp, - gen_int_mode (size, - GET_MODE(myfp)))); + emit_move_insn (myfp, plus_constant (myfp, size)); /* Copy to stack pointer. */ if (AVR_HAVE_8BIT_SP) @@ -977,58 +1029,63 @@ expand_epilogue (void) /* Method 2-Adjust Stack pointer. */ if (size <= 5) { + rtx sp_plus_insns; + start_sequence (); emit_move_insn (stack_pointer_rtx, - gen_rtx_PLUS (HImode, stack_pointer_rtx, - gen_int_mode (size, - HImode))); + plus_constant (stack_pointer_rtx, size)); sp_plus_insns = get_insns (); end_sequence (); - } - /* Use shortest method. */ - if (size <= 5 && (get_sequence_length (sp_plus_insns) - < get_sequence_length (fp_plus_insns))) - emit_insn (sp_plus_insns); - else + /* Use shortest method. */ + if (get_sequence_length (sp_plus_insns) + < get_sequence_length (fp_plus_insns)) + emit_insn (sp_plus_insns); + else + emit_insn (fp_plus_insns); + } + else emit_insn (fp_plus_insns); } if (!(cfun->machine->is_OS_task || cfun->machine->is_OS_main)) { - /* Restore previous frame_pointer. */ - emit_insn (gen_pophi (frame_pointer_rtx)); + /* Restore previous frame_pointer. See expand_prologue for + rationale for not using pophi. */ + emit_pop_byte (REG_Y + 1); + emit_pop_byte (REG_Y); } } + /* Restore used registers. */ for (reg = 31; reg >= 0; --reg) - { - if (TEST_HARD_REG_BIT (set, reg)) - emit_insn (gen_popqi (gen_rtx_REG (QImode, reg))); - } + if (TEST_HARD_REG_BIT (set, reg)) + emit_pop_byte (reg); + if (cfun->machine->is_interrupt || cfun->machine->is_signal) { /* Restore RAMPZ using tmp reg as scratch. */ - if(AVR_HAVE_RAMPZ - && (TEST_HARD_REG_BIT (set, REG_Z) && TEST_HARD_REG_BIT (set, REG_Z + 1))) + if (AVR_HAVE_RAMPZ + && TEST_HARD_REG_BIT (set, REG_Z) + && TEST_HARD_REG_BIT (set, REG_Z + 1)) { - emit_insn (gen_popqi (tmp_reg_rtx)); - emit_move_insn (gen_rtx_MEM(QImode, GEN_INT(RAMPZ_ADDR)), + emit_pop_byte (TMP_REGNO); + emit_move_insn (gen_rtx_MEM (QImode, GEN_INT (RAMPZ_ADDR)), tmp_reg_rtx); } /* Restore SREG using tmp reg as scratch. */ - emit_insn (gen_popqi (tmp_reg_rtx)); + emit_pop_byte (TMP_REGNO); - emit_move_insn (gen_rtx_MEM(QImode, GEN_INT(SREG_ADDR)), + emit_move_insn (gen_rtx_MEM (QImode, GEN_INT (SREG_ADDR)), tmp_reg_rtx); /* Restore tmp REG. */ - emit_insn (gen_popqi (tmp_reg_rtx)); + emit_pop_byte (TMP_REGNO); /* Restore zero REG. */ - emit_insn (gen_popqi (zero_reg_rtx)); + emit_pop_byte (ZERO_REGNO); } emit_jump_insn (gen_return ()); diff --git a/gcc/config/avr/avr.h b/gcc/config/avr/avr.h index 146ab6793de..bd18aedc0f4 100644 --- a/gcc/config/avr/avr.h +++ b/gcc/config/avr/avr.h @@ -351,9 +351,6 @@ enum reg_class { #define STATIC_CHAIN_REGNUM 2 -/* Offset from the frame pointer register value to the top of the stack. */ -#define FRAME_POINTER_CFA_OFFSET(FNDECL) 0 - #define ELIMINABLE_REGS { \ {ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM}, \ {FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM} \ @@ -794,6 +791,13 @@ mmcu=*:-mmcu=%*}" #define OBJECT_FORMAT_ELF +#define INCOMING_RETURN_ADDR_RTX avr_incoming_return_addr_rtx () +#define INCOMING_FRAME_SP_OFFSET (AVR_3_BYTE_PC ? 3 : 2) + +/* The caller's stack pointer value immediately before the call + is one byte below the first argument. */ +#define ARG_POINTER_CFA_OFFSET(FNDECL) -1 + #define HARD_REGNO_RENAME_OK(OLD_REG, NEW_REG) \ avr_hard_regno_rename_ok (OLD_REG, NEW_REG) diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md index b9e92f4a253..0fdee391022 100644 --- a/gcc/config/avr/avr.md +++ b/gcc/config/avr/avr.md @@ -181,7 +181,7 @@ (define_insn "*pushqi" - [(set (mem:QI (post_dec (reg:HI REG_SP))) + [(set (mem:QI (post_dec:HI (reg:HI REG_SP))) (match_operand:QI 0 "reg_or_0_operand" "r,L"))] "" "@ @@ -189,9 +189,8 @@ push __zero_reg__" [(set_attr "length" "1,1")]) - (define_insn "*pushhi" - [(set (mem:HI (post_dec (reg:HI REG_SP))) + [(set (mem:HI (post_dec:HI (reg:HI REG_SP))) (match_operand:HI 0 "reg_or_0_operand" "r,L"))] "" "@ @@ -200,7 +199,7 @@ [(set_attr "length" "2,2")]) (define_insn "*pushsi" - [(set (mem:SI (post_dec (reg:HI REG_SP))) + [(set (mem:SI (post_dec:HI (reg:HI REG_SP))) (match_operand:SI 0 "reg_or_0_operand" "r,L"))] "" "@ @@ -209,7 +208,7 @@ [(set_attr "length" "4,4")]) (define_insn "*pushsf" - [(set (mem:SF (post_dec (reg:HI REG_SP))) + [(set (mem:SF (post_dec:HI (reg:HI REG_SP))) (match_operand:SF 0 "register_operand" "r"))] "" "push %D0 @@ -3126,20 +3125,12 @@ (define_insn "popqi" [(set (match_operand:QI 0 "register_operand" "=r") - (mem:QI (post_inc (reg:HI REG_SP))))] + (mem:QI (pre_inc:HI (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)] -- 2.30.2