re PR debug/48220 (DW_OP_GNU_entry_value/DW_TAG_GNU_call_site_parameter vs register window)

PR target/48220
	* doc/md.texi (Standard Names): Document window_save.
	* cfgexpand.c (expand_debug_parm_decl): New function extracted from
	expand_debug_expr and expand_debug_source_expr.  If the target has
	a window_save instruction, adjust the ENTRY_VALUE_EXP.
	(expand_debug_expr) <SSA_NAME>: Call expand_debug_parm_decl if the
	SSA_NAME_VAR is a parameter.
	(expand_debug_source_expr) <PARM_DECL>: Call expand_debug_parm_decl.
	* var-tracking.c (parm_reg_t): New type and associated vector type.
	(windowed_parm_regs): New variable.
	(adjust_insn): If the target has a window_save instruction and this
	is the instruction, make its effect on parameter registers explicit.
	(next_non_note_insn_var_location): New function.
	(emit_notes_in_bb): Use it instead of NEXT_INSN throughout.
	(vt_add_function_parameter): If the target has a window_save insn,
	adjust the incoming RTL and record that in windowed_parm_regs.
	(vt_finalize): Free windowed_parm_regs.

From-SVN: r176318
This commit is contained in:
Eric Botcazou 2011-07-15 17:09:56 +00:00 committed by Eric Botcazou
parent 021a9e7ef2
commit 12c5ffe5ef
4 changed files with 186 additions and 62 deletions

View File

@ -1,3 +1,23 @@
2011-07-15 Eric Botcazou <ebotcazou@adacore.com>
PR target/48220
* doc/md.texi (Standard Names): Document window_save.
* cfgexpand.c (expand_debug_parm_decl): New function extracted from
expand_debug_expr and expand_debug_source_expr. If the target has
a window_save instruction, adjust the ENTRY_VALUE_EXP.
(expand_debug_expr) <SSA_NAME>: Call expand_debug_parm_decl if the
SSA_NAME_VAR is a parameter.
(expand_debug_source_expr) <PARM_DECL>: Call expand_debug_parm_decl.
* var-tracking.c (parm_reg_t): New type and associated vector type.
(windowed_parm_regs): New variable.
(adjust_insn): If the target has a window_save instruction and this
is the instruction, make its effect on parameter registers explicit.
(next_non_note_insn_var_location): New function.
(emit_notes_in_bb): Use it instead of NEXT_INSN throughout.
(vt_add_function_parameter): If the target has a window_save insn,
adjust the incoming RTL and record that in windowed_parm_regs.
(vt_finalize): Free windowed_parm_regs.
2011-07-15 Bernd Schmidt <bernds@codesourcery.com>
* doc/invoke.texi (C6X Options): New section.

View File

@ -2358,8 +2358,60 @@ convert_debug_memory_address (enum machine_mode mode, rtx x,
return x;
}
/* Return an RTX equivalent to the value of the tree expression
EXP. */
/* Return an RTX equivalent to the value of the parameter DECL. */
static rtx
expand_debug_parm_decl (tree decl)
{
rtx incoming = DECL_INCOMING_RTL (decl);
if (incoming
&& GET_MODE (incoming) != BLKmode
&& ((REG_P (incoming) && HARD_REGISTER_P (incoming))
|| (MEM_P (incoming)
&& REG_P (XEXP (incoming, 0))
&& HARD_REGISTER_P (XEXP (incoming, 0)))))
{
rtx rtl = gen_rtx_ENTRY_VALUE (GET_MODE (incoming));
#ifdef HAVE_window_save
/* DECL_INCOMING_RTL uses the INCOMING_REGNO of parameter registers.
If the target machine has an explicit window save instruction, the
actual entry value is the corresponding OUTGOING_REGNO instead. */
if (REG_P (incoming)
&& OUTGOING_REGNO (REGNO (incoming)) != REGNO (incoming))
incoming
= gen_rtx_REG_offset (incoming, GET_MODE (incoming),
OUTGOING_REGNO (REGNO (incoming)), 0);
else if (MEM_P (incoming))
{
rtx reg = XEXP (incoming, 0);
if (OUTGOING_REGNO (REGNO (reg)) != REGNO (reg))
{
reg = gen_raw_REG (GET_MODE (reg), OUTGOING_REGNO (REGNO (reg)));
incoming = replace_equiv_address_nv (incoming, reg);
}
}
#endif
ENTRY_VALUE_EXP (rtl) = incoming;
return rtl;
}
if (incoming
&& GET_MODE (incoming) != BLKmode
&& !TREE_ADDRESSABLE (decl)
&& MEM_P (incoming)
&& (XEXP (incoming, 0) == virtual_incoming_args_rtx
|| (GET_CODE (XEXP (incoming, 0)) == PLUS
&& XEXP (XEXP (incoming, 0), 0) == virtual_incoming_args_rtx
&& CONST_INT_P (XEXP (XEXP (incoming, 0), 1)))))
return incoming;
return NULL_RTX;
}
/* Return an RTX equivalent to the value of the tree expression EXP. */
static rtx
expand_debug_expr (tree exp)
@ -3169,36 +3221,12 @@ expand_debug_expr (tree exp)
if (SSA_NAME_IS_DEFAULT_DEF (exp)
&& TREE_CODE (SSA_NAME_VAR (exp)) == PARM_DECL)
{
rtx incoming = DECL_INCOMING_RTL (SSA_NAME_VAR (exp));
if (incoming
&& GET_MODE (incoming) != BLKmode
&& ((REG_P (incoming) && HARD_REGISTER_P (incoming))
|| (MEM_P (incoming)
&& REG_P (XEXP (incoming, 0))
&& HARD_REGISTER_P (XEXP (incoming, 0)))))
{
op0 = gen_rtx_ENTRY_VALUE (GET_MODE (incoming));
ENTRY_VALUE_EXP (op0) = incoming;
goto adjust_mode;
}
if (incoming
&& MEM_P (incoming)
&& !TREE_ADDRESSABLE (SSA_NAME_VAR (exp))
&& GET_MODE (incoming) != BLKmode
&& (XEXP (incoming, 0) == virtual_incoming_args_rtx
|| (GET_CODE (XEXP (incoming, 0)) == PLUS
&& XEXP (XEXP (incoming, 0), 0)
== virtual_incoming_args_rtx
&& CONST_INT_P (XEXP (XEXP (incoming, 0),
1)))))
{
op0 = incoming;
goto adjust_mode;
}
op0 = expand_debug_parm_decl (SSA_NAME_VAR (exp));
if (op0)
goto adjust_mode;
op0 = expand_debug_expr (SSA_NAME_VAR (exp));
if (!op0)
return NULL;
goto adjust_mode;
if (op0)
goto adjust_mode;
}
return NULL;
}
@ -3327,36 +3355,14 @@ expand_debug_source_expr (tree exp)
{
case PARM_DECL:
{
rtx incoming = DECL_INCOMING_RTL (exp);
mode = DECL_MODE (exp);
if (incoming
&& GET_MODE (incoming) != BLKmode
&& ((REG_P (incoming) && HARD_REGISTER_P (incoming))
|| (MEM_P (incoming)
&& REG_P (XEXP (incoming, 0))
&& HARD_REGISTER_P (XEXP (incoming, 0)))))
{
op0 = gen_rtx_ENTRY_VALUE (GET_MODE (incoming));
ENTRY_VALUE_EXP (op0) = incoming;
break;
}
if (incoming
&& MEM_P (incoming)
&& !TREE_ADDRESSABLE (exp)
&& GET_MODE (incoming) != BLKmode
&& (XEXP (incoming, 0) == virtual_incoming_args_rtx
|| (GET_CODE (XEXP (incoming, 0)) == PLUS
&& XEXP (XEXP (incoming, 0), 0)
== virtual_incoming_args_rtx
&& CONST_INT_P (XEXP (XEXP (incoming, 0), 1)))))
{
op0 = incoming;
break;
}
op0 = expand_debug_parm_decl (exp);
if (op0)
break;
/* See if this isn't an argument that has been completely
optimized out. */
if (!DECL_RTL_SET_P (exp)
&& incoming == NULL_RTX
&& !DECL_INCOMING_RTL (exp)
&& DECL_ABSTRACT_ORIGIN (current_function_decl))
{
tree aexp = exp;

View File

@ -5333,6 +5333,14 @@ Using a prologue pattern is generally preferred over defining
The @code{prologue} pattern is particularly useful for targets which perform
instruction scheduling.
@cindex @code{window_save} instruction pattern
@anchor{window_save instruction pattern}
@item @samp{window_save}
This pattern, if defined, emits RTL for a register window save. It should
be defined if the target machine has register windows but the window events
are decoupled from calls to subroutines. The canonical example is the SPARC
architecture.
@cindex @code{epilogue} instruction pattern
@anchor{epilogue instruction pattern}
@item @samp{epilogue}

View File

@ -34,7 +34,7 @@
operations.
The micro operations of one instruction are ordered so that
pre-modifying stack adjustment < use < use with no var < call insn <
< set < clobber < post-modifying stack adjustment
< clobber < set < post-modifying stack adjustment
Then, a forward dataflow analysis is performed to find out how locations
of variables change through code and to propagate the variable locations
@ -400,6 +400,17 @@ static shared_hash empty_shared_hash;
/* Scratch register bitmap used by cselib_expand_value_rtx. */
static bitmap scratch_regs = NULL;
typedef struct GTY(()) parm_reg {
rtx outgoing;
rtx incoming;
} parm_reg_t;
DEF_VEC_O(parm_reg_t);
DEF_VEC_ALLOC_O(parm_reg_t, gc);
/* Vector of windowed parameter registers, if any. */
static VEC(parm_reg_t, gc) *windowed_parm_regs = NULL;
/* Variable used to tell whether cselib_process_insn called our hook. */
static bool cselib_hook_called;
@ -970,6 +981,33 @@ adjust_insn (basic_block bb, rtx insn)
{
struct adjust_mem_data amd;
rtx set;
#ifdef HAVE_window_save
/* If the target machine has an explicit window save instruction, the
transformation OUTGOING_REGNO -> INCOMING_REGNO is done there. */
if (RTX_FRAME_RELATED_P (insn)
&& find_reg_note (insn, REG_CFA_WINDOW_SAVE, NULL_RTX))
{
unsigned int i, nregs = VEC_length(parm_reg_t, windowed_parm_regs);
rtx rtl = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (nregs * 2));
parm_reg_t *p;
FOR_EACH_VEC_ELT (parm_reg_t, windowed_parm_regs, i, p)
{
XVECEXP (rtl, 0, i * 2)
= gen_rtx_SET (VOIDmode, p->incoming, p->outgoing);
/* Do not clobber the attached DECL, but only the REG. */
XVECEXP (rtl, 0, i * 2 + 1)
= gen_rtx_CLOBBER (GET_MODE (p->outgoing),
gen_raw_REG (GET_MODE (p->outgoing),
REGNO (p->outgoing)));
}
validate_change (NULL_RTX, &PATTERN (insn), rtl, true);
return;
}
#endif
amd.mem_mode = VOIDmode;
amd.stack_adjust = -VTI (bb)->out.stack_adjust;
amd.side_effects = NULL_RTX;
@ -8002,6 +8040,23 @@ emit_notes_for_differences (rtx insn, dataflow_set *old_set,
emit_notes_for_changes (insn, EMIT_NOTE_BEFORE_INSN, new_set->vars);
}
/* Return the next insn after INSN that is not a NOTE_INSN_VAR_LOCATION. */
static rtx
next_non_note_insn_var_location (rtx insn)
{
while (insn)
{
insn = NEXT_INSN (insn);
if (insn == 0
|| !NOTE_P (insn)
|| NOTE_KIND (insn) != NOTE_INSN_VAR_LOCATION)
break;
}
return insn;
}
/* Emit the notes for changes of location parts in the basic block BB. */
static void
@ -8016,6 +8071,7 @@ emit_notes_in_bb (basic_block bb, dataflow_set *set)
FOR_EACH_VEC_ELT (micro_operation, VTI (bb)->mos, i, mo)
{
rtx insn = mo->insn;
rtx next_insn = next_non_note_insn_var_location (insn);
switch (mo->type)
{
@ -8222,7 +8278,7 @@ emit_notes_in_bb (basic_block bb, dataflow_set *set)
val_store (set, XEXP (reverse, 0), XEXP (reverse, 1),
insn, false);
emit_notes_for_changes (NEXT_INSN (insn), EMIT_NOTE_BEFORE_INSN,
emit_notes_for_changes (next_insn, EMIT_NOTE_BEFORE_INSN,
set->vars);
}
break;
@ -8245,7 +8301,7 @@ emit_notes_in_bb (basic_block bb, dataflow_set *set)
var_mem_delete_and_set (set, loc, true, VAR_INIT_STATUS_INITIALIZED,
set_src);
emit_notes_for_changes (NEXT_INSN (insn), EMIT_NOTE_BEFORE_INSN,
emit_notes_for_changes (next_insn, EMIT_NOTE_BEFORE_INSN,
set->vars);
}
break;
@ -8270,7 +8326,7 @@ emit_notes_in_bb (basic_block bb, dataflow_set *set)
else
var_mem_delete_and_set (set, loc, false, src_status, set_src);
emit_notes_for_changes (NEXT_INSN (insn), EMIT_NOTE_BEFORE_INSN,
emit_notes_for_changes (next_insn, EMIT_NOTE_BEFORE_INSN,
set->vars);
}
break;
@ -8297,7 +8353,7 @@ emit_notes_in_bb (basic_block bb, dataflow_set *set)
else
var_mem_delete (set, loc, true);
emit_notes_for_changes (NEXT_INSN (insn), EMIT_NOTE_BEFORE_INSN,
emit_notes_for_changes (next_insn, EMIT_NOTE_BEFORE_INSN,
set->vars);
}
break;
@ -8483,6 +8539,39 @@ vt_add_function_parameter (tree parm)
plus_constant (arg_pointer_rtx, off));
}
#ifdef HAVE_window_save
/* DECL_INCOMING_RTL uses the INCOMING_REGNO of parameter registers.
If the target machine has an explicit window save instruction, the
actual entry value is the corresponding OUTGOING_REGNO instead. */
if (REG_P (incoming)
&& HARD_REGISTER_P (incoming)
&& OUTGOING_REGNO (REGNO (incoming)) != REGNO (incoming))
{
parm_reg_t *p
= VEC_safe_push (parm_reg_t, gc, windowed_parm_regs, NULL);
p->incoming = incoming;
incoming
= gen_rtx_REG_offset (incoming, GET_MODE (incoming),
OUTGOING_REGNO (REGNO (incoming)), 0);
p->outgoing = incoming;
}
else if (MEM_P (incoming)
&& REG_P (XEXP (incoming, 0))
&& HARD_REGISTER_P (XEXP (incoming, 0)))
{
rtx reg = XEXP (incoming, 0);
if (OUTGOING_REGNO (REGNO (reg)) != REGNO (reg))
{
parm_reg_t *p
= VEC_safe_push (parm_reg_t, gc, windowed_parm_regs, NULL);
p->incoming = reg;
reg = gen_raw_REG (GET_MODE (reg), OUTGOING_REGNO (REGNO (reg)));
p->outgoing = reg;
incoming = replace_equiv_address_nv (incoming, reg);
}
}
#endif
if (!vt_get_decl_and_offset (incoming, &decl, &offset))
{
if (REG_P (incoming) || MEM_P (incoming))
@ -9046,6 +9135,7 @@ vt_finalize (void)
cselib_finish ();
BITMAP_FREE (scratch_regs);
scratch_regs = NULL;
VEC_free (parm_reg_t, gc, windowed_parm_regs);
}
if (vui_vec)