summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog18
-rw-r--r--gcc/doc/tm.texi15
-rw-r--r--gcc/dwarf2out.c126
-rw-r--r--gcc/function.c13
-rw-r--r--gcc/unwind-dw2.c4
-rw-r--r--gcc/var-tracking.c5
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, &reg);
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);