static rtx cfa_base_rtx;
static HOST_WIDE_INT cfa_base_offset;
-/* Compute a CFA-based value for the stack pointer. */
+/* Compute a CFA-based value for an ADJUSTMENT made to stack_pointer_rtx
+ or hard_frame_pointer_rtx. */
static inline rtx
compute_cfa_pointer (HOST_WIDE_INT adjustment)
static rtx
replace_expr_with_values (rtx loc)
{
- if (REG_P (loc))
+ if (REG_P (loc) || GET_CODE (loc) == ENTRY_VALUE)
return NULL;
else if (MEM_P (loc))
{
if (MEM_P (vloc)
&& !REG_P (XEXP (vloc, 0))
&& !MEM_P (XEXP (vloc, 0))
+ && GET_CODE (XEXP (vloc, 0)) != ENTRY_VALUE
&& (GET_CODE (XEXP (vloc, 0)) != PLUS
|| XEXP (XEXP (vloc, 0), 0) != cfa_base_rtx
|| !CONST_INT_P (XEXP (XEXP (vloc, 0), 1))))
if (MEM_P (oloc)
&& !REG_P (XEXP (oloc, 0))
&& !MEM_P (XEXP (oloc, 0))
+ && GET_CODE (XEXP (oloc, 0)) != ENTRY_VALUE
&& (GET_CODE (XEXP (oloc, 0)) != PLUS
|| XEXP (XEXP (oloc, 0), 0) != cfa_base_rtx
|| !CONST_INT_P (XEXP (XEXP (oloc, 0), 1))))
for_each_rtx (x, add_uses, cui);
}
+#define EXPR_DEPTH (PARAM_VALUE (PARAM_MAX_VARTRACK_EXPR_DEPTH))
+
/* Attempt to reverse the EXPR operation in the debug info. Say for
reg1 = reg2 + 6 even when reg2 is no longer live we
can express its value as VAL - 6. */
if (MEM_P (loc) && type == MO_VAL_SET
&& !REG_P (XEXP (loc, 0))
&& !MEM_P (XEXP (loc, 0))
+ && GET_CODE (XEXP (loc, 0)) != ENTRY_VALUE
&& (GET_CODE (XEXP (loc, 0)) != PLUS
|| XEXP (XEXP (loc, 0), 0) != cfa_base_rtx
|| !CONST_INT_P (XEXP (XEXP (loc, 0), 1))))
rtx this_arg = NULL_RTX;
tree type = NULL_TREE, t, fndecl = NULL_TREE;
tree obj_type_ref = NULL_TREE;
- CUMULATIVE_ARGS args_so_far;
+ CUMULATIVE_ARGS args_so_far_v;
+ cumulative_args_t args_so_far;
- memset (&args_so_far, 0, sizeof (args_so_far));
+ memset (&args_so_far_v, 0, sizeof (args_so_far_v));
+ args_so_far = pack_cumulative_args (&args_so_far_v);
if (GET_CODE (call) == PARALLEL)
call = XVECEXP (call, 0, 0);
if (GET_CODE (call) == SET)
tree struct_addr = build_pointer_type (TREE_TYPE (type));
enum machine_mode mode = TYPE_MODE (struct_addr);
rtx reg;
- INIT_CUMULATIVE_ARGS (args_so_far, type, NULL_RTX, fndecl,
+ INIT_CUMULATIVE_ARGS (args_so_far_v, type, NULL_RTX, fndecl,
nargs + 1);
- reg = targetm.calls.function_arg (&args_so_far, mode,
+ reg = targetm.calls.function_arg (args_so_far, mode,
struct_addr, true);
- targetm.calls.function_arg_advance (&args_so_far, mode,
+ targetm.calls.function_arg_advance (args_so_far, mode,
struct_addr, true);
if (reg == NULL_RTX)
{
}
else
#endif
- INIT_CUMULATIVE_ARGS (args_so_far, type, NULL_RTX, fndecl,
+ INIT_CUMULATIVE_ARGS (args_so_far_v, type, NULL_RTX, fndecl,
nargs);
if (obj_type_ref && TYPE_ARG_TYPES (type) != void_list_node)
{
enum machine_mode mode;
t = TYPE_ARG_TYPES (type);
mode = TYPE_MODE (TREE_VALUE (t));
- this_arg = targetm.calls.function_arg (&args_so_far, mode,
+ this_arg = targetm.calls.function_arg (args_so_far, mode,
TREE_VALUE (t), true);
if (this_arg && !REG_P (this_arg))
this_arg = NULL_RTX;
tree argtype = TREE_VALUE (t);
enum machine_mode mode = TYPE_MODE (argtype);
rtx reg;
- if (pass_by_reference (&args_so_far, mode, argtype, true))
+ if (pass_by_reference (&args_so_far_v, mode, argtype, true))
{
argtype = build_pointer_type (argtype);
mode = TYPE_MODE (argtype);
}
- reg = targetm.calls.function_arg (&args_so_far, mode,
+ reg = targetm.calls.function_arg (args_so_far, mode,
argtype, true);
if (TREE_CODE (argtype) == REFERENCE_TYPE
&& INTEGRAL_TYPE_P (TREE_TYPE (argtype))
}
}
}
- targetm.calls.function_arg_advance (&args_so_far, mode,
+ targetm.calls.function_arg_advance (args_so_far, mode,
argtype, true);
t = TREE_CHAIN (t);
}
data.dummy = false;
data.cur_loc_changed = false;
data.ignore_cur_loc = ignore_cur_loc;
- loc = cselib_expand_value_rtx_cb (loc, scratch_regs, 8,
+ loc = cselib_expand_value_rtx_cb (loc, scratch_regs, EXPR_DEPTH,
vt_expand_loc_callback, &data);
if (loc && MEM_P (loc))
data.dummy = true;
data.cur_loc_changed = false;
data.ignore_cur_loc = false;
- ret = cselib_dummy_expand_value_rtx_cb (loc, scratch_regs, 8,
+ ret = cselib_dummy_expand_value_rtx_cb (loc, scratch_regs, EXPR_DEPTH,
vt_expand_loc_callback, &data);
*pcur_loc_changed = data.cur_loc_changed;
return ret;
return false;
}
+/* Helper function for vt_add_function_parameter. RTL is
+ the expression and VAL corresponding cselib_val pointer
+ for which ENTRY_VALUE should be created. */
+
+static void
+create_entry_value (rtx rtl, cselib_val *val)
+{
+ cselib_val *val2;
+ struct elt_loc_list *el;
+ el = (struct elt_loc_list *) ggc_alloc_cleared_atomic (sizeof (*el));
+ el->next = val->locs;
+ el->loc = gen_rtx_ENTRY_VALUE (GET_MODE (rtl));
+ ENTRY_VALUE_EXP (el->loc) = rtl;
+ el->setting_insn = get_insns ();
+ val->locs = el;
+ val2 = cselib_lookup_from_insn (el->loc, GET_MODE (rtl), true,
+ VOIDmode, get_insns ());
+ if (val2
+ && val2 != val
+ && val2->locs
+ && rtx_equal_p (val2->locs->loc, el->loc))
+ {
+ struct elt_loc_list *el2;
+
+ preserve_value (val2);
+ el2 = (struct elt_loc_list *) ggc_alloc_cleared_atomic (sizeof (*el2));
+ el2->next = val2->locs;
+ el2->loc = val->val_rtx;
+ el2->setting_insn = get_insns ();
+ val2->locs = el2;
+ }
+}
+
/* Insert function parameter PARM in IN and OUT sets of ENTRY_BLOCK. */
static void
if (GET_MODE (decl_rtl) == BLKmode || GET_MODE (incoming) == BLKmode)
return;
+ /* If there is a DRAP register, rewrite the incoming location of parameters
+ passed on the stack into MEMs based on the argument pointer, as the DRAP
+ register can be reused for other purposes and we do not track locations
+ based on generic registers. But the prerequisite is that this argument
+ pointer be also the virtual CFA pointer, see vt_initialize. */
+ if (MEM_P (incoming)
+ && stack_realign_drap
+ && arg_pointer_rtx == cfa_base_rtx
+ && (XEXP (incoming, 0) == crtl->args.internal_arg_pointer
+ || (GET_CODE (XEXP (incoming, 0)) == PLUS
+ && XEXP (XEXP (incoming, 0), 0)
+ == crtl->args.internal_arg_pointer
+ && CONST_INT_P (XEXP (XEXP (incoming, 0), 1)))))
+ {
+ HOST_WIDE_INT off = -FIRST_PARM_OFFSET (current_function_decl);
+ if (GET_CODE (XEXP (incoming, 0)) == PLUS)
+ off += INTVAL (XEXP (XEXP (incoming, 0), 1));
+ incoming
+ = replace_equiv_address_nv (incoming,
+ plus_constant (arg_pointer_rtx, off));
+ }
+
if (!vt_get_decl_and_offset (incoming, &decl, &offset))
{
if (REG_P (incoming) || MEM_P (incoming))
VAR_INIT_STATUS_INITIALIZED, NULL, INSERT);
if (dv_is_value_p (dv))
{
- cselib_val *val = CSELIB_VAL_PTR (dv_as_value (dv)), *val2;
- struct elt_loc_list *el;
- el = (struct elt_loc_list *)
- ggc_alloc_cleared_atomic (sizeof (*el));
- el->next = val->locs;
- el->loc = gen_rtx_ENTRY_VALUE (GET_MODE (incoming));
- ENTRY_VALUE_EXP (el->loc) = incoming;
- el->setting_insn = get_insns ();
- val->locs = el;
- val2 = cselib_lookup_from_insn (el->loc, GET_MODE (incoming),
- true, VOIDmode, get_insns ());
- if (val2
- && val2 != val
- && val2->locs
- && rtx_equal_p (val2->locs->loc, el->loc))
- {
- struct elt_loc_list *el2;
-
- preserve_value (val2);
- el2 = (struct elt_loc_list *)
- ggc_alloc_cleared_atomic (sizeof (*el2));
- el2->next = val2->locs;
- el2->loc = dv_as_value (dv);
- el2->setting_insn = get_insns ();
- val2->locs = el2;
- }
+ cselib_val *val = CSELIB_VAL_PTR (dv_as_value (dv));
+ create_entry_value (incoming, val);
if (TREE_CODE (TREE_TYPE (parm)) == REFERENCE_TYPE
&& INTEGRAL_TYPE_P (TREE_TYPE (TREE_TYPE (parm))))
{
if (val)
{
preserve_value (val);
- el = (struct elt_loc_list *)
- ggc_alloc_cleared_atomic (sizeof (*el));
- el->next = val->locs;
- el->loc = gen_rtx_ENTRY_VALUE (indmode);
- ENTRY_VALUE_EXP (el->loc) = mem;
- el->setting_insn = get_insns ();
- val->locs = el;
- val2 = cselib_lookup_from_insn (el->loc, GET_MODE (mem),
- true, VOIDmode,
- get_insns ());
- if (val2
- && val2 != val
- && val2->locs
- && rtx_equal_p (val2->locs->loc, el->loc))
- {
- struct elt_loc_list *el2;
-
- preserve_value (val2);
- el2 = (struct elt_loc_list *)
- ggc_alloc_cleared_atomic (sizeof (*el2));
- el2->next = val2->locs;
- el2->loc = val->val_rtx;
- el2->setting_insn = get_insns ();
- val2->locs = el2;
- }
+ create_entry_value (mem, val);
}
}
}
/* Tell alias analysis that cfa_base_rtx should share
find_base_term value with stack pointer or hard frame pointer. */
- vt_equate_reg_base_value (cfa_base_rtx,
- frame_pointer_needed
- ? hard_frame_pointer_rtx : stack_pointer_rtx);
+ if (!frame_pointer_needed)
+ vt_equate_reg_base_value (cfa_base_rtx, stack_pointer_rtx);
+ else if (!crtl->stack_realign_tried)
+ vt_equate_reg_base_value (cfa_base_rtx, hard_frame_pointer_rtx);
+
val = cselib_lookup_from_insn (cfa_base_rtx, GET_MODE (cfa_base_rtx), 1,
VOIDmode, get_insns ());
preserve_value (val);
static bool
vt_initialize (void)
{
- basic_block bb, prologue_bb = NULL;
+ basic_block bb, prologue_bb = single_succ (ENTRY_BLOCK_PTR);
HOST_WIDE_INT fp_cfa_offset = -1;
alloc_aux_for_blocks (sizeof (struct variable_tracking_info_def));
CLEAR_HARD_REG_SET (argument_reg_set);
+ /* In order to factor out the adjustments made to the stack pointer or to
+ the hard frame pointer and thus be able to use DW_OP_fbreg operations
+ instead of individual location lists, we're going to rewrite MEMs based
+ on them into MEMs based on the CFA by de-eliminating stack_pointer_rtx
+ or hard_frame_pointer_rtx to the virtual CFA pointer frame_pointer_rtx
+ resp. arg_pointer_rtx. We can do this either when there is no frame
+ pointer in the function and stack adjustments are consistent for all
+ basic blocks or when there is a frame pointer and no stack realignment.
+ But we first have to check that frame_pointer_rtx resp. arg_pointer_rtx
+ has been eliminated. */
if (!frame_pointer_needed)
{
rtx reg, elim;
}
if (elim != hard_frame_pointer_rtx)
fp_cfa_offset = -1;
- else
- prologue_bb = single_succ (ENTRY_BLOCK_PTR);
}
+ else
+ fp_cfa_offset = -1;
}
+
+ /* If the stack is realigned and a DRAP register is used, we're going to
+ rewrite MEMs based on it representing incoming locations of parameters
+ passed on the stack into MEMs based on the argument pointer. Although
+ we aren't going to rewrite other MEMs, we still need to initialize the
+ virtual CFA pointer in order to ensure that the argument pointer will
+ be seen as a constant throughout the function.
+
+ ??? This doesn't work if FRAME_POINTER_CFA_OFFSET is defined. */
+ else if (stack_realign_drap)
+ {
+ rtx reg, elim;
+
+#ifdef FRAME_POINTER_CFA_OFFSET
+ reg = frame_pointer_rtx;
+#else
+ reg = arg_pointer_rtx;
+#endif
+ elim = eliminate_regs (reg, VOIDmode, NULL_RTX);
+ if (elim != reg)
+ {
+ if (GET_CODE (elim) == PLUS)
+ elim = XEXP (elim, 0);
+ if (elim == hard_frame_pointer_rtx)
+ vt_init_cfa_base ();
+ }
+ }
+
if (frame_pointer_needed)
{
rtx insn;
}
if (bb == prologue_bb
+ && fp_cfa_offset != -1
&& hard_frame_pointer_adjustment == -1
&& RTX_FRAME_RELATED_P (insn)
&& fp_setter (insn))
static bool
gate_handle_var_tracking (void)
{
- return (flag_var_tracking);
+ return (flag_var_tracking && !targetm.delay_vartrack);
}
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- TODO_dump_func | TODO_verify_rtl_sharing/* todo_flags_finish */
+ TODO_verify_rtl_sharing /* todo_flags_finish */
}
};