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:
Jason Merrill 2000-03-23 00:29:55 +00:00 committed by Jason Merrill
parent cb1072f450
commit 2c84914526
13 changed files with 211 additions and 76 deletions

View File

@ -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.

View 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)));
}

View File

@ -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 \

View File

@ -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),

View File

@ -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. */

View File

@ -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.

View File

@ -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();
}

View File

@ -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;

View File

@ -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, &reg);

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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