(location_or_const_value_attribute): Fixed to use DECL_INCOMING_RTL for PARM_DECLs only when DECL_RTL isn't usable...

(location_or_const_value_attribute): Fixed to use DECL_INCOMING_RTL
for PARM_DECLs only when DECL_RTL isn't usable, and even then, only
when it actually points to the right place.

From-SVN: r4189
This commit is contained in:
Richard Kenner 1993-04-21 18:14:38 -04:00
parent a76386d8e5
commit 0e02aa7e28
1 changed files with 100 additions and 59 deletions

View File

@ -2100,68 +2100,109 @@ location_or_const_value_attribute (decl)
return;
if ((TREE_CODE (decl) != VAR_DECL) && (TREE_CODE (decl) != PARM_DECL))
abort ();
/* Existing Dwarf debuggers need and expect the location descriptors for
formal parameters to reflect either the place where the parameters get
passed (if they are passed on the stack and in memory) or else the
(preserved) registers which the parameters get copied to during the
function prologue.
At least this is the way things are for most common CISC machines
(e.g. x86 and m68k) where parameters are passed in the stack, and for
most common RISC machines (e.g. i860 and m88k) where parameters are
passed in registers.
The rules for Sparc are a little weird for some reason. The DWARF
generated by the USL C compiler for the Sparc/svr4 reference port says
that the parameters are passed in the stack. I haven't figured out
how to duplicate that behavior here (for the Sparc) yet, or even if
I really need to.
Note that none of this is clearly spelled out in the current Dwarf
version 1 specification, but it's obvious if you look at the output of
the CI5 compiler, or if you try to use the svr4 SDB debugger. Hopefully,
a later version of the Dwarf specification will clarify this. For now,
we just need to generate the right thing. Note that Dwarf version 2
will provide us with a means to describe *all* of the locations in which
a given variable or parameter resides (and the PC ranges over which it
occupies each one), but for now we can only describe one "location"
for each formal parameter passed, and so we just try to mimic existing
practice as much as possible.
*/
if (TREE_CODE (decl) != PARM_DECL)
/* If this decl is not a formal parameter, just use DECL_RTL. */
rtl = DECL_RTL (decl);
else
{
if (GET_CODE (DECL_INCOMING_RTL (decl)) == MEM)
/* Parameter was passed in memory, so say that's where it lives. */
rtl = DECL_INCOMING_RTL (decl);
else
{
/* Parameter was passed in a register, so say it lives in the
register it will be copied to during the prologue. */
rtl = DECL_RTL (decl);
/* Note that in cases where the formal parameter is never used
and where this compilation is done with -O, the copying of
of an incoming register parameter to another register (in
the prologue) can be totally optimized away. (In such cases
the DECL_RTL will indicate a pseudo-register.) We could just
use the DECL_RTL (as we normally do for register parameters)
in these cases, but if we did that, we would end up generating
a null location descriptor. (See `location_attribute' above.)
That would be acceptable (according to the DWARF spec) but it
is probably more useful to say that the formal resides where
it was passed instead of saying that it resides nowhere. */
if (is_pseudo_reg (rtl))
rtl = DECL_INCOMING_RTL (decl);
}
/* Should never happen. */
abort ();
return;
}
if (rtl == NULL)
/* Here we have to decide where we are going to say the parameter "lives"
(as far as the debugger is concerned). We only have a couple of choices.
GCC provides us with DECL_RTL and with DECL_INCOMING_RTL. DECL_RTL
normally indicates where the parameter lives during most of the activa-
tion of the function. If optimization is enabled however, this could
be either NULL or else a pseudo-reg. Both of those cases indicate that
the parameter doesn't really live anywhere (as far as the code generation
parts of GCC are concerned) during most of the function's activation.
That will happen (for example) if the parameter is never referenced
within the function.
We could just generate a location descriptor here for all non-NULL
non-pseudo values of DECL_RTL and ignore all of the rest, but we can
be a little nicer than that if we also consider DECL_INCOMING_RTL in
cases where DECL_RTL is NULL or is a pseudo-reg.
Note however that we can only get away with using DECL_INCOMING_RTL as
a backup substitute for DECL_RTL in certain limited cases. In cases
where DECL_ARG_TYPE(decl) indicates the same type as TREE_TYPE(decl)
we can be sure that the parameter was passed using the same type as it
is declared to have within the function, and that its DECL_INCOMING_RTL
points us to a place where a value of that type is passed. In cases
where DECL_ARG_TYPE(decl) and TREE_TYPE(decl) are different types
however, we cannot (in general) use DECL_INCOMING_RTL as a backup
substitute for DECL_RTL because in these cases, DECL_INCOMING_RTL
points us to a value of some type which is *different* from the type
of the parameter itself. Thus, if we tried to use DECL_INCOMING_RTL
to generate a location attribute in such cases, the debugger would
end up (for example) trying to fetch a `float' from a place which
actually contains the first part of a `double'. That would lead to
really incorrect and confusing output at debug-time, and we don't
want that now do we?
So in general, we DO NOT use DECL_INCOMING_RTL as a backup for DECL_RTL
in cases where DECL_ARG_TYPE(decl) != TREE_TYPE(decl). There are a
couple of cute exceptions however. On little-endian machines we can
get away with using DECL_INCOMING_RTL even when DECL_ARG_TYPE(decl) is
not the same as TREE_TYPE(decl) but only when DECL_ARG_TYPE(decl) is
an integral type which is smaller than TREE_TYPE(decl). These cases
arise when (on a little-endian machine) a non-prototyped function has
a parameter declared to be of type `short' or `char'. In such cases,
TREE_TYPE(decl) will be `short' or `char', DECL_ARG_TYPE(decl) will be
`int', and DECL_INCOMING_RTL will point to the lowest-order byte of the
passed `int' value. If the debugger then uses that address to fetch a
`short' or a `char' (on a little-endian machine) the result will be the
correct data, so we allow for such exceptional cases below.
Note that our goal here is to describe the place where the given formal
parameter lives during most of the function's activation (i.e. between
the end of the prologue and the start of the epilogue). We'll do that
as best as we can. Note however that if the given formal parameter is
modified sometime during the execution of the function, then a stack
backtrace (at debug-time) will show the function as having been called
with the *new* value rather than the value which was originally passed
in. This happens rarely enough that it is not a major problem, but it
*is* a problem, and I'd like to fix it. A future version of dwarfout.c
may generate two additional attributes for any given TAG_formal_parameter
DIE which will describe the "passed type" and the "passed location" for
the given formal parameter in addition to the attributes we now generate
to indicate the "declared type" and the "active location" for each
parameter. This additional set of attributes could be used by debuggers
for stack backtraces.
Separately, note that sometimes DECL_RTL can be NULL and DECL_INCOMING_RTL
can be NULL also. This happens (for example) for inlined-instances of
inline function formal parameters which are never referenced. This really
shouldn't be happening. All PARM_DECL nodes should get valid non-NULL
DECL_INCOMING_RTL values, but integrate.c doesn't currently generate
these values for inlined instances of inline function parameters, so
when we see such cases, we are just SOL (shit-out-of-luck) for the time
being (until integrate.c gets fixed).
*/
/* Use DECL_RTL as the "location" unless we find something better. */
rtl = DECL_RTL (decl);
if (TREE_CODE (decl) == PARM_DECL)
if (rtl == NULL_RTX || is_pseudo_reg (rtl))
{
/* This decl represents a formal parameter which was optimized out. */
register tree declared_type = TYPE_MAIN_VARIANT (TREE_TYPE (decl));
register tree passed_type = TYPE_MAIN_VARIANT (DECL_ARG_TYPE (decl));
/* Note that DECL_INCOMING_RTL may be NULL in here, but we handle
*all* cases where (rtl == NULL_RTX) just below. */
if (declared_type == passed_type)
rtl = DECL_INCOMING_RTL (decl);
#if (BYTES_BIG_ENDIAN == 0)
else
if (TREE_CODE (declared_type) == INTEGER_TYPE)
if (TYPE_SIZE (declared_type) <= TYPE_SIZE (passed_type))
rtl = DECL_INCOMING_RTL (decl);
#endif /* (BYTES_BIG_ENDIAN == 0) */
}
if (rtl == NULL_RTX)
return;
switch (GET_CODE (rtl))