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)
case REG:
if (cselib_lookup (*loc, GET_MODE (SUBREG_REG (subreg)), 0, VOIDmode))
return 1;
+ if (!validate_subreg (GET_MODE (subreg), GET_MODE (*loc),
+ *loc, subreg_lowpart_offset (GET_MODE (subreg),
+ GET_MODE (*loc))))
+ return 1;
return -1;
case PLUS:
case MINUS:
decl_or_value odv = dv_from_value (node->loc);
void **oslot = shared_hash_find_slot_noinsert (set->vars, odv);
- oslot = set_slot_part (set, val, oslot, odv, 0,
- node->init, NULL_RTX);
+ set_slot_part (set, val, oslot, odv, 0,
+ node->init, NULL_RTX);
VALUE_RECURSED_INTO (node->loc) = true;
}
}
if (val)
- cslot = set_slot_part (set, val, cslot, cdv, 0,
- VAR_INIT_STATUS_INITIALIZED, NULL_RTX);
+ set_slot_part (set, val, cslot, cdv, 0,
+ VAR_INIT_STATUS_INITIALIZED, NULL_RTX);
slot = clobber_slot_part (set, cval, slot, 0, NULL);
slot = set_slot_part (set, cval, slot, dv, 0,
node->init, node->set_src);
- slot = clobber_slot_part (set, cval, slot, 0, node->set_src);
+ clobber_slot_part (set, cval, slot, 0, node->set_src);
return 1;
}
VALUE_RECURSED_INTO (val) = true;
for (node = var->var_part[0].loc_chain; node; node = node->next)
- if (MEM_P (node->loc) && MEM_EXPR (node->loc) == expr
- && MEM_OFFSET (node->loc) == 0)
+ if (MEM_P (node->loc)
+ && MEM_EXPR (node->loc) == expr
+ && INT_MEM_OFFSET (node->loc) == 0)
{
where = node;
break;
{
for (loc = var->var_part[0].loc_chain; loc; loc = loc->next)
{
- /* We want to remove dying MEMs that doesn't refer to
- DECL. */
+ /* We want to remove dying MEMs that doesn't refer to DECL. */
if (GET_CODE (loc->loc) == MEM
&& (MEM_EXPR (loc->loc) != decl
- || MEM_OFFSET (loc->loc))
+ || INT_MEM_OFFSET (loc->loc) != 0)
&& !mem_dies_at_call (loc->loc))
break;
/* We want to move here MEMs that do refer to DECL. */
if (GET_CODE (loc->loc) != MEM
|| (MEM_EXPR (loc->loc) == decl
- && MEM_OFFSET (loc->loc) == 0)
+ && INT_MEM_OFFSET (loc->loc) == 0)
|| !mem_dies_at_call (loc->loc))
{
if (old_loc != loc->loc && emit_notes)
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 link, x;
rtx prev, cur, next;
rtx call = PATTERN (insn);
- tree type = NULL_TREE, t;
- CUMULATIVE_ARGS args_so_far;
-
- memset (&args_so_far, 0, sizeof (args_so_far));
+ rtx this_arg = NULL_RTX;
+ tree type = NULL_TREE, t, fndecl = NULL_TREE;
+ tree obj_type_ref = NULL_TREE;
+ CUMULATIVE_ARGS args_so_far_v;
+ cumulative_args_t 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)
call = SET_SRC (call);
- if (GET_CODE (call) == CALL
- && MEM_P (XEXP (call, 0))
- && GET_CODE (XEXP (XEXP (call, 0), 0)) == SYMBOL_REF)
- {
- rtx symbol = XEXP (XEXP (call, 0), 0);
- if (SYMBOL_REF_DECL (symbol)
- && TREE_CODE (SYMBOL_REF_DECL (symbol)) == FUNCTION_DECL
- && TYPE_ARG_TYPES (TREE_TYPE (SYMBOL_REF_DECL (symbol))))
+ if (GET_CODE (call) == CALL && MEM_P (XEXP (call, 0)))
+ {
+ if (GET_CODE (XEXP (XEXP (call, 0), 0)) == SYMBOL_REF)
+ {
+ rtx symbol = XEXP (XEXP (call, 0), 0);
+ if (SYMBOL_REF_DECL (symbol))
+ fndecl = SYMBOL_REF_DECL (symbol);
+ }
+ if (fndecl == NULL_TREE)
+ fndecl = MEM_EXPR (XEXP (call, 0));
+ if (fndecl
+ && TREE_CODE (TREE_TYPE (fndecl)) != FUNCTION_TYPE
+ && TREE_CODE (TREE_TYPE (fndecl)) != METHOD_TYPE)
+ fndecl = NULL_TREE;
+ if (fndecl && TYPE_ARG_TYPES (TREE_TYPE (fndecl)))
+ type = TREE_TYPE (fndecl);
+ if (fndecl && TREE_CODE (fndecl) != FUNCTION_DECL)
+ {
+ if (TREE_CODE (fndecl) == INDIRECT_REF
+ && TREE_CODE (TREE_OPERAND (fndecl, 0)) == OBJ_TYPE_REF)
+ obj_type_ref = TREE_OPERAND (fndecl, 0);
+ fndecl = NULL_TREE;
+ }
+ if (type)
{
- type = TREE_TYPE (SYMBOL_REF_DECL (symbol));
for (t = TYPE_ARG_TYPES (type); t && t != void_list_node;
t = TREE_CHAIN (t))
if (TREE_CODE (TREE_VALUE (t)) == REFERENCE_TYPE
&& INTEGRAL_TYPE_P (TREE_TYPE (TREE_VALUE (t))))
break;
- if (t == NULL || t == void_list_node)
+ if ((t == NULL || t == void_list_node) && obj_type_ref == NULL_TREE)
type = NULL;
else
- INIT_CUMULATIVE_ARGS (args_so_far, type, NULL_RTX,
- SYMBOL_REF_DECL (symbol),
- list_length (TYPE_ARG_TYPES (type)));
+ {
+ int nargs ATTRIBUTE_UNUSED = list_length (TYPE_ARG_TYPES (type));
+ link = CALL_INSN_FUNCTION_USAGE (insn);
+#ifndef PCC_STATIC_STRUCT_RETURN
+ if (aggregate_value_p (TREE_TYPE (type), type)
+ && targetm.calls.struct_value_rtx (type, 0) == 0)
+ {
+ 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_v, type, NULL_RTX, fndecl,
+ nargs + 1);
+ reg = targetm.calls.function_arg (args_so_far, mode,
+ struct_addr, true);
+ targetm.calls.function_arg_advance (args_so_far, mode,
+ struct_addr, true);
+ if (reg == NULL_RTX)
+ {
+ for (; link; link = XEXP (link, 1))
+ if (GET_CODE (XEXP (link, 0)) == USE
+ && MEM_P (XEXP (XEXP (link, 0), 0)))
+ {
+ link = XEXP (link, 1);
+ break;
+ }
+ }
+ }
+ else
+#endif
+ 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,
+ TREE_VALUE (t), true);
+ if (this_arg && !REG_P (this_arg))
+ this_arg = NULL_RTX;
+ else if (this_arg == NULL_RTX)
+ {
+ for (; link; link = XEXP (link, 1))
+ if (GET_CODE (XEXP (link, 0)) == USE
+ && MEM_P (XEXP (XEXP (link, 0), 0)))
+ {
+ this_arg = XEXP (XEXP (link, 0), 0);
+ break;
+ }
+ }
+ }
+ }
}
}
t = type ? TYPE_ARG_TYPES (type) : NULL_TREE;
call_arguments = gen_rtx_EXPR_LIST (VOIDmode, item, call_arguments);
if (t && t != void_list_node)
{
- enum machine_mode mode = TYPE_MODE (TREE_VALUE (t));
- rtx reg = targetm.calls.function_arg (&args_so_far, mode,
- TREE_VALUE (t), true);
- if (TREE_CODE (TREE_VALUE (t)) == REFERENCE_TYPE
- && INTEGRAL_TYPE_P (TREE_TYPE (TREE_VALUE (t)))
+ tree argtype = TREE_VALUE (t);
+ enum machine_mode mode = TYPE_MODE (argtype);
+ rtx reg;
+ 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,
+ argtype, true);
+ if (TREE_CODE (argtype) == REFERENCE_TYPE
+ && INTEGRAL_TYPE_P (TREE_TYPE (argtype))
&& reg
&& REG_P (reg)
&& GET_MODE (reg) == mode
&& item)
{
enum machine_mode indmode
- = TYPE_MODE (TREE_TYPE (TREE_VALUE (t)));
+ = TYPE_MODE (TREE_TYPE (argtype));
rtx mem = gen_rtx_MEM (indmode, x);
cselib_val *val = cselib_lookup (mem, indmode, 0, VOIDmode);
if (val && cselib_preserved_value_p (val))
/* Try harder, when passing address of a constant
pool integer it can be easily read back. */
- val = CSELIB_VAL_PTR (XEXP (item, 1));
+ item = XEXP (item, 1);
+ if (GET_CODE (item) == SUBREG)
+ item = SUBREG_REG (item);
+ gcc_assert (GET_CODE (item) == VALUE);
+ val = CSELIB_VAL_PTR (item);
for (l = val->locs; l; l = l->next)
if (GET_CODE (l->loc) == SYMBOL_REF
&& TREE_CONSTANT_POOL_ADDRESS_P (l->loc)
}
}
}
- targetm.calls.function_arg_advance (&args_so_far, mode,
- TREE_VALUE (t), true);
+ targetm.calls.function_arg_advance (args_so_far, mode,
+ argtype, true);
t = TREE_CHAIN (t);
}
}
if (GET_CODE (x) == CALL && MEM_P (XEXP (x, 0)))
{
x = XEXP (XEXP (x, 0), 0);
- if (GET_CODE (x) != SYMBOL_REF)
+ if (GET_CODE (x) == SYMBOL_REF)
+ /* Don't record anything. */;
+ else if (CONSTANT_P (x))
+ {
+ x = gen_rtx_CONCAT (GET_MODE (x) == VOIDmode ? Pmode : GET_MODE (x),
+ pc_rtx, x);
+ call_arguments
+ = gen_rtx_EXPR_LIST (VOIDmode, x, call_arguments);
+ }
+ else
{
cselib_val *val = cselib_lookup (x, GET_MODE (x), 0, VOIDmode);
if (val && cselib_preserved_value_p (val))
}
}
}
+ if (this_arg)
+ {
+ enum machine_mode mode
+ = TYPE_MODE (TREE_TYPE (OBJ_TYPE_REF_EXPR (obj_type_ref)));
+ rtx clobbered = gen_rtx_MEM (mode, this_arg);
+ HOST_WIDE_INT token
+ = tree_low_cst (OBJ_TYPE_REF_TOKEN (obj_type_ref), 0);
+ if (token)
+ clobbered = plus_constant (clobbered, token * GET_MODE_SIZE (mode));
+ clobbered = gen_rtx_MEM (mode, clobbered);
+ x = gen_rtx_CONCAT (mode, gen_rtx_CLOBBER (VOIDmode, pc_rtx), clobbered);
+ call_arguments
+ = gen_rtx_EXPR_LIST (VOIDmode, x, call_arguments);
+ }
}
/* Callback for cselib_record_sets_hook, that records as micro
if (!slot)
slot = shared_hash_find_slot_unshare (&set->vars, dv, iopt);
}
- slot = set_slot_part (set, loc, slot, dv, offset, initialized, set_src);
+ set_slot_part (set, loc, slot, dv, offset, initialized, set_src);
}
/* Remove all recorded register locations for the given variable part
if (!slot)
return;
- slot = clobber_slot_part (set, loc, slot, offset, set_src);
+ clobber_slot_part (set, loc, slot, offset, set_src);
}
/* Delete the part of variable's location from dataflow set SET. The
if (!slot)
return;
- slot = delete_slot_part (set, loc, slot, offset);
+ delete_slot_part (set, loc, slot, offset);
}
/* Structure for passing some other parameters to function
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))
if (dv_is_value_p (dv))
{
cselib_val *val = CSELIB_VAL_PTR (dv_as_value (dv));
- 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), incoming);
- el->setting_insn = get_insns ();
- val->locs = el;
+ 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, mem);
- el->setting_insn = get_insns ();
- val->locs = el;
+ 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 */
}
};