diff options
author | Geoffrey Keating <geoffk@apple.com> | 2004-07-01 04:09:07 +0000 |
---|---|---|
committer | Geoffrey Keating <geoffk@gcc.gnu.org> | 2004-07-01 04:09:07 +0000 |
commit | f8a57be8182804460dde7e7f28a681e26577fdae (patch) | |
tree | c06b7ba921908103e7b86d67bed62ad6003088e2 /gcc/dwarf2out.c | |
parent | ec6376abd7f23e0993138ed92c56552eea9cd5a2 (diff) | |
download | gcc-f8a57be8182804460dde7e7f28a681e26577fdae.zip gcc-f8a57be8182804460dde7e7f28a681e26577fdae.tar.gz gcc-f8a57be8182804460dde7e7f28a681e26577fdae.tar.bz2 |
Index: gcc/ChangeLog
2004-06-28 Geoffrey Keating <geoffk@apple.com>
Andreas Tobler <a.tobler@schweiz.ch>
PR 15813
* dwarf2out.c (reg_save): Output DW_CFA_same_value when a
register is saved in itself.
(initial_return_save): If the return address is a register,
it's already there, don't bother to mention it in the CFI.
(struct queued_reg_save): Add field saved_reg.
(struct reg_saved_in_data): New.
(regs_saved_in_regs): New.
(num_regs_saved_in_regs): New.
(queue_reg_save): Add extra parameter to specify register saved
in register. Remove duplicate entries from queue. Add comment
for function.
(flush_queued_reg_saves): Handle registers saved in registers.
Update regs_saved_in_regs. Add comment for function.
(clobbers_queued_reg_save): Add comment for function. Allow
for regs_saved_in_regs.
(reg_saved_in): New.
(dwarf2out_frame_debug_expr): Handle saving registers in other
registers.
(dwarf2out_frame_debug): Reset regs_saved_in_regs.
* unwind-dw2.c (execute_cfa_program): Correct handling of
DW_CFA_same_value. Add FIXME comment about incorrect implementation
of DW_CFA_restore_extended.
* config/rs6000/rs6000.c (rs6000_emit_prologue): Let
dwarf2out_frame_debug_expr see instructions that save registers
in other registers or save those other registers in memory.
* unwind-dw2.c (DWARF_FRAME_REGISTERS): Move to unwind-dw2.h.
(_Unwind_FrameState): Likewise.
* unwind-dw2.h: New.
* Makefile.in (LIB2ADDEHDEP): Add unwind-dw2.h.
* config/rs6000/darwin-fallback.c: New file.
* config/rs6000/darwin.h (MD_FALLBACK_FRAME_STATE_FOR): Define.
* config/rs6000/t-darwin (LIB2FUNCS_EXTRA): Add darwin-fallback.o.
Index: gcc/testsuite/ChangeLog
2004-06-26 Geoffrey Keating <geoffk@apple.com>
Andreas Tobler <a.tobler@schweiz.ch>
* gcc.dg/cleanup-10.c: Run on all Linux platforms and powerpc-darwin.
Use SA_RESETHAND rather than SA_ONESHOT. Trap SIGBUS as well
as SIGSEGV.
* gcc.dg/cleanup-11.c: Likewise.
* gcc.dg/cleanup-8.c: Likewise.
* gcc.dg/cleanup-9.c: Likewise.
* gcc.dg/cleanup-5.c: Run on all platforms.
Index: libjava/ChangeLog
2004-06-26 Geoffrey Keating <geoffk@apple.com>
Andreas Tobler <a.tobler@schweiz.ch>
* configure.host (powerpc-*-darwin*): New case, define
can_unwind_signal.
* configure.in (*-*-darwin*): New case, point to darwin-signal.h.
* configure: Regenerate.
* include/darwin-signal.h: New.
Co-Authored-By: Andreas Tobler <a.tobler@schweiz.ch>
From-SVN: r83953
Diffstat (limited to 'gcc/dwarf2out.c')
-rw-r--r-- | gcc/dwarf2out.c | 172 |
1 files changed, 141 insertions, 31 deletions
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index 17b4c20..8549c7d 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -359,7 +359,6 @@ static HOST_WIDE_INT stack_adjust_offset (rtx); static void output_cfi (dw_cfi_ref, dw_fde_ref, int); static void output_call_frame_info (int); static void dwarf2out_stack_adjust (rtx); -static void queue_reg_save (const char *, rtx, HOST_WIDE_INT); static void flush_queued_reg_saves (void); static bool clobbers_queued_reg_save (rtx); static void dwarf2out_frame_debug_expr (rtx, const char *); @@ -843,8 +842,7 @@ reg_save (const char *label, unsigned int reg, unsigned int sreg, HOST_WIDE_INT cfi->dw_cfi_oprnd2.dw_cfi_offset = offset; } else if (sreg == reg) - /* We could emit a DW_CFA_same_value in this case, but don't bother. */ - return; + cfi->dw_cfi_opc = DW_CFA_same_value; else { cfi->dw_cfi_opc = DW_CFA_register; @@ -974,7 +972,8 @@ initial_return_save (rtx rtl) abort (); } - reg_save (NULL, DWARF_FRAME_RETURN_COLUMN, reg, offset - cfa.offset); + if (reg != DWARF_FRAME_RETURN_COLUMN) + reg_save (NULL, DWARF_FRAME_RETURN_COLUMN, reg, offset - cfa.offset); } /* Given a SET, calculate the amount of stack adjustment it @@ -1144,53 +1143,134 @@ struct queued_reg_save GTY(()) struct queued_reg_save *next; rtx reg; HOST_WIDE_INT cfa_offset; + rtx saved_reg; }; static GTY(()) struct queued_reg_save *queued_reg_saves; +/* The caller's ORIG_REG is saved in SAVED_IN_REG. */ +struct reg_saved_in_data GTY(()) { + rtx orig_reg; + rtx saved_in_reg; +}; + +/* A list of registers saved in other registers. + The list intentionally has a small maximum capacity of 4; if your + port needs more than that, you might consider implementing a + more efficient data structure. */ +static GTY(()) struct reg_saved_in_data regs_saved_in_regs[4]; +static GTY(()) size_t num_regs_saved_in_regs; + #if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO) static const char *last_reg_save_label; +/* Add an entry to QUEUED_REG_SAVES saying that REG is now saved at + SREG, or if SREG is NULL then it is saved at OFFSET to the CFA. */ + static void -queue_reg_save (const char *label, rtx reg, HOST_WIDE_INT offset) +queue_reg_save (const char *label, rtx reg, rtx sreg, HOST_WIDE_INT offset) { - struct queued_reg_save *q = ggc_alloc (sizeof (*q)); + 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 (q = queued_reg_saves; q != NULL; q = q->next) + if (REGNO (q->reg) == REGNO (reg)) + break; + + if (q == NULL) + { + q = ggc_alloc (sizeof (*q)); + q->next = queued_reg_saves; + queued_reg_saves = q; + } - q->next = queued_reg_saves; q->reg = reg; q->cfa_offset = offset; - queued_reg_saves = q; + q->saved_reg = sreg; last_reg_save_label = label; } +/* Output all the entries in QUEUED_REG_SAVES. */ + static void flush_queued_reg_saves (void) { - struct queued_reg_save *q, *next; + struct queued_reg_save *q; - for (q = queued_reg_saves; q; q = next) + for (q = queued_reg_saves; q; q = q->next) { - dwarf2out_reg_save (last_reg_save_label, REGNO (q->reg), q->cfa_offset); - next = q->next; + size_t i; + for (i = 0; i < num_regs_saved_in_regs; i++) + if (REGNO (regs_saved_in_regs[i].orig_reg) == REGNO (q->reg)) + break; + if (q->saved_reg && i == num_regs_saved_in_regs) + { + if (i == ARRAY_SIZE (regs_saved_in_regs)) + abort (); + num_regs_saved_in_regs++; + } + if (i != num_regs_saved_in_regs) + { + regs_saved_in_regs[i].orig_reg = q->reg; + regs_saved_in_regs[i].saved_in_reg = q->saved_reg; + } + + reg_save (last_reg_save_label, REGNO (q->reg), + q->saved_reg ? REGNO (q->saved_reg) : -1U, q->cfa_offset); } queued_reg_saves = NULL; last_reg_save_label = NULL; } +/* Does INSN clobber any register which QUEUED_REG_SAVES lists a saved + location for? Or, does it clobber a register which we've previously + said that some other register is saved in, and for which we now + have a new location for? */ + static bool clobbers_queued_reg_save (rtx insn) { struct queued_reg_save *q; for (q = queued_reg_saves; q; q = q->next) - if (modified_in_p (q->reg, insn)) - return true; + { + size_t i; + if (modified_in_p (q->reg, insn)) + return true; + for (i = 0; i < num_regs_saved_in_regs; i++) + if (REGNO (q->reg) == REGNO (regs_saved_in_regs[i].orig_reg) + && modified_in_p (regs_saved_in_regs[i].saved_in_reg, insn)) + return true; + } return false; } +/* What register, if any, is currently saved in REG? */ + +static rtx +reg_saved_in (rtx reg) +{ + unsigned int regn = REGNO (reg); + size_t i; + struct queued_reg_save *q; + + for (q = queued_reg_saves; q; q = q->next) + if (q->saved_reg && regn == REGNO (q->saved_reg)) + return q->reg; + + for (i = 0; i < num_regs_saved_in_regs; i++) + if (regs_saved_in_regs[i].saved_in_reg + && regn == REGNO (regs_saved_in_regs[i].saved_in_reg)) + return regs_saved_in_regs[i].orig_reg; + + return NULL_RTX; +} + /* A temporary register holding an integral value used in adjusting SP or setting up the store_reg. The "offset" field holds the integer @@ -1199,8 +1279,8 @@ static dw_cfa_location cfa_temp; /* Record call frame debugging information for an expression EXPR, which either sets SP or FP (adjusting how we calculate the frame - address) or saves a register to the stack. LABEL indicates the - address of EXPR. + address) or saves a register to the stack or another register. + LABEL indicates the address of EXPR. This function encodes a state machine mapping rtxes to actions on cfa, cfa_store, and cfa_temp.reg. We describe these rules so @@ -1224,12 +1304,20 @@ static dw_cfa_location cfa_temp; RTX_FRAME_RELATED_P is set on an insn which modifies memory, it's a register save, and the register used to calculate the destination had better be the one we think we're using for this purpose. + It's also assumed that a copy from a call-saved register to another + register is saving that register if RTX_FRAME_RELATED_P is set on + that instruction. If the copy is from a call-saved register to + the *same* register, that means that the register is now the same + value as in the caller. Except: If the register being saved is the CFA register, and the offset is nonzero, we are saving the CFA, so we assume we have to use DW_CFA_def_cfa_expression. If the offset is 0, we assume that the intent is to save the value of SP from the previous frame. + In addition, if a register has previously been saved to a different + register, + Invariants / Summaries of Rules cfa current rule for calculating the CFA. It usually @@ -1380,29 +1468,42 @@ dwarf2out_frame_debug_expr (rtx expr, const char *label) src = SET_SRC (expr); dest = SET_DEST (expr); + if (GET_CODE (src) == REG) + { + rtx rsi = reg_saved_in (src); + if (rsi) + src = rsi; + } + switch (GET_CODE (dest)) { case REG: - /* Rule 1 */ - /* Update the CFA rule wrt SP or FP. Make sure src is - relative to the current CFA register. */ switch (GET_CODE (src)) { /* Setting FP from SP. */ case REG: if (cfa.reg == (unsigned) REGNO (src)) - /* OK. */ - ; + { + /* Rule 1 */ + /* Update the CFA rule wrt SP or FP. Make sure src is + relative to the current CFA register. + + We used to require that dest be either SP or FP, but the + ARM copies SP to a temporary register, and from there to + FP. So we just rely on the backends to only set + RTX_FRAME_RELATED_P on appropriate insns. */ + cfa.reg = REGNO (dest); + cfa_temp.reg = cfa.reg; + cfa_temp.offset = cfa.offset; + } + else if (call_used_regs [REGNO (dest)] + && ! fixed_regs [REGNO (dest)]) + { + /* Saving a register in a register. */ + queue_reg_save (label, src, dest, 0); + } else abort (); - - /* We used to require that dest be either SP or FP, but the - ARM copies SP to a temporary register, and from there to - FP. So we just rely on the backends to only set - RTX_FRAME_RELATED_P on appropriate insns. */ - cfa.reg = REGNO (dest); - cfa_temp.reg = cfa.reg; - cfa_temp.offset = cfa.offset; break; case PLUS: @@ -1642,7 +1743,7 @@ dwarf2out_frame_debug_expr (rtx expr, const char *label) we're saving SP like any other register; this happens on the ARM. */ def_cfa_1 (label, &cfa); - queue_reg_save (label, stack_pointer_rtx, offset); + queue_reg_save (label, stack_pointer_rtx, NULL_RTX, offset); break; } else @@ -1665,7 +1766,7 @@ dwarf2out_frame_debug_expr (rtx expr, const char *label) } def_cfa_1 (label, &cfa); - queue_reg_save (label, src, offset); + queue_reg_save (label, src, NULL_RTX, offset); break; default: @@ -1685,6 +1786,8 @@ dwarf2out_frame_debug (rtx insn) if (insn == NULL_RTX) { + size_t i; + /* Flush any queued register saves. */ flush_queued_reg_saves (); @@ -1697,6 +1800,13 @@ dwarf2out_frame_debug (rtx insn) cfa_store = cfa; cfa_temp.reg = -1; cfa_temp.offset = 0; + + for (i = 0; i < num_regs_saved_in_regs; i++) + { + regs_saved_in_regs[i].orig_reg = NULL_RTX; + regs_saved_in_regs[i].saved_in_reg = NULL_RTX; + } + num_regs_saved_in_regs = 0; return; } |