Implement dwarf2 exception handling for the ARM.
* config/arm/arm.h (INCOMING_RETURN_ADDR_RTX): Define. (DWARF_FRAME_RETURN_COLUMN): Define. * config/arm/arm.c (emit_multi_reg_push): Return rtx. Attach REG_FRAME_RELATED_EXPR note. (emit_sfm): Likewise. (arm_expand_prologue): Set RTX_FRAME_RELATED_P on everything. * dwarf2out.c (reg_save): Handle saving a register to itself. (dwarf2out_frame_debug_expr): Handle an intermediate cfa reg. * except.c (eh_regs): Don't use the static chain reg if it's callee-saved. * frame.h (frame_state): Add cfa_saved field. * frame.c (execute_cfa_insn): Set it. * libgcc2.c (throw_helper): Don't adjust sp if it's restored in the epilogue. * function.c (ARG_POINTER_CFA_OFFSET): Default to FIRST_PARM_OFFSET. Now takes a parm. (instantiate_virtual_regs): Adjust. * tm.texi: Adjust. * config/m68k/m68k.h (ARG_POINTER_CFA_OFFSET): Don't define. * config/ns32k/ns32k.h (ARG_POINTER_CFA_OFFSET): Don't define. * config/sparc/sparc.h (ARG_POINTER_CFA_OFFSET): Take a parm. * dwarf2out.c (reg_number): Refer to FIRST_PSEUDO_REGISTER. (initial_return_save): Use DWARF_FRAME_REGNUM, not reg_number. From-SVN: r32696
This commit is contained in:
parent
cb1072f450
commit
2c84914526
|
@ -1,3 +1,36 @@
|
|||
2000-03-22 Jason Merrill <jason@casey.cygnus.com>
|
||||
|
||||
* config/rs6000/rs6000.h (DWARF_FRAME_RETURN_COLUMN): Define.
|
||||
* config/alpha/alpha.h (DWARF_FRAME_RETURN_COLUMN): Define.
|
||||
* config/sparc/sparc.h (DWARF_FRAME_RETURN_COLUMN): Define.
|
||||
* dwarf2out.c (throw_helper): Adjust.
|
||||
|
||||
Implement dwarf2 exception handling for the ARM.
|
||||
* config/arm/arm.h (INCOMING_RETURN_ADDR_RTX): Define.
|
||||
(DWARF_FRAME_RETURN_COLUMN): Define.
|
||||
* config/arm/arm.c (emit_multi_reg_push): Return rtx. Attach
|
||||
REG_FRAME_RELATED_EXPR note.
|
||||
(emit_sfm): Likewise.
|
||||
(arm_expand_prologue): Set RTX_FRAME_RELATED_P on everything.
|
||||
* dwarf2out.c (reg_save): Handle saving a register to itself.
|
||||
(dwarf2out_frame_debug_expr): Handle an intermediate cfa reg.
|
||||
* except.c (eh_regs): Don't use the static chain reg if it's
|
||||
callee-saved.
|
||||
* frame.h (frame_state): Add cfa_saved field.
|
||||
* frame.c (execute_cfa_insn): Set it.
|
||||
* libgcc2.c (throw_helper): Don't adjust sp if it's restored in
|
||||
the epilogue.
|
||||
* function.c (ARG_POINTER_CFA_OFFSET): Default to FIRST_PARM_OFFSET.
|
||||
Now takes a parm.
|
||||
(instantiate_virtual_regs): Adjust.
|
||||
* tm.texi: Adjust.
|
||||
* config/m68k/m68k.h (ARG_POINTER_CFA_OFFSET): Don't define.
|
||||
* config/ns32k/ns32k.h (ARG_POINTER_CFA_OFFSET): Don't define.
|
||||
* config/sparc/sparc.h (ARG_POINTER_CFA_OFFSET): Take a parm.
|
||||
|
||||
* dwarf2out.c (reg_number): Refer to FIRST_PSEUDO_REGISTER.
|
||||
(initial_return_save): Use DWARF_FRAME_REGNUM, not reg_number.
|
||||
|
||||
2000-03-22 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
|
||||
|
||||
* builtins.def: New file.
|
||||
|
|
|
@ -64,8 +64,8 @@ static int eliminate_lr2ip PARAMS ((rtx *));
|
|||
static char * shift_op PARAMS ((rtx, HOST_WIDE_INT *));
|
||||
static int pattern_really_clobbers_lr PARAMS ((rtx));
|
||||
static int function_really_clobbers_lr PARAMS ((rtx));
|
||||
static void emit_multi_reg_push PARAMS ((int));
|
||||
static void emit_sfm PARAMS ((int, int));
|
||||
static rtx emit_multi_reg_push PARAMS ((int));
|
||||
static rtx emit_sfm PARAMS ((int, int));
|
||||
static enum arm_cond_code get_arm_condition_code PARAMS ((rtx));
|
||||
static int const_ok_for_op PARAMS ((HOST_WIDE_INT, enum rtx_code));
|
||||
static void arm_add_gc_roots PARAMS ((void));
|
||||
|
@ -6268,13 +6268,20 @@ output_func_epilogue (frame_size)
|
|||
after_arm_reorg = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
/* Generate and emit an insn that we will recognize as a push_multi.
|
||||
Unfortunately, since this insn does not reflect very well the actual
|
||||
semantics of the operation, we need to annotate the insn for the benefit
|
||||
of DWARF2 frame unwind information. */
|
||||
|
||||
static rtx
|
||||
emit_multi_reg_push (mask)
|
||||
int mask;
|
||||
{
|
||||
int num_regs = 0;
|
||||
int i, j;
|
||||
rtx par;
|
||||
rtx dwarf;
|
||||
rtx tmp, reg;
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
if (mask & (1 << i))
|
||||
|
@ -6284,20 +6291,32 @@ emit_multi_reg_push (mask)
|
|||
abort ();
|
||||
|
||||
par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (num_regs));
|
||||
dwarf = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (num_regs));
|
||||
RTX_FRAME_RELATED_P (dwarf) = 1;
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
if (mask & (1 << i))
|
||||
{
|
||||
reg = gen_rtx_REG (SImode, i);
|
||||
|
||||
XVECEXP (par, 0, 0)
|
||||
= gen_rtx_SET (VOIDmode,
|
||||
gen_rtx_MEM (BLKmode,
|
||||
gen_rtx_PRE_DEC (BLKmode,
|
||||
stack_pointer_rtx)),
|
||||
gen_rtx_UNSPEC (BLKmode,
|
||||
gen_rtvec (1,
|
||||
gen_rtx_REG (SImode, i)),
|
||||
gen_rtvec (1, reg),
|
||||
2));
|
||||
|
||||
tmp = gen_rtx_SET (VOIDmode,
|
||||
gen_rtx_MEM (SImode,
|
||||
gen_rtx_PRE_DEC (BLKmode,
|
||||
stack_pointer_rtx)),
|
||||
reg);
|
||||
RTX_FRAME_RELATED_P (tmp) = 1;
|
||||
XVECEXP (dwarf, 0, num_regs - 1) = tmp;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -6306,38 +6325,77 @@ emit_multi_reg_push (mask)
|
|||
{
|
||||
if (mask & (1 << i))
|
||||
{
|
||||
XVECEXP (par, 0, j)
|
||||
= gen_rtx_USE (VOIDmode, gen_rtx_REG (SImode, i));
|
||||
reg = gen_rtx_REG (SImode, i);
|
||||
|
||||
XVECEXP (par, 0, j) = gen_rtx_USE (VOIDmode, reg);
|
||||
|
||||
tmp = gen_rtx_SET (VOIDmode,
|
||||
gen_rtx_MEM (SImode,
|
||||
gen_rtx_PRE_DEC (BLKmode,
|
||||
stack_pointer_rtx)),
|
||||
reg);
|
||||
RTX_FRAME_RELATED_P (tmp) = 1;
|
||||
XVECEXP (dwarf, 0, num_regs - j - 1) = tmp;
|
||||
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
emit_insn (par);
|
||||
par = emit_insn (par);
|
||||
REG_NOTES (par) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf,
|
||||
REG_NOTES (par));
|
||||
return par;
|
||||
}
|
||||
|
||||
static void
|
||||
static rtx
|
||||
emit_sfm (base_reg, count)
|
||||
int base_reg;
|
||||
int count;
|
||||
{
|
||||
rtx par;
|
||||
rtx dwarf;
|
||||
rtx tmp, reg;
|
||||
int i;
|
||||
|
||||
par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count));
|
||||
dwarf = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count));
|
||||
RTX_FRAME_RELATED_P (dwarf) = 1;
|
||||
|
||||
reg = gen_rtx_REG (XFmode, base_reg++);
|
||||
|
||||
XVECEXP (par, 0, 0)
|
||||
= gen_rtx_SET (VOIDmode,
|
||||
gen_rtx_MEM (BLKmode,
|
||||
gen_rtx_PRE_DEC (BLKmode, stack_pointer_rtx)),
|
||||
gen_rtx_UNSPEC (BLKmode,
|
||||
gen_rtvec (1, gen_rtx_REG (XFmode,
|
||||
base_reg++)),
|
||||
gen_rtvec (1, reg),
|
||||
2));
|
||||
tmp
|
||||
= gen_rtx_SET (VOIDmode,
|
||||
gen_rtx_MEM (XFmode,
|
||||
gen_rtx_PRE_DEC (BLKmode, stack_pointer_rtx)),
|
||||
reg);
|
||||
RTX_FRAME_RELATED_P (tmp) = 1;
|
||||
XVECEXP (dwarf, 0, count - 1) = tmp;
|
||||
|
||||
for (i = 1; i < count; i++)
|
||||
XVECEXP (par, 0, i) = gen_rtx_USE (VOIDmode,
|
||||
gen_rtx_REG (XFmode, base_reg++));
|
||||
{
|
||||
reg = gen_rtx_REG (XFmode, base_reg++);
|
||||
XVECEXP (par, 0, i) = gen_rtx_USE (VOIDmode, reg);
|
||||
|
||||
emit_insn (par);
|
||||
tmp = gen_rtx_SET (VOIDmode,
|
||||
gen_rtx_MEM (XFmode,
|
||||
gen_rtx_PRE_DEC (BLKmode,
|
||||
stack_pointer_rtx)),
|
||||
reg);
|
||||
RTX_FRAME_RELATED_P (tmp) = 1;
|
||||
XVECEXP (dwarf, 0, count - i - 1) = tmp;
|
||||
}
|
||||
|
||||
par = emit_insn (par);
|
||||
REG_NOTES (par) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf,
|
||||
REG_NOTES (par));
|
||||
return par;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -6352,6 +6410,7 @@ arm_expand_prologue ()
|
|||
the call-saved regs. */
|
||||
int volatile_func = (optimize > 0
|
||||
&& TREE_THIS_VOLATILE (current_function_decl));
|
||||
rtx insn;
|
||||
|
||||
/* Naked functions don't have prologues. */
|
||||
if (arm_naked_function_p (current_function_decl))
|
||||
|
@ -6376,18 +6435,21 @@ arm_expand_prologue ()
|
|||
if (frame_pointer_needed)
|
||||
{
|
||||
live_regs_mask |= 0xD800;
|
||||
emit_insn (gen_movsi (gen_rtx_REG (SImode, IP_REGNUM),
|
||||
stack_pointer_rtx));
|
||||
insn = emit_insn (gen_movsi (gen_rtx_REG (SImode, IP_REGNUM),
|
||||
stack_pointer_rtx));
|
||||
RTX_FRAME_RELATED_P (insn) = 1;
|
||||
}
|
||||
|
||||
if (current_function_pretend_args_size)
|
||||
{
|
||||
if (store_arg_regs)
|
||||
emit_multi_reg_push ((0xf0 >> (current_function_pretend_args_size / 4))
|
||||
& 0xf);
|
||||
insn = emit_multi_reg_push
|
||||
((0xf0 >> (current_function_pretend_args_size / 4)) & 0xf);
|
||||
else
|
||||
emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
|
||||
GEN_INT (-current_function_pretend_args_size)));
|
||||
insn = emit_insn
|
||||
(gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
|
||||
GEN_INT (-current_function_pretend_args_size)));
|
||||
RTX_FRAME_RELATED_P (insn) = 1;
|
||||
}
|
||||
|
||||
if (live_regs_mask)
|
||||
|
@ -6395,10 +6457,11 @@ arm_expand_prologue ()
|
|||
/* If we have to push any regs, then we must push lr as well, or
|
||||
we won't get a proper return. */
|
||||
live_regs_mask |= 1 << LR_REGNUM;
|
||||
emit_multi_reg_push (live_regs_mask);
|
||||
insn = emit_multi_reg_push (live_regs_mask);
|
||||
RTX_FRAME_RELATED_P (insn) = 1;
|
||||
}
|
||||
|
||||
/* For now the integer regs are still pushed in output_func_epilogue (). */
|
||||
/* And now the floating point regs. */
|
||||
|
||||
if (! volatile_func)
|
||||
{
|
||||
|
@ -6406,12 +6469,13 @@ arm_expand_prologue ()
|
|||
{
|
||||
for (reg = 23; reg > 15; reg--)
|
||||
if (regs_ever_live[reg] && ! call_used_regs[reg])
|
||||
emit_insn (gen_rtx_SET
|
||||
(VOIDmode,
|
||||
gen_rtx_MEM (XFmode,
|
||||
gen_rtx_PRE_DEC (XFmode,
|
||||
stack_pointer_rtx)),
|
||||
gen_rtx_REG (XFmode, reg)));
|
||||
{
|
||||
insn = gen_rtx_PRE_DEC (XFmode, stack_pointer_rtx);
|
||||
insn = gen_rtx_MEM (XFmode, insn);
|
||||
insn = emit_insn (gen_rtx_SET (VOIDmode, insn,
|
||||
gen_rtx_REG (XFmode, reg)));
|
||||
RTX_FRAME_RELATED_P (insn) = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -6423,31 +6487,44 @@ arm_expand_prologue ()
|
|||
{
|
||||
if (start_reg - reg == 3)
|
||||
{
|
||||
emit_sfm (reg, 4);
|
||||
insn = emit_sfm (reg, 4);
|
||||
RTX_FRAME_RELATED_P (insn) = 1;
|
||||
start_reg = reg - 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (start_reg != reg)
|
||||
emit_sfm (reg + 1, start_reg - reg);
|
||||
{
|
||||
insn = emit_sfm (reg + 1, start_reg - reg);
|
||||
RTX_FRAME_RELATED_P (insn) = 1;
|
||||
}
|
||||
start_reg = reg - 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (start_reg != reg)
|
||||
emit_sfm (reg + 1, start_reg - reg);
|
||||
{
|
||||
insn = emit_sfm (reg + 1, start_reg - reg);
|
||||
RTX_FRAME_RELATED_P (insn) = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (frame_pointer_needed)
|
||||
emit_insn (gen_addsi3 (hard_frame_pointer_rtx, gen_rtx_REG (SImode, IP_REGNUM),
|
||||
(GEN_INT
|
||||
(-(4 + current_function_pretend_args_size)))));
|
||||
{
|
||||
insn = GEN_INT (-(4 + current_function_pretend_args_size));
|
||||
insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx,
|
||||
gen_rtx_REG (SImode, IP_REGNUM),
|
||||
insn));
|
||||
RTX_FRAME_RELATED_P (insn) = 1;
|
||||
}
|
||||
|
||||
if (amount != const0_rtx)
|
||||
{
|
||||
emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, amount));
|
||||
insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
|
||||
amount));
|
||||
RTX_FRAME_RELATED_P (insn) = 1;
|
||||
emit_insn (gen_rtx_CLOBBER (VOIDmode,
|
||||
gen_rtx_MEM (BLKmode, stack_pointer_rtx)));
|
||||
}
|
||||
|
|
|
@ -2275,6 +2275,13 @@ extern struct rtx_def * arm_compare_op1;
|
|||
? gen_rtx_MEM (Pmode, plus_constant (FRAME, -4)) \
|
||||
: NULL_RTX)
|
||||
|
||||
/* Pick up the return address upon entry to a procedure. Used for
|
||||
dwarf2 unwind information. This also enables the table driven
|
||||
mechanism. */
|
||||
|
||||
#define INCOMING_RETURN_ADDR_RTX gen_rtx_REG (Pmode, LR_REGNUM)
|
||||
#define DWARF_FRAME_RETURN_COLUMN DWARF_FRAME_REGNUM (LR_REGNUM)
|
||||
|
||||
/* Used to mask out junk bits from the return address, such as
|
||||
processor state, interrupt status, condition codes and the like. */
|
||||
#define MASK_RETURN_ADDR \
|
||||
|
|
|
@ -925,9 +925,6 @@ extern enum reg_class regno_reg_class[];
|
|||
/* Offset of first parameter from the argument pointer register value. */
|
||||
#define FIRST_PARM_OFFSET(FNDECL) 8
|
||||
|
||||
/* Offset of the CFA from the argument pointer register value. */
|
||||
#define ARG_POINTER_CFA_OFFSET 8
|
||||
|
||||
/* Value is the number of byte of arguments automatically
|
||||
popped when returning from a subroutine call.
|
||||
FUNDECL is the declaration node of the function (as a tree),
|
||||
|
|
|
@ -552,9 +552,6 @@ enum reg_class
|
|||
|
||||
#define INCOMING_FRAME_SP_OFFSET 4
|
||||
|
||||
/* Offset of the CFA from the argument pointer register value. */
|
||||
#define ARG_POINTER_CFA_OFFSET 8
|
||||
|
||||
/* If we generate an insn to push BYTES bytes,
|
||||
this says how many the stack pointer really advances by.
|
||||
On the 32000, sp@- in a byte insn really pushes a BYTE. */
|
||||
|
|
|
@ -1603,9 +1603,11 @@ extern char leaf_reg_remap[];
|
|||
(TARGET_ARCH64 ? (SPARC_STACK_BIAS + 16 * UNITS_PER_WORD) \
|
||||
: (STRUCT_VALUE_OFFSET + UNITS_PER_WORD))
|
||||
|
||||
/* Offset from the argument pointer register value to the CFA. */
|
||||
/* Offset from the argument pointer register value to the CFA.
|
||||
This is different from FIRST_PARM_OFFSET because the register window
|
||||
comes between the CFA and the arguments. */
|
||||
|
||||
#define ARG_POINTER_CFA_OFFSET SPARC_STACK_BIAS
|
||||
#define ARG_POINTER_CFA_OFFSET(FNDECL) SPARC_STACK_BIAS
|
||||
|
||||
/* When a parameter is passed in a register, stack space is still
|
||||
allocated for it.
|
||||
|
|
|
@ -559,7 +559,7 @@ reg_number (rtl)
|
|||
{
|
||||
register unsigned regno = REGNO (rtl);
|
||||
|
||||
if (regno >= DWARF_FRAME_REGISTERS)
|
||||
if (regno >= FIRST_PSEUDO_REGISTER)
|
||||
{
|
||||
warning ("internal regno botch: regno = %d\n", regno);
|
||||
regno = 0;
|
||||
|
@ -882,6 +882,9 @@ reg_save (label, reg, sreg, offset)
|
|||
}
|
||||
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;
|
||||
else
|
||||
{
|
||||
cfi->dw_cfi_opc = DW_CFA_register;
|
||||
|
@ -975,7 +978,7 @@ initial_return_save (rtl)
|
|||
{
|
||||
case REG:
|
||||
/* RA is in a register. */
|
||||
reg = reg_number (rtl);
|
||||
reg = DWARF_FRAME_REGNUM (REGNO (rtl));
|
||||
break;
|
||||
case MEM:
|
||||
/* RA is on the stack. */
|
||||
|
@ -1174,10 +1177,11 @@ dwarf2out_frame_debug_expr (expr, label)
|
|||
case REG:
|
||||
if (cfa_reg != (unsigned) REGNO (src))
|
||||
abort ();
|
||||
if (REGNO (dest) != STACK_POINTER_REGNUM
|
||||
&& !(frame_pointer_needed
|
||||
&& REGNO (dest) == HARD_FRAME_POINTER_REGNUM))
|
||||
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);
|
||||
break;
|
||||
|
||||
|
@ -1221,32 +1225,19 @@ dwarf2out_frame_debug_expr (expr, label)
|
|||
{
|
||||
/* Either setting the FP from an offset of the SP,
|
||||
or adjusting the FP */
|
||||
if (! frame_pointer_needed
|
||||
|| REGNO (dest) != HARD_FRAME_POINTER_REGNUM)
|
||||
if (! frame_pointer_needed)
|
||||
abort ();
|
||||
|
||||
if (XEXP (src, 0) == stack_pointer_rtx
|
||||
if (GET_CODE (XEXP (src, 0)) == REG
|
||||
&& (unsigned) REGNO (XEXP (src, 0)) == cfa_reg
|
||||
&& GET_CODE (XEXP (src, 1)) == CONST_INT)
|
||||
{
|
||||
if (cfa_reg != STACK_POINTER_REGNUM)
|
||||
abort ();
|
||||
offset = INTVAL (XEXP (src, 1));
|
||||
if (GET_CODE (src) == PLUS)
|
||||
offset = -offset;
|
||||
cfa_offset += offset;
|
||||
cfa_reg = HARD_FRAME_POINTER_REGNUM;
|
||||
}
|
||||
else if (XEXP (src, 0) == hard_frame_pointer_rtx
|
||||
&& GET_CODE (XEXP (src, 1)) == CONST_INT)
|
||||
{
|
||||
if (cfa_reg != (unsigned) HARD_FRAME_POINTER_REGNUM)
|
||||
abort ();
|
||||
offset = INTVAL (XEXP (src, 1));
|
||||
if (GET_CODE (src) == PLUS)
|
||||
offset = -offset;
|
||||
cfa_offset += offset;
|
||||
}
|
||||
|
||||
else
|
||||
abort();
|
||||
}
|
||||
|
|
10
gcc/except.c
10
gcc/except.c
|
@ -2910,9 +2910,10 @@ expand_builtin_frob_return_addr (addr_tree)
|
|||
The first passes the exception context to the handler. For this
|
||||
we use the return value register for a void*.
|
||||
|
||||
The second holds the stack pointer value to be restored. For
|
||||
this we use the static chain register if it exists and is different
|
||||
from the previous, otherwise some arbitrary call-clobbered register.
|
||||
The second holds the stack pointer value to be restored. For this
|
||||
we use the static chain register if it exists, is different from
|
||||
the previous, and is call-clobbered; otherwise some arbitrary
|
||||
call-clobbered register.
|
||||
|
||||
The third holds the address of the handler itself. Here we use
|
||||
some arbitrary call-clobbered register. */
|
||||
|
@ -2939,7 +2940,8 @@ eh_regs (pcontext, psp, pra, outgoing)
|
|||
rsp = static_chain_incoming_rtx;
|
||||
else
|
||||
rsp = static_chain_rtx;
|
||||
if (REGNO (rsp) == REGNO (rcontext))
|
||||
if (REGNO (rsp) == REGNO (rcontext)
|
||||
|| ! call_used_regs [REGNO (rsp)])
|
||||
#endif /* STATIC_CHAIN_REGNUM */
|
||||
rsp = NULL_RTX;
|
||||
|
||||
|
|
|
@ -697,6 +697,8 @@ execute_cfa_insn (void *p, struct frame_state_internal *state,
|
|||
offset *= info->data_align;
|
||||
state->s.saved[reg] = REG_SAVED_OFFSET;
|
||||
state->s.reg_or_offset[reg] = offset;
|
||||
if (reg == state->s.cfa_reg)
|
||||
state->s.cfa_saved = 1;
|
||||
}
|
||||
else if (insn & DW_CFA_restore)
|
||||
{
|
||||
|
@ -728,6 +730,8 @@ execute_cfa_insn (void *p, struct frame_state_internal *state,
|
|||
offset *= info->data_align;
|
||||
state->s.saved[reg] = REG_SAVED_OFFSET;
|
||||
state->s.reg_or_offset[reg] = offset;
|
||||
if (reg == state->s.cfa_reg)
|
||||
state->s.cfa_saved = 1;
|
||||
break;
|
||||
case DW_CFA_restore_extended:
|
||||
p = decode_uleb128 (p, ®);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* Header file for unwinding stack frames for exception handling. */
|
||||
/* Compile this one with gcc. */
|
||||
/* Copyright (C) 1997, 1998, 1999 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
|
||||
Contributed by Jason Merrill <jason@cygnus.com>.
|
||||
|
||||
This file is part of GNU CC.
|
||||
|
@ -34,6 +34,7 @@ typedef struct frame_state
|
|||
long reg_or_offset[DWARF_FRAME_REGISTERS+1];
|
||||
unsigned short cfa_reg;
|
||||
unsigned short retaddr_column;
|
||||
char cfa_saved;
|
||||
char saved[DWARF_FRAME_REGISTERS+1];
|
||||
} frame_state;
|
||||
|
||||
|
|
|
@ -2760,10 +2760,10 @@ static int cfa_offset;
|
|||
#endif
|
||||
#endif
|
||||
|
||||
/* On a few machines, the CFA coincides with the arg pointer. */
|
||||
/* On most machines, the CFA coincides with the first incoming parm. */
|
||||
|
||||
#ifndef ARG_POINTER_CFA_OFFSET
|
||||
#define ARG_POINTER_CFA_OFFSET 0
|
||||
#define ARG_POINTER_CFA_OFFSET(FNDECL) FIRST_PARM_OFFSET (FNDECL)
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -3335,7 +3335,7 @@ instantiate_virtual_regs (fndecl, insns)
|
|||
var_offset = STARTING_FRAME_OFFSET;
|
||||
dynamic_offset = STACK_DYNAMIC_OFFSET (fndecl);
|
||||
out_arg_offset = STACK_POINTER_OFFSET;
|
||||
cfa_offset = ARG_POINTER_CFA_OFFSET;
|
||||
cfa_offset = ARG_POINTER_CFA_OFFSET (fndecl);
|
||||
|
||||
/* Scan all variables and parameters of this function. For each that is
|
||||
in memory, instantiate all virtual registers if the result is a valid
|
||||
|
|
|
@ -3679,6 +3679,7 @@ throw_helper (struct eh_context *eh, void *pc, frame_state *my_udata,
|
|||
void *handler;
|
||||
void *handler_p = 0;
|
||||
void *pc_p = 0;
|
||||
void *restored_cfa = 0;
|
||||
frame_state saved_ustruct;
|
||||
int new_eh_model;
|
||||
int cleanup = 0;
|
||||
|
@ -3788,6 +3789,11 @@ throw_helper (struct eh_context *eh, void *pc, frame_state *my_udata,
|
|||
pc = saved_pc;
|
||||
memcpy (udata, my_udata, sizeof (*udata));
|
||||
|
||||
if (udata->cfa_saved)
|
||||
/* We saved the CFA register into the stack in this frame, so we
|
||||
will restore it in the __throw epilogue. Remember the value. */
|
||||
restored_cfa = udata->cfa;
|
||||
|
||||
while (pc != handler_pc)
|
||||
{
|
||||
frame_state *p = udata;
|
||||
|
@ -3808,6 +3814,9 @@ throw_helper (struct eh_context *eh, void *pc, frame_state *my_udata,
|
|||
copy_reg (i, udata, my_udata);
|
||||
}
|
||||
|
||||
if (udata->cfa_saved)
|
||||
restored_cfa = udata->cfa;
|
||||
|
||||
pc = get_return_addr (udata, sub_udata) - 1;
|
||||
}
|
||||
|
||||
|
@ -3823,6 +3832,13 @@ throw_helper (struct eh_context *eh, void *pc, frame_state *my_udata,
|
|||
}
|
||||
/* udata now refers to the frame called by the handler frame. */
|
||||
|
||||
if (my_udata->cfa_saved)
|
||||
/* If we saved the CFA register into the stack (after it became the
|
||||
CFA register), we'll restore that value into SP in the epilogue,
|
||||
as on the ARM. So calculate the adjustment based on the value that
|
||||
will be restored. */
|
||||
my_udata->cfa = restored_cfa;
|
||||
|
||||
/* We adjust SP by the difference between __throw's CFA and the CFA for
|
||||
the frame called by the handler frame, because those CFAs correspond
|
||||
to the SP values at the two call sites. We need to further adjust by
|
||||
|
|
14
gcc/tm.texi
14
gcc/tm.texi
|
@ -2292,6 +2292,9 @@ the stack.
|
|||
You only need to define this macro if you want to support call frame
|
||||
debugging information like that provided by DWARF 2.
|
||||
|
||||
If this RTL is a @code{REG}, you should also define
|
||||
DWARF_FRAME_RETURN_COLUMN to @code{DWARF_FRAME_REGNUM (REGNO)}.
|
||||
|
||||
@findex INCOMING_FRAME_SP_OFFSET
|
||||
@item INCOMING_FRAME_SP_OFFSET
|
||||
A C expression whose value is an integer giving the offset, in bytes,
|
||||
|
@ -2304,15 +2307,20 @@ You only need to define this macro if you want to support call frame
|
|||
debugging information like that provided by DWARF 2.
|
||||
|
||||
@findex ARG_POINTER_CFA_OFFSET
|
||||
@item ARG_POINTER_CFA_OFFSET
|
||||
@item ARG_POINTER_CFA_OFFSET (@var{fundecl})
|
||||
A C expression whose value is an integer giving the offset, in bytes,
|
||||
from the argument pointer to the canonical frame address (cfa). The
|
||||
final value should coincide with that calculated by
|
||||
@code{INCOMING_FRAME_SP_OFFSET}. Which is unfortunately not usable
|
||||
during virtual register instantiation.
|
||||
|
||||
You only need to define this macro if you want to support call frame
|
||||
debugging information like that provided by DWARF 2.
|
||||
The default value for this macro is @code{FIRST_PARM_OFFSET (fundecl)},
|
||||
which is correct for most machines; in general, the arguments are found
|
||||
immediately before the stack frame. See @file{function.c} for details.
|
||||
|
||||
You only need to define this macro if this default is incorrect, and you
|
||||
want to support call frame debugging information like that provided by
|
||||
DWARF 2.
|
||||
|
||||
@findex SMALL_STACK
|
||||
@item SMALL_STACK
|
||||
|
|
Loading…
Reference in New Issue