diff options
-rw-r--r-- | gcc/ChangeLog | 18 | ||||
-rw-r--r-- | gcc/doc/tm.texi | 15 | ||||
-rw-r--r-- | gcc/dwarf2out.c | 126 | ||||
-rw-r--r-- | gcc/function.c | 13 | ||||
-rw-r--r-- | gcc/unwind-dw2.c | 4 | ||||
-rw-r--r-- | gcc/var-tracking.c | 5 |
6 files changed, 129 insertions, 52 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 21a7e5d30a9..ca612fb0fe6 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,21 @@ +2005-11-17 Richard Henderson <rth@redhat.com> + + * dwarf2out.c (dw_cfi_oprnd_struct): Reduce dw_cfi_reg_num to int. + (lookup_cfa_1): Apply data alignment to DW_CFA_def_cfa_offset_sf + and DW_CFA_def_cfa_sf. + (def_cfa_1): Use DW_CFA_def_cfa_offset_sf with negative values. + (dbx_reg_number): Don't assert particular registers here. + (based_loc_descr): ... do it here instead. Fold in ... + (eliminate_reg_to_offset): ... this function. + (compute_frame_pointer_to_cfa_displacement): Fold in the effects + of eliminate_reg_to_offset; use FRAME_POINTER_CFA_OFFSET. + * unwind-dw2.c (execute_cfa_program): Apply data align factor + to DW_CFA_def_cfa_offset_sf and DW_CFA_def_cfa_sf. + * function.c (instantiate_new_reg): Use FRAME_POINTER_CFA_OFFSET. + (instantiate_virtual_regs): Likewise. + * var-tracking.c (adjust_stack_reference): Likewise. + * doc/tm.texi (FRAME_POINTER_CFA_OFFSET): New. + 2005-11-17 Bernd Schmidt <bernd.schmidt@analog.com> * config/bfin/elf.h (STARTFILE_SPEC): Add "crtlibid%O%s" diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index b339c4ccdc0..b229ee823dd 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -2926,6 +2926,21 @@ want to support call frame debugging information like that provided by DWARF 2. @end defmac +@defmac FRAME_POINTER_CFA_OFFSET (@var{fundecl}) +If defined, a C expression whose value is an integer giving the offset +in bytes from the frame pointer to the canonical frame address (cfa). +The final value should conincide with that calculated by +@code{INCOMING_FRAME_SP_OFFSET}. + +Normally the CFA is calculated as an offset from the argument pointer, +via @code{ARG_POINTER_CFA_OFFSET}, but if the argument pointer is +variable due to the ABI, this may not be possible. If this macro is +defined, it imples that the virtual register instantiation should be +based on the frame pointer instead of the argument pointer. Only one +of @code{FRAME_POINTER_CFA_OFFSET} and @code{ARG_POINTER_CFA_OFFSET} +should be defined. +@end defmac + @node Exception Handling @subsection Exception Handling Support @cindex exception handling diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index f7a006e8980..60a7d558084 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -214,7 +214,7 @@ enum dw_cfi_oprnd_type { typedef union dw_cfi_oprnd_struct GTY(()) { - unsigned long GTY ((tag ("dw_cfi_oprnd_reg_num"))) dw_cfi_reg_num; + unsigned int GTY ((tag ("dw_cfi_oprnd_reg_num"))) dw_cfi_reg_num; HOST_WIDE_INT GTY ((tag ("dw_cfi_oprnd_offset"))) dw_cfi_offset; const char * GTY ((tag ("dw_cfi_oprnd_addr"))) dw_cfi_addr; struct dw_loc_descr_struct * GTY ((tag ("dw_cfi_oprnd_loc"))) dw_cfi_loc; @@ -671,6 +671,10 @@ lookup_cfa_1 (dw_cfi_ref cfi, dw_cfa_location *loc) case DW_CFA_def_cfa_offset: loc->offset = cfi->dw_cfi_oprnd1.dw_cfi_offset; break; + case DW_CFA_def_cfa_offset_sf: + loc->offset + = cfi->dw_cfi_oprnd1.dw_cfi_offset * DWARF_CIE_DATA_ALIGNMENT; + break; case DW_CFA_def_cfa_register: loc->reg = cfi->dw_cfi_oprnd1.dw_cfi_reg_num; break; @@ -678,6 +682,11 @@ lookup_cfa_1 (dw_cfi_ref cfi, dw_cfa_location *loc) loc->reg = cfi->dw_cfi_oprnd1.dw_cfi_reg_num; loc->offset = cfi->dw_cfi_oprnd2.dw_cfi_offset; break; + case DW_CFA_def_cfa_sf: + loc->reg = cfi->dw_cfi_oprnd1.dw_cfi_reg_num; + loc->offset + = cfi->dw_cfi_oprnd2.dw_cfi_offset * DWARF_CIE_DATA_ALIGNMENT; + break; case DW_CFA_def_cfa_expression: get_cfa_from_loc_descr (loc, cfi->dw_cfi_oprnd1.dw_cfi_loc); break; @@ -775,11 +784,21 @@ def_cfa_1 (const char *label, dw_cfa_location *loc_p) if (loc.reg == old_cfa.reg && !loc.indirect) { - /* Construct a "DW_CFA_def_cfa_offset <offset>" instruction, - indicating the CFA register did not change but the offset - did. */ - cfi->dw_cfi_opc = DW_CFA_def_cfa_offset; - cfi->dw_cfi_oprnd1.dw_cfi_offset = loc.offset; + /* Construct a "DW_CFA_def_cfa_offset <offset>" instruction, indicating + the CFA register did not change but the offset did. */ + if (loc.offset < 0) + { + HOST_WIDE_INT f_offset = loc.offset / DWARF_CIE_DATA_ALIGNMENT; + gcc_assert (f_offset * DWARF_CIE_DATA_ALIGNMENT == loc.offset); + + cfi->dw_cfi_opc = DW_CFA_def_cfa_offset_sf; + cfi->dw_cfi_oprnd1.dw_cfi_offset = f_offset; + } + else + { + cfi->dw_cfi_opc = DW_CFA_def_cfa_offset; + cfi->dw_cfi_oprnd1.dw_cfi_offset = loc.offset; + } } #ifndef MIPS_DEBUGGING_INFO /* SGI dbx thinks this means no offset. */ @@ -800,9 +819,21 @@ def_cfa_1 (const char *label, dw_cfa_location *loc_p) /* Construct a "DW_CFA_def_cfa <register> <offset>" instruction, indicating the CFA register has changed to <register> with the specified offset. */ - cfi->dw_cfi_opc = DW_CFA_def_cfa; - cfi->dw_cfi_oprnd1.dw_cfi_reg_num = loc.reg; - cfi->dw_cfi_oprnd2.dw_cfi_offset = loc.offset; + if (loc.offset < 0) + { + HOST_WIDE_INT f_offset = loc.offset / DWARF_CIE_DATA_ALIGNMENT; + gcc_assert (f_offset * DWARF_CIE_DATA_ALIGNMENT == loc.offset); + + cfi->dw_cfi_opc = DW_CFA_def_cfa_sf; + cfi->dw_cfi_oprnd1.dw_cfi_reg_num = loc.reg; + cfi->dw_cfi_oprnd2.dw_cfi_offset = f_offset; + } + else + { + cfi->dw_cfi_opc = DW_CFA_def_cfa; + cfi->dw_cfi_oprnd1.dw_cfi_reg_num = loc.reg; + cfi->dw_cfi_oprnd2.dw_cfi_offset = loc.offset; + } } else { @@ -8460,12 +8491,6 @@ dbx_reg_number (rtx rtl) { unsigned regno = REGNO (rtl); - /* We do not want to see registers that should have been eliminated. */ - gcc_assert (HARD_FRAME_POINTER_REGNUM == ARG_POINTER_REGNUM - || rtl != arg_pointer_rtx); - gcc_assert (HARD_FRAME_POINTER_REGNUM == FRAME_POINTER_REGNUM - || rtl != frame_pointer_rtx); - gcc_assert (regno < FIRST_PSEUDO_REGISTER); #ifdef LEAF_REG_REMAP @@ -8619,32 +8644,12 @@ int_loc_descriptor (HOST_WIDE_INT i) return new_loc_descr (op, i, 0); } -/* Return an offset from an eliminable register to the post-prologue - frame pointer. */ - -static HOST_WIDE_INT -eliminate_reg_to_offset (rtx reg) -{ - HOST_WIDE_INT offset = 0; - - reg = eliminate_regs (reg, VOIDmode, NULL_RTX); - if (GET_CODE (reg) == PLUS) - { - offset = INTVAL (XEXP (reg, 1)); - reg = XEXP (reg, 0); - } - gcc_assert (reg == (frame_pointer_needed ? hard_frame_pointer_rtx - : stack_pointer_rtx)); - - return offset; -} - /* Return a location descriptor that designates a base+offset location. */ static dw_loc_descr_ref based_loc_descr (rtx reg, HOST_WIDE_INT offset) { - dw_loc_descr_ref loc_result; + unsigned int regno; /* We only use "frame base" when we're sure we're talking about the post-prologue local stack frame. We do this by *not* running @@ -8652,22 +8657,28 @@ based_loc_descr (rtx reg, HOST_WIDE_INT offset) argument pointer and soft frame pointer rtx's. */ if (reg == arg_pointer_rtx || reg == frame_pointer_rtx) { - offset += eliminate_reg_to_offset (reg); - offset += frame_pointer_cfa_offset; + rtx elim = eliminate_regs (reg, VOIDmode, NULL_RTX); - loc_result = new_loc_descr (DW_OP_fbreg, offset, 0); - } - else - { - unsigned int regno = dbx_reg_number (reg); + if (elim != reg) + { + if (GET_CODE (elim) == PLUS) + { + offset += INTVAL (XEXP (elim, 1)); + elim = XEXP (elim, 0); + } + gcc_assert (elim == (frame_pointer_needed ? hard_frame_pointer_rtx + : stack_pointer_rtx)); + offset += frame_pointer_cfa_offset; - if (regno <= 31) - loc_result = new_loc_descr (DW_OP_breg0 + regno, offset, 0); - else - loc_result = new_loc_descr (DW_OP_bregx, regno, offset); + return new_loc_descr (DW_OP_fbreg, offset, 0); + } } - return loc_result; + regno = dbx_reg_number (reg); + if (regno <= 31) + return new_loc_descr (DW_OP_breg0 + regno, offset, 0); + else + return new_loc_descr (DW_OP_bregx, regno, offset); } /* Return true if this RTL expression describes a base+offset calculation. */ @@ -10406,9 +10417,24 @@ static void compute_frame_pointer_to_cfa_displacement (void) { HOST_WIDE_INT offset; + rtx reg, elim; + +#ifdef FRAME_POINTER_CFA_OFFSET + reg = frame_pointer_rtx; + offset = FRAME_POINTER_CFA_OFFSET (current_function_decl); +#else + reg = arg_pointer_rtx; + offset = ARG_POINTER_CFA_OFFSET (current_function_decl); +#endif - offset = eliminate_reg_to_offset (arg_pointer_rtx); - offset += ARG_POINTER_CFA_OFFSET (current_function_decl); + elim = eliminate_regs (reg, VOIDmode, NULL_RTX); + if (GET_CODE (elim) == PLUS) + { + offset += INTVAL (XEXP (elim, 1)); + elim = XEXP (elim, 0); + } + gcc_assert (elim == (frame_pointer_needed ? hard_frame_pointer_rtx + : stack_pointer_rtx)); frame_pointer_cfa_offset = -offset; } diff --git a/gcc/function.c b/gcc/function.c index dbf9df74ade..c0339b8950e 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -1246,7 +1246,14 @@ instantiate_new_reg (rtx x, HOST_WIDE_INT *poffset) else if (x == virtual_outgoing_args_rtx) new = stack_pointer_rtx, offset = out_arg_offset; else if (x == virtual_cfa_rtx) - new = arg_pointer_rtx, offset = cfa_offset; + { +#ifdef FRAME_POINTER_CFA_OFFSET + new = frame_pointer_rtx; +#else + new = arg_pointer_rtx; +#endif + offset = cfa_offset; + } else return NULL_RTX; @@ -1632,7 +1639,11 @@ instantiate_virtual_regs (void) var_offset = STARTING_FRAME_OFFSET; dynamic_offset = STACK_DYNAMIC_OFFSET (current_function_decl); out_arg_offset = STACK_POINTER_OFFSET; +#ifdef FRAME_POINTER_CFA_OFFSET + cfa_offset = FRAME_POINTER_CFA_OFFSET (current_function_decl); +#else cfa_offset = ARG_POINTER_CFA_OFFSET (current_function_decl); +#endif /* Initialize recognition, indicating that volatile is OK. */ init_recog (); diff --git a/gcc/unwind-dw2.c b/gcc/unwind-dw2.c index 4626ec6d84c..930f02f3799 100644 --- a/gcc/unwind-dw2.c +++ b/gcc/unwind-dw2.c @@ -902,7 +902,7 @@ execute_cfa_program (const unsigned char *insn_ptr, insn_ptr += utmp; break; - /* From the 2.1 draft. */ + /* From the dwarf3 draft. */ case DW_CFA_offset_extended_sf: insn_ptr = read_uleb128 (insn_ptr, ®); insn_ptr = read_sleb128 (insn_ptr, &stmp); @@ -916,10 +916,12 @@ execute_cfa_program (const unsigned char *insn_ptr, insn_ptr = read_uleb128 (insn_ptr, &fs->cfa_reg); insn_ptr = read_sleb128 (insn_ptr, &fs->cfa_offset); fs->cfa_how = CFA_REG_OFFSET; + fs->cfa_offset *= fs->data_align; break; case DW_CFA_def_cfa_offset_sf: insn_ptr = read_sleb128 (insn_ptr, &fs->cfa_offset); + fs->cfa_offset *= fs->data_align; /* cfa_how deliberately not set. */ break; diff --git a/gcc/var-tracking.c b/gcc/var-tracking.c index d69ca139c42..fb4a1813218 100644 --- a/gcc/var-tracking.c +++ b/gcc/var-tracking.c @@ -557,8 +557,13 @@ adjust_stack_reference (rtx mem, HOST_WIDE_INT adjustment) { rtx addr, cfa, tmp; +#ifdef FRAME_POINTER_CFA_OFFSET + adjustment -= FRAME_POINTER_CFA_OFFSET (current_function_decl); + cfa = plus_constant (frame_pointer_rtx, adjustment); +#else adjustment -= ARG_POINTER_CFA_OFFSET (current_function_decl); cfa = plus_constant (arg_pointer_rtx, adjustment); +#endif addr = replace_rtx (copy_rtx (XEXP (mem, 0)), stack_pointer_rtx, cfa); tmp = simplify_rtx (addr); |