From a8e5c0e77e06f7776efcb59cf79562a2a16fb1df Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 9 Jul 2011 13:39:00 -0700 Subject: [PATCH] dwarf2cfi: Handle return column save from CIE. When we record a save of the return column in the CIE, remember that while processing the FDE. This requires propagating the handling of PC_RTX as a representative of the return column to more locations. MIPS had been handling this case by hand, and is no longer required. * dwarf2cfi.c (cie_return_save): New. (queue_reg_save): Use compare_reg_or_pc. (dwarf2out_flush_queued_reg_saves): Handle pc_rtx as return column. (dwarf2out_frame_debug_expr): Likewise. (dwarf2out_frame_debug_cfa_register): Record saved reg for pc too. (initial_return_save): Likewise. (execute_dwarf2_frame): Save and restore initial return save from the cie to the fde. * config/mips/mips.c (mips_frame_set): Remove special case for DWARF_FRAME_RETURN_COLUMN. From-SVN: r176099 --- gcc/ChangeLog | 13 +++ gcc/config/mips/mips.c | 7 -- gcc/dwarf2cfi.c | 222 +++++++++++++++++++++++------------------ 3 files changed, 139 insertions(+), 103 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index d5fd40a2cbb..bf10d3d361c 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,16 @@ +2011-07-09 Richard Henderson + + * dwarf2cfi.c (cie_return_save): New. + (queue_reg_save): Use compare_reg_or_pc. + (dwarf2out_flush_queued_reg_saves): Handle pc_rtx as return column. + (dwarf2out_frame_debug_expr): Likewise. + (dwarf2out_frame_debug_cfa_register): Record saved reg for pc too. + (initial_return_save): Likewise. + (execute_dwarf2_frame): Save and restore initial return save from + the cie to the fde. + * config/mips/mips.c (mips_frame_set): Remove special case for + DWARF_FRAME_RETURN_COLUMN. + 2011-07-09 Richard Henderson * dwarf2cfi.c (lookup_cfa): Remove. diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index f4010da3657..ee71c4040c7 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -8203,13 +8203,6 @@ mips_frame_set (rtx mem, rtx reg) { rtx set; - /* If we're saving the return address register and the DWARF return - address column differs from the hard register number, adjust the - note reg to refer to the former. */ - if (REGNO (reg) == RETURN_ADDR_REGNUM - && DWARF_FRAME_RETURN_COLUMN != RETURN_ADDR_REGNUM) - reg = gen_rtx_REG (GET_MODE (reg), DWARF_FRAME_RETURN_COLUMN); - set = gen_rtx_SET (VOIDmode, mem, reg); RTX_FRAME_RELATED_P (set) = 1; diff --git a/gcc/dwarf2cfi.c b/gcc/dwarf2cfi.c index b4b035ddd56..5b76df359f4 100644 --- a/gcc/dwarf2cfi.c +++ b/gcc/dwarf2cfi.c @@ -603,64 +603,6 @@ reg_save (unsigned int reg, unsigned int sreg, HOST_WIDE_INT offset) add_cfi (cfi); } -/* Record the initial position of the return address. RTL is - INCOMING_RETURN_ADDR_RTX. */ - -static void -initial_return_save (rtx rtl) -{ - unsigned int reg = INVALID_REGNUM; - HOST_WIDE_INT offset = 0; - - switch (GET_CODE (rtl)) - { - case REG: - /* RA is in a register. */ - reg = DWARF_FRAME_REGNUM (REGNO (rtl)); - break; - - case MEM: - /* RA is on the stack. */ - rtl = XEXP (rtl, 0); - switch (GET_CODE (rtl)) - { - case REG: - gcc_assert (REGNO (rtl) == STACK_POINTER_REGNUM); - offset = 0; - break; - - case PLUS: - gcc_assert (REGNO (XEXP (rtl, 0)) == STACK_POINTER_REGNUM); - offset = INTVAL (XEXP (rtl, 1)); - break; - - case MINUS: - gcc_assert (REGNO (XEXP (rtl, 0)) == STACK_POINTER_REGNUM); - offset = -INTVAL (XEXP (rtl, 1)); - break; - - default: - gcc_unreachable (); - } - - break; - - case PLUS: - /* The return address is at some offset from any value we can - actually load. For instance, on the SPARC it is in %i7+8. Just - ignore the offset for now; it doesn't matter for unwinding frames. */ - gcc_assert (CONST_INT_P (XEXP (rtl, 1))); - initial_return_save (XEXP (rtl, 0)); - return; - - default: - gcc_unreachable (); - } - - if (reg != DWARF_FRAME_RETURN_COLUMN) - reg_save (DWARF_FRAME_RETURN_COLUMN, reg, offset - cfa.offset); -} - /* Given a SET, calculate the amount of stack adjustment it contains. */ @@ -1088,6 +1030,8 @@ DEF_VEC_ALLOC_O (reg_saved_in_data, gc); 5 entries. */ static GTY(()) VEC(reg_saved_in_data, gc) *regs_saved_in_regs; +static GTY(()) reg_saved_in_data *cie_return_save; + /* Compare X and Y for equivalence. The inputs may be REGs or PC_RTX. */ static bool @@ -1134,10 +1078,9 @@ queue_reg_save (rtx reg, rtx sreg, HOST_WIDE_INT offset) struct queued_reg_save *q; /* Duplicates waste space, but it's also necessary to remove them - for correctness, since the queue gets output in reverse - order. */ + for correctness, since the queue gets output in reverse order. */ for (q = queued_reg_saves; q != NULL; q = q->next) - if (REGNO (q->reg) == REGNO (reg)) + if (compare_reg_or_pc (q->reg, reg)) break; if (q == NULL) @@ -1165,7 +1108,10 @@ dwarf2out_flush_queued_reg_saves (void) record_reg_saved_in_reg (q->saved_reg, q->reg); - reg = DWARF_FRAME_REGNUM (REGNO (q->reg)); + if (q->reg == pc_rtx) + reg = DWARF_FRAME_RETURN_COLUMN; + else + reg = DWARF_FRAME_REGNUM (REGNO (q->reg)); if (q->saved_reg) sreg = DWARF_FRAME_REGNUM (REGNO (q->saved_reg)); else @@ -1375,13 +1321,11 @@ dwarf2out_frame_debug_cfa_register (rtx set) src = XEXP (set, 1); dest = XEXP (set, 0); + record_reg_saved_in_reg (dest, src); if (src == pc_rtx) sregno = DWARF_FRAME_RETURN_COLUMN; else - { - record_reg_saved_in_reg (dest, src); - sregno = DWARF_FRAME_REGNUM (REGNO (src)); - } + sregno = DWARF_FRAME_REGNUM (REGNO (src)); dregno = DWARF_FRAME_REGNUM (REGNO (dest)); @@ -2031,14 +1975,14 @@ dwarf2out_frame_debug_expr (rtx expr) gcc_unreachable (); } - /* Rule 17 */ - /* If the source operand of this MEM operation is not a - register, basically the source is return address. Here - we only care how much stack grew and we don't save it. */ - if (!REG_P (src)) + /* Rule 17 */ + /* If the source operand of this MEM operation is a memory, + we only care how much stack grew. */ + if (MEM_P (src)) break; - if (REGNO (src) != STACK_POINTER_REGNUM + if (REG_P (src) + && REGNO (src) != STACK_POINTER_REGNUM && REGNO (src) != HARD_FRAME_POINTER_REGNUM && (unsigned) REGNO (src) == cfa.reg) { @@ -2098,32 +2042,30 @@ dwarf2out_frame_debug_expr (rtx expr) } def_cfa_1 (&cfa); - { - span = targetm.dwarf_register_span (src); - if (!span) - queue_reg_save (src, NULL_RTX, offset); - else - { - /* We have a PARALLEL describing where the contents of SRC - live. Queue register saves for each piece of the - PARALLEL. */ - int par_index; - int limit; - HOST_WIDE_INT span_offset = offset; - - gcc_assert (GET_CODE (span) == PARALLEL); + span = NULL; + if (REG_P (src)) + span = targetm.dwarf_register_span (src); + if (!span) + queue_reg_save (src, NULL_RTX, offset); + else + { + /* We have a PARALLEL describing where the contents of SRC live. + Queue register saves for each piece of the PARALLEL. */ + int par_index; + int limit; + HOST_WIDE_INT span_offset = offset; - limit = XVECLEN (span, 0); - for (par_index = 0; par_index < limit; par_index++) - { - rtx elem = XVECEXP (span, 0, par_index); + gcc_assert (GET_CODE (span) == PARALLEL); - queue_reg_save (elem, NULL_RTX, span_offset); - span_offset += GET_MODE_SIZE (GET_MODE (elem)); - } - } - } + limit = XVECLEN (span, 0); + for (par_index = 0; par_index < limit; par_index++) + { + rtx elem = XVECEXP (span, 0, par_index); + queue_reg_save (elem, NULL_RTX, span_offset); + span_offset += GET_MODE_SIZE (GET_MODE (elem)); + } + } break; default: @@ -2543,6 +2485,67 @@ dwarf2out_frame_debug_restore_state (void) cfa_remember.in_use = 0; } +/* Record the initial position of the return address. RTL is + INCOMING_RETURN_ADDR_RTX. */ + +static void +initial_return_save (rtx rtl) +{ + unsigned int reg = INVALID_REGNUM; + HOST_WIDE_INT offset = 0; + + switch (GET_CODE (rtl)) + { + case REG: + /* RA is in a register. */ + reg = DWARF_FRAME_REGNUM (REGNO (rtl)); + break; + + case MEM: + /* RA is on the stack. */ + rtl = XEXP (rtl, 0); + switch (GET_CODE (rtl)) + { + case REG: + gcc_assert (REGNO (rtl) == STACK_POINTER_REGNUM); + offset = 0; + break; + + case PLUS: + gcc_assert (REGNO (XEXP (rtl, 0)) == STACK_POINTER_REGNUM); + offset = INTVAL (XEXP (rtl, 1)); + break; + + case MINUS: + gcc_assert (REGNO (XEXP (rtl, 0)) == STACK_POINTER_REGNUM); + offset = -INTVAL (XEXP (rtl, 1)); + break; + + default: + gcc_unreachable (); + } + + break; + + case PLUS: + /* The return address is at some offset from any value we can + actually load. For instance, on the SPARC it is in %i7+8. Just + ignore the offset for now; it doesn't matter for unwinding frames. */ + gcc_assert (CONST_INT_P (XEXP (rtl, 1))); + initial_return_save (XEXP (rtl, 0)); + return; + + default: + gcc_unreachable (); + } + + if (reg != DWARF_FRAME_RETURN_COLUMN) + { + if (reg != INVALID_REGNUM) + record_reg_saved_in_reg (rtl, pc_rtx); + reg_save (DWARF_FRAME_RETURN_COLUMN, reg, offset - cfa.offset); + } +} /* Annotate the function with NOTE_INSN_CFI notes to record the CFI state at each location within the function. These notes will be @@ -2569,7 +2572,31 @@ execute_dwarf2_frame (void) if (targetm.debug_unwind_info () == UI_DWARF2 || targetm_common.except_unwind_info (&global_options) == UI_DWARF2) - initial_return_save (INCOMING_RETURN_ADDR_RTX); + { + initial_return_save (INCOMING_RETURN_ADDR_RTX); + + /* For a few targets, we have the return address incoming into a + register, but choose a different return column. This will result + in a DW_CFA_register for the return, and an entry in + regs_saved_in_regs to match. If the target later stores that + return address register to the stack, we want to be able to emit + the DW_CFA_offset against the return column, not the intermediate + save register. Save the contents of regs_saved_in_regs so that + we can re-initialize it at the start of each function. */ + switch (VEC_length (reg_saved_in_data, regs_saved_in_regs)) + { + case 0: + break; + case 1: + cie_return_save = ggc_alloc_reg_saved_in_data (); + *cie_return_save = *VEC_index (reg_saved_in_data, + regs_saved_in_regs, 0); + regs_saved_in_regs = NULL; + break; + default: + gcc_unreachable (); + } + } add_cfi_vec = NULL; } @@ -2588,6 +2615,9 @@ execute_dwarf2_frame (void) memset (&cfa_temp, 0, sizeof(cfa_temp)); cfa_temp.reg = INVALID_REGNUM; + if (cie_return_save) + VEC_safe_push (reg_saved_in_data, gc, regs_saved_in_regs, cie_return_save); + dwarf2out_alloc_current_fde (); /* Do the work. */ -- 2.30.2