Commit 12c5ffe5 by Eric Botcazou Committed by Eric Botcazou

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
parent 021a9e7e
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> 2011-07-15 Bernd Schmidt <bernds@codesourcery.com>
* doc/invoke.texi (C6X Options): New section. * doc/invoke.texi (C6X Options): New section.
......
...@@ -2358,8 +2358,60 @@ convert_debug_memory_address (enum machine_mode mode, rtx x, ...@@ -2358,8 +2358,60 @@ convert_debug_memory_address (enum machine_mode mode, rtx x,
return x; return x;
} }
/* Return an RTX equivalent to the value of the tree expression /* Return an RTX equivalent to the value of the parameter DECL. */
EXP. */
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 static rtx
expand_debug_expr (tree exp) expand_debug_expr (tree exp)
...@@ -3169,36 +3221,12 @@ expand_debug_expr (tree exp) ...@@ -3169,36 +3221,12 @@ expand_debug_expr (tree exp)
if (SSA_NAME_IS_DEFAULT_DEF (exp) if (SSA_NAME_IS_DEFAULT_DEF (exp)
&& TREE_CODE (SSA_NAME_VAR (exp)) == PARM_DECL) && TREE_CODE (SSA_NAME_VAR (exp)) == PARM_DECL)
{ {
rtx incoming = DECL_INCOMING_RTL (SSA_NAME_VAR (exp)); op0 = expand_debug_parm_decl (SSA_NAME_VAR (exp));
if (incoming if (op0)
&& GET_MODE (incoming) != BLKmode goto adjust_mode;
&& ((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_expr (SSA_NAME_VAR (exp)); op0 = expand_debug_expr (SSA_NAME_VAR (exp));
if (!op0) if (op0)
return NULL; goto adjust_mode;
goto adjust_mode;
} }
return NULL; return NULL;
} }
...@@ -3327,36 +3355,14 @@ expand_debug_source_expr (tree exp) ...@@ -3327,36 +3355,14 @@ expand_debug_source_expr (tree exp)
{ {
case PARM_DECL: case PARM_DECL:
{ {
rtx incoming = DECL_INCOMING_RTL (exp);
mode = DECL_MODE (exp); mode = DECL_MODE (exp);
if (incoming op0 = expand_debug_parm_decl (exp);
&& GET_MODE (incoming) != BLKmode if (op0)
&& ((REG_P (incoming) && HARD_REGISTER_P (incoming)) break;
|| (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;
}
/* See if this isn't an argument that has been completely /* See if this isn't an argument that has been completely
optimized out. */ optimized out. */
if (!DECL_RTL_SET_P (exp) if (!DECL_RTL_SET_P (exp)
&& incoming == NULL_RTX && !DECL_INCOMING_RTL (exp)
&& DECL_ABSTRACT_ORIGIN (current_function_decl)) && DECL_ABSTRACT_ORIGIN (current_function_decl))
{ {
tree aexp = exp; tree aexp = exp;
......
...@@ -5333,6 +5333,14 @@ Using a prologue pattern is generally preferred over defining ...@@ -5333,6 +5333,14 @@ Using a prologue pattern is generally preferred over defining
The @code{prologue} pattern is particularly useful for targets which perform The @code{prologue} pattern is particularly useful for targets which perform
instruction scheduling. 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 @cindex @code{epilogue} instruction pattern
@anchor{epilogue instruction pattern} @anchor{epilogue instruction pattern}
@item @samp{epilogue} @item @samp{epilogue}
......
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
operations. operations.
The micro operations of one instruction are ordered so that The micro operations of one instruction are ordered so that
pre-modifying stack adjustment < use < use with no var < call insn < 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 Then, a forward dataflow analysis is performed to find out how locations
of variables change through code and to propagate the variable locations of variables change through code and to propagate the variable locations
...@@ -400,6 +400,17 @@ static shared_hash empty_shared_hash; ...@@ -400,6 +400,17 @@ static shared_hash empty_shared_hash;
/* Scratch register bitmap used by cselib_expand_value_rtx. */ /* Scratch register bitmap used by cselib_expand_value_rtx. */
static bitmap scratch_regs = NULL; 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. */ /* Variable used to tell whether cselib_process_insn called our hook. */
static bool cselib_hook_called; static bool cselib_hook_called;
...@@ -970,6 +981,33 @@ adjust_insn (basic_block bb, rtx insn) ...@@ -970,6 +981,33 @@ adjust_insn (basic_block bb, rtx insn)
{ {
struct adjust_mem_data amd; struct adjust_mem_data amd;
rtx set; 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.mem_mode = VOIDmode;
amd.stack_adjust = -VTI (bb)->out.stack_adjust; amd.stack_adjust = -VTI (bb)->out.stack_adjust;
amd.side_effects = NULL_RTX; amd.side_effects = NULL_RTX;
...@@ -8002,6 +8040,23 @@ emit_notes_for_differences (rtx insn, dataflow_set *old_set, ...@@ -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); 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. */ /* Emit the notes for changes of location parts in the basic block BB. */
static void static void
...@@ -8016,6 +8071,7 @@ emit_notes_in_bb (basic_block bb, dataflow_set *set) ...@@ -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) FOR_EACH_VEC_ELT (micro_operation, VTI (bb)->mos, i, mo)
{ {
rtx insn = mo->insn; rtx insn = mo->insn;
rtx next_insn = next_non_note_insn_var_location (insn);
switch (mo->type) switch (mo->type)
{ {
...@@ -8222,7 +8278,7 @@ emit_notes_in_bb (basic_block bb, dataflow_set *set) ...@@ -8222,7 +8278,7 @@ emit_notes_in_bb (basic_block bb, dataflow_set *set)
val_store (set, XEXP (reverse, 0), XEXP (reverse, 1), val_store (set, XEXP (reverse, 0), XEXP (reverse, 1),
insn, false); 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); set->vars);
} }
break; break;
...@@ -8245,7 +8301,7 @@ emit_notes_in_bb (basic_block bb, dataflow_set *set) ...@@ -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, var_mem_delete_and_set (set, loc, true, VAR_INIT_STATUS_INITIALIZED,
set_src); 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); set->vars);
} }
break; break;
...@@ -8270,7 +8326,7 @@ emit_notes_in_bb (basic_block bb, dataflow_set *set) ...@@ -8270,7 +8326,7 @@ emit_notes_in_bb (basic_block bb, dataflow_set *set)
else else
var_mem_delete_and_set (set, loc, false, src_status, set_src); 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); set->vars);
} }
break; break;
...@@ -8297,7 +8353,7 @@ emit_notes_in_bb (basic_block bb, dataflow_set *set) ...@@ -8297,7 +8353,7 @@ emit_notes_in_bb (basic_block bb, dataflow_set *set)
else else
var_mem_delete (set, loc, true); 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); set->vars);
} }
break; break;
...@@ -8483,6 +8539,39 @@ vt_add_function_parameter (tree parm) ...@@ -8483,6 +8539,39 @@ vt_add_function_parameter (tree parm)
plus_constant (arg_pointer_rtx, off)); 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 (!vt_get_decl_and_offset (incoming, &decl, &offset))
{ {
if (REG_P (incoming) || MEM_P (incoming)) if (REG_P (incoming) || MEM_P (incoming))
...@@ -9046,6 +9135,7 @@ vt_finalize (void) ...@@ -9046,6 +9135,7 @@ vt_finalize (void)
cselib_finish (); cselib_finish ();
BITMAP_FREE (scratch_regs); BITMAP_FREE (scratch_regs);
scratch_regs = NULL; scratch_regs = NULL;
VEC_free (parm_reg_t, gc, windowed_parm_regs);
} }
if (vui_vec) if (vui_vec)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment