re PR debug/46724 (Wrong debug info: Invalid variable location)
PR debug/46724 * function.c (assign_parms_augmented_arg_list): Name and mark DECL of result address as NAMELESS rather than IGNORED. (assign_parms): Set DECL_VALUE_EXPR for indirect result. * tree.h (tree_decl_common::decl_flag_2): Document RESULT_DECL. (DECL_HAS_VALUE_EXPR_P): Accept RESULT_DECL. * dwarf2out.c (loc_list_from_tree) <RESULT_DECL>: Use DECL_VALUE_EXPR. * dbxout.c (dbxout_expand_expr) <RESULT_DECL>: Likewise. * var-tracking.c (vt_add_function_parameter): New, split out of... (vt_add_function_parameters): ... this. Handle incoming pointer to hold result. From-SVN: r168160
This commit is contained in:
parent
16a9afdc66
commit
8dcfef8f2b
@ -1,3 +1,18 @@
|
||||
2010-12-22 Alexandre Oliva <aoliva@redhat.com>
|
||||
|
||||
PR debug/46724
|
||||
* function.c (assign_parms_augmented_arg_list): Name and mark
|
||||
DECL of result address as NAMELESS rather than IGNORED.
|
||||
(assign_parms): Set DECL_VALUE_EXPR for indirect result.
|
||||
* tree.h (tree_decl_common::decl_flag_2): Document RESULT_DECL.
|
||||
(DECL_HAS_VALUE_EXPR_P): Accept RESULT_DECL.
|
||||
* dwarf2out.c (loc_list_from_tree) <RESULT_DECL>: Use
|
||||
DECL_VALUE_EXPR.
|
||||
* dbxout.c (dbxout_expand_expr) <RESULT_DECL>: Likewise.
|
||||
* var-tracking.c (vt_add_function_parameter): New, split out of...
|
||||
(vt_add_function_parameters): ... this. Handle incoming
|
||||
pointer to hold result.
|
||||
|
||||
2010-12-22 Jie Zhang <jie@codesourcery.com>
|
||||
|
||||
* config/arm/arm.c (output_move_double): Update the comment
|
||||
|
@ -2396,12 +2396,12 @@ dbxout_expand_expr (tree expr)
|
||||
/* FALLTHRU */
|
||||
|
||||
case PARM_DECL:
|
||||
case RESULT_DECL:
|
||||
if (DECL_HAS_VALUE_EXPR_P (expr))
|
||||
return dbxout_expand_expr (DECL_VALUE_EXPR (expr));
|
||||
/* FALLTHRU */
|
||||
|
||||
case CONST_DECL:
|
||||
case RESULT_DECL:
|
||||
return DECL_RTL_IF_SET (expr);
|
||||
|
||||
case INTEGER_CST:
|
||||
|
@ -15446,12 +15446,12 @@ loc_list_from_tree (tree loc, int want_address)
|
||||
/* FALLTHRU */
|
||||
|
||||
case PARM_DECL:
|
||||
case RESULT_DECL:
|
||||
if (DECL_HAS_VALUE_EXPR_P (loc))
|
||||
return loc_list_from_tree (DECL_VALUE_EXPR (loc),
|
||||
want_address);
|
||||
/* FALLTHRU */
|
||||
|
||||
case RESULT_DECL:
|
||||
case FUNCTION_DECL:
|
||||
{
|
||||
rtx rtl;
|
||||
|
@ -2253,10 +2253,11 @@ assign_parms_augmented_arg_list (struct assign_parm_data_all *all)
|
||||
tree decl;
|
||||
|
||||
decl = build_decl (DECL_SOURCE_LOCATION (fndecl),
|
||||
PARM_DECL, NULL_TREE, type);
|
||||
PARM_DECL, get_identifier (".result_ptr"), type);
|
||||
DECL_ARG_TYPE (decl) = type;
|
||||
DECL_ARTIFICIAL (decl) = 1;
|
||||
DECL_IGNORED_P (decl) = 1;
|
||||
DECL_NAMELESS (decl) = 1;
|
||||
TREE_CONSTANT (decl) = 1;
|
||||
|
||||
DECL_CHAIN (decl) = all->orig_fnargs;
|
||||
all->orig_fnargs = decl;
|
||||
@ -3418,13 +3419,22 @@ assign_parms (tree fndecl)
|
||||
rtx x;
|
||||
|
||||
if (DECL_BY_REFERENCE (result))
|
||||
x = addr;
|
||||
{
|
||||
SET_DECL_VALUE_EXPR (result, all.function_result_decl);
|
||||
x = addr;
|
||||
}
|
||||
else
|
||||
{
|
||||
SET_DECL_VALUE_EXPR (result,
|
||||
build1 (INDIRECT_REF, TREE_TYPE (result),
|
||||
all.function_result_decl));
|
||||
addr = convert_memory_address (Pmode, addr);
|
||||
x = gen_rtx_MEM (DECL_MODE (result), addr);
|
||||
set_mem_attributes (x, result, 1);
|
||||
}
|
||||
|
||||
DECL_HAS_VALUE_EXPR_P (result) = 1;
|
||||
|
||||
SET_DECL_RTL (result, x);
|
||||
}
|
||||
|
||||
|
@ -2773,7 +2773,8 @@ struct GTY(()) tree_decl_common {
|
||||
In TYPE_DECL, this is TYPE_DECL_SUPPRESS_DEBUG. */
|
||||
unsigned decl_flag_1 : 1;
|
||||
/* In FIELD_DECL, this is DECL_NONADDRESSABLE_P
|
||||
In VAR_DECL and PARM_DECL, this is DECL_HAS_VALUE_EXPR_P. */
|
||||
In VAR_DECL, PARM_DECL and RESULT_DECL, this is
|
||||
DECL_HAS_VALUE_EXPR_P. */
|
||||
unsigned decl_flag_2 : 1;
|
||||
/* Logically, these two would go in a theoretical base shared by var and
|
||||
parm decl. */
|
||||
@ -2818,7 +2819,8 @@ extern void decl_value_expr_insert (tree, tree);
|
||||
decl itself. This should only be used for debugging; once this field has
|
||||
been set, the decl itself may not legitimately appear in the function. */
|
||||
#define DECL_HAS_VALUE_EXPR_P(NODE) \
|
||||
(TREE_CHECK2 (NODE, VAR_DECL, PARM_DECL)->decl_common.decl_flag_2)
|
||||
(TREE_CHECK3 (NODE, VAR_DECL, PARM_DECL, RESULT_DECL) \
|
||||
->decl_common.decl_flag_2)
|
||||
#define DECL_VALUE_EXPR(NODE) \
|
||||
(decl_value_expr_lookup (DECL_WRTL_CHECK (NODE)))
|
||||
#define SET_DECL_VALUE_EXPR(NODE, VAL) \
|
||||
|
@ -7999,6 +7999,113 @@ vt_get_decl_and_offset (rtx rtl, tree *declp, HOST_WIDE_INT *offsetp)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Insert function parameter PARM in IN and OUT sets of ENTRY_BLOCK. */
|
||||
|
||||
static void
|
||||
vt_add_function_parameter (tree parm)
|
||||
{
|
||||
rtx decl_rtl = DECL_RTL_IF_SET (parm);
|
||||
rtx incoming = DECL_INCOMING_RTL (parm);
|
||||
tree decl;
|
||||
enum machine_mode mode;
|
||||
HOST_WIDE_INT offset;
|
||||
dataflow_set *out;
|
||||
decl_or_value dv;
|
||||
|
||||
if (TREE_CODE (parm) != PARM_DECL)
|
||||
return;
|
||||
|
||||
if (!decl_rtl || !incoming)
|
||||
return;
|
||||
|
||||
if (GET_MODE (decl_rtl) == BLKmode || GET_MODE (incoming) == BLKmode)
|
||||
return;
|
||||
|
||||
if (!vt_get_decl_and_offset (incoming, &decl, &offset))
|
||||
{
|
||||
if (REG_P (incoming) || MEM_P (incoming))
|
||||
{
|
||||
/* This means argument is passed by invisible reference. */
|
||||
offset = 0;
|
||||
decl = parm;
|
||||
incoming = gen_rtx_MEM (GET_MODE (decl_rtl), incoming);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!vt_get_decl_and_offset (decl_rtl, &decl, &offset))
|
||||
return;
|
||||
offset += byte_lowpart_offset (GET_MODE (incoming),
|
||||
GET_MODE (decl_rtl));
|
||||
}
|
||||
}
|
||||
|
||||
if (!decl)
|
||||
return;
|
||||
|
||||
if (parm != decl)
|
||||
{
|
||||
/* Assume that DECL_RTL was a pseudo that got spilled to
|
||||
memory. The spill slot sharing code will force the
|
||||
memory to reference spill_slot_decl (%sfp), so we don't
|
||||
match above. That's ok, the pseudo must have referenced
|
||||
the entire parameter, so just reset OFFSET. */
|
||||
gcc_assert (decl == get_spill_slot_decl (false));
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
if (!track_loc_p (incoming, parm, offset, false, &mode, &offset))
|
||||
return;
|
||||
|
||||
out = &VTI (ENTRY_BLOCK_PTR)->out;
|
||||
|
||||
dv = dv_from_decl (parm);
|
||||
|
||||
if (target_for_debug_bind (parm)
|
||||
/* We can't deal with these right now, because this kind of
|
||||
variable is single-part. ??? We could handle parallels
|
||||
that describe multiple locations for the same single
|
||||
value, but ATM we don't. */
|
||||
&& GET_CODE (incoming) != PARALLEL)
|
||||
{
|
||||
cselib_val *val;
|
||||
|
||||
/* ??? We shouldn't ever hit this, but it may happen because
|
||||
arguments passed by invisible reference aren't dealt with
|
||||
above: incoming-rtl will have Pmode rather than the
|
||||
expected mode for the type. */
|
||||
if (offset)
|
||||
return;
|
||||
|
||||
val = cselib_lookup (var_lowpart (mode, incoming), mode, true);
|
||||
|
||||
/* ??? Float-typed values in memory are not handled by
|
||||
cselib. */
|
||||
if (val)
|
||||
{
|
||||
preserve_value (val);
|
||||
set_variable_part (out, val->val_rtx, dv, offset,
|
||||
VAR_INIT_STATUS_INITIALIZED, NULL, INSERT);
|
||||
dv = dv_from_value (val->val_rtx);
|
||||
}
|
||||
}
|
||||
|
||||
if (REG_P (incoming))
|
||||
{
|
||||
incoming = var_lowpart (mode, incoming);
|
||||
gcc_assert (REGNO (incoming) < FIRST_PSEUDO_REGISTER);
|
||||
attrs_list_insert (&out->regs[REGNO (incoming)], dv, offset,
|
||||
incoming);
|
||||
set_variable_part (out, incoming, dv, offset,
|
||||
VAR_INIT_STATUS_INITIALIZED, NULL, INSERT);
|
||||
}
|
||||
else if (MEM_P (incoming))
|
||||
{
|
||||
incoming = var_lowpart (mode, incoming);
|
||||
set_variable_part (out, incoming, dv, offset,
|
||||
VAR_INIT_STATUS_INITIALIZED, NULL, INSERT);
|
||||
}
|
||||
}
|
||||
|
||||
/* Insert function parameters to IN and OUT sets of ENTRY_BLOCK. */
|
||||
|
||||
static void
|
||||
@ -8008,110 +8115,20 @@ vt_add_function_parameters (void)
|
||||
|
||||
for (parm = DECL_ARGUMENTS (current_function_decl);
|
||||
parm; parm = DECL_CHAIN (parm))
|
||||
vt_add_function_parameter (parm);
|
||||
|
||||
if (DECL_HAS_VALUE_EXPR_P (DECL_RESULT (current_function_decl)))
|
||||
{
|
||||
rtx decl_rtl = DECL_RTL_IF_SET (parm);
|
||||
rtx incoming = DECL_INCOMING_RTL (parm);
|
||||
tree decl;
|
||||
enum machine_mode mode;
|
||||
HOST_WIDE_INT offset;
|
||||
dataflow_set *out;
|
||||
decl_or_value dv;
|
||||
tree vexpr = DECL_VALUE_EXPR (DECL_RESULT (current_function_decl));
|
||||
|
||||
if (TREE_CODE (parm) != PARM_DECL)
|
||||
continue;
|
||||
if (TREE_CODE (vexpr) == INDIRECT_REF)
|
||||
vexpr = TREE_OPERAND (vexpr, 0);
|
||||
|
||||
if (!DECL_NAME (parm))
|
||||
continue;
|
||||
|
||||
if (!decl_rtl || !incoming)
|
||||
continue;
|
||||
|
||||
if (GET_MODE (decl_rtl) == BLKmode || GET_MODE (incoming) == BLKmode)
|
||||
continue;
|
||||
|
||||
if (!vt_get_decl_and_offset (incoming, &decl, &offset))
|
||||
{
|
||||
if (REG_P (incoming) || MEM_P (incoming))
|
||||
{
|
||||
/* This means argument is passed by invisible reference. */
|
||||
offset = 0;
|
||||
decl = parm;
|
||||
incoming = gen_rtx_MEM (GET_MODE (decl_rtl), incoming);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!vt_get_decl_and_offset (decl_rtl, &decl, &offset))
|
||||
continue;
|
||||
offset += byte_lowpart_offset (GET_MODE (incoming),
|
||||
GET_MODE (decl_rtl));
|
||||
}
|
||||
}
|
||||
|
||||
if (!decl)
|
||||
continue;
|
||||
|
||||
if (parm != decl)
|
||||
{
|
||||
/* Assume that DECL_RTL was a pseudo that got spilled to
|
||||
memory. The spill slot sharing code will force the
|
||||
memory to reference spill_slot_decl (%sfp), so we don't
|
||||
match above. That's ok, the pseudo must have referenced
|
||||
the entire parameter, so just reset OFFSET. */
|
||||
gcc_assert (decl == get_spill_slot_decl (false));
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
if (!track_loc_p (incoming, parm, offset, false, &mode, &offset))
|
||||
continue;
|
||||
|
||||
out = &VTI (ENTRY_BLOCK_PTR)->out;
|
||||
|
||||
dv = dv_from_decl (parm);
|
||||
|
||||
if (target_for_debug_bind (parm)
|
||||
/* We can't deal with these right now, because this kind of
|
||||
variable is single-part. ??? We could handle parallels
|
||||
that describe multiple locations for the same single
|
||||
value, but ATM we don't. */
|
||||
&& GET_CODE (incoming) != PARALLEL)
|
||||
{
|
||||
cselib_val *val;
|
||||
|
||||
/* ??? We shouldn't ever hit this, but it may happen because
|
||||
arguments passed by invisible reference aren't dealt with
|
||||
above: incoming-rtl will have Pmode rather than the
|
||||
expected mode for the type. */
|
||||
if (offset)
|
||||
continue;
|
||||
|
||||
val = cselib_lookup (var_lowpart (mode, incoming), mode, true);
|
||||
|
||||
/* ??? Float-typed values in memory are not handled by
|
||||
cselib. */
|
||||
if (val)
|
||||
{
|
||||
preserve_value (val);
|
||||
set_variable_part (out, val->val_rtx, dv, offset,
|
||||
VAR_INIT_STATUS_INITIALIZED, NULL, INSERT);
|
||||
dv = dv_from_value (val->val_rtx);
|
||||
}
|
||||
}
|
||||
|
||||
if (REG_P (incoming))
|
||||
{
|
||||
incoming = var_lowpart (mode, incoming);
|
||||
gcc_assert (REGNO (incoming) < FIRST_PSEUDO_REGISTER);
|
||||
attrs_list_insert (&out->regs[REGNO (incoming)], dv, offset,
|
||||
incoming);
|
||||
set_variable_part (out, incoming, dv, offset,
|
||||
VAR_INIT_STATUS_INITIALIZED, NULL, INSERT);
|
||||
}
|
||||
else if (MEM_P (incoming))
|
||||
{
|
||||
incoming = var_lowpart (mode, incoming);
|
||||
set_variable_part (out, incoming, dv, offset,
|
||||
VAR_INIT_STATUS_INITIALIZED, NULL, INSERT);
|
||||
}
|
||||
if (TREE_CODE (vexpr) == PARM_DECL
|
||||
&& DECL_ARTIFICIAL (vexpr)
|
||||
&& !DECL_IGNORED_P (vexpr)
|
||||
&& DECL_NAMELESS (vexpr))
|
||||
vt_add_function_parameter (vexpr);
|
||||
}
|
||||
|
||||
if (MAY_HAVE_DEBUG_INSNS)
|
||||
|
Loading…
Reference in New Issue
Block a user