/* Variable tracking routines for the GNU compiler.
- Copyright (C) 2002-2018 Free Software Foundation, Inc.
+ Copyright (C) 2002-2020 Free Software Foundation, Inc.
This file is part of GCC.
#include "tree-dfa.h"
#include "tree-ssa.h"
#include "cselib.h"
-#include "params.h"
#include "tree-pretty-print.h"
#include "rtl-iter.h"
#include "fibonacci_heap.h"
+#include "print-rtl.h"
+#include "function-abi.h"
typedef fibonacci_heap <long, basic_block_def> bb_heap_t;
typedef fibonacci_node <long, basic_block_def> bb_heap_node_t;
or hard_frame_pointer_rtx. */
static inline rtx
-compute_cfa_pointer (HOST_WIDE_INT adjustment)
+compute_cfa_pointer (poly_int64 adjustment)
{
return plus_constant (Pmode, cfa_base_rtx, adjustment + cfa_base_offset);
}
/* Adjustment for hard_frame_pointer_rtx to cfa base reg,
or -1 if the replacement shouldn't be done. */
-static HOST_WIDE_INT hard_frame_pointer_adjustment = -1;
+static poly_int64 hard_frame_pointer_adjustment = -1;
/* Data for adjust_mems callback. */
-struct adjust_mem_data
+class adjust_mem_data
{
+public:
bool store;
machine_mode mem_mode;
HOST_WIDE_INT stack_adjust;
case MULT:
break;
case ASHIFT:
+ if (GET_MODE (XEXP (x, 1)) != VOIDmode)
+ {
+ enum machine_mode mode = GET_MODE (subreg);
+ rtx op1 = XEXP (x, 1);
+ enum machine_mode op1_mode = GET_MODE (op1);
+ if (GET_MODE_PRECISION (as_a <scalar_int_mode> (mode))
+ < GET_MODE_PRECISION (as_a <scalar_int_mode> (op1_mode)))
+ {
+ poly_uint64 byte = subreg_lowpart_offset (mode, op1_mode);
+ if (GET_CODE (op1) == SUBREG || GET_CODE (op1) == CONCAT)
+ {
+ if (!simplify_subreg (mode, op1, op1_mode, byte))
+ return false;
+ }
+ else if (!validate_subreg (mode, op1_mode, op1, byte))
+ return false;
+ }
+ }
iter.substitute (XEXP (x, 0));
break;
default:
static rtx
adjust_mems (rtx loc, const_rtx old_rtx, void *data)
{
- struct adjust_mem_data *amd = (struct adjust_mem_data *) data;
+ class adjust_mem_data *amd = (class adjust_mem_data *) data;
rtx mem, addr = loc, tem;
machine_mode mem_mode_save;
bool store_save;
return compute_cfa_pointer (amd->stack_adjust);
else if (loc == hard_frame_pointer_rtx
&& frame_pointer_needed
- && hard_frame_pointer_adjustment != -1
+ && maybe_ne (hard_frame_pointer_adjustment, -1)
&& cfa_base_rtx)
return compute_cfa_pointer (hard_frame_pointer_adjustment);
gcc_checking_assert (loc != virtual_incoming_args_rtx);
amd.stack_adjust = -VTI (bb)->out.stack_adjust;
amd.store = true;
- note_stores (PATTERN (insn), adjust_mem_stores, &amd);
+ note_stores (insn, adjust_mem_stores, &amd);
amd.store = false;
if (GET_CODE (PATTERN (insn)) == PARALLEL
static rtx
vt_canonicalize_addr (dataflow_set *set, rtx oloc)
{
- HOST_WIDE_INT ofst = 0;
+ poly_int64 ofst = 0, term;
machine_mode mode = GET_MODE (oloc);
rtx loc = oloc;
rtx x;
while (retry)
{
while (GET_CODE (loc) == PLUS
- && GET_CODE (XEXP (loc, 1)) == CONST_INT)
+ && poly_int_rtx_p (XEXP (loc, 1), &term))
{
- ofst += INTVAL (XEXP (loc, 1));
+ ofst += term;
loc = XEXP (loc, 0);
}
loc = get_addr_from_global_cache (loc);
/* Consolidate plus_constants. */
- while (ofst && GET_CODE (loc) == PLUS
- && GET_CODE (XEXP (loc, 1)) == CONST_INT)
+ while (maybe_ne (ofst, 0)
+ && GET_CODE (loc) == PLUS
+ && poly_int_rtx_p (XEXP (loc, 1), &term))
{
- ofst += INTVAL (XEXP (loc, 1));
+ ofst += term;
loc = XEXP (loc, 0);
}
}
/* Add OFST back in. */
- if (ofst)
+ if (maybe_ne (ofst, 0))
{
/* Don't build new RTL if we can help it. */
- if (GET_CODE (oloc) == PLUS
- && XEXP (oloc, 0) == loc
- && INTVAL (XEXP (oloc, 1)) == ofst)
+ if (strip_offset (oloc, &term) == loc && known_eq (term, ofst))
return oloc;
loc = plus_constant (mode, loc, ofst);
{
unsigned int r;
hard_reg_set_iterator hrsi;
- HARD_REG_SET invalidated_regs;
- get_call_reg_set_usage (call_insn, &invalidated_regs,
- regs_invalidated_by_call);
+ HARD_REG_SET callee_clobbers
+ = insn_callee_abi (call_insn).full_reg_clobbers ();
- EXECUTE_IF_SET_IN_HARD_REG_SET (invalidated_regs, 0, r, hrsi)
+ EXECUTE_IF_SET_IN_HARD_REG_SET (callee_clobbers, 0, r, hrsi)
var_regno_delete (set, r);
if (MAY_HAVE_DEBUG_BIND_INSNS)
compile time for ridiculously complex expressions, although they're
seldom useful, and they may often have to be discarded as not
representable anyway. */
-#define EXPR_USE_DEPTH (PARAM_VALUE (PARAM_MAX_VARTRACK_EXPR_DEPTH))
+#define EXPR_USE_DEPTH (param_max_vartrack_expr_depth)
/* Attempt to reverse the EXPR operation in the debug info and record
it in the cselib table. Say for reg1 = reg2 + 6 even when reg2 is
&& (GET_CODE (l->loc) != CONST || !references_value_p (l->loc, 0)))
return;
/* Avoid creating too large locs lists. */
- else if (count == PARAM_VALUE (PARAM_MAX_VARTRACK_REVERSE_OP_SIZE))
+ else if (count == param_max_vartrack_reverse_op_size)
return;
switch (GET_CODE (src))
}
if (loc == stack_pointer_rtx
- && hard_frame_pointer_adjustment != -1
+ && (maybe_ne (hard_frame_pointer_adjustment, -1)
+ || (!frame_pointer_needed && !ACCUMULATE_OUTGOING_ARGS))
&& preserve)
cselib_set_value_sp_based (v);
+ /* Don't record MO_VAL_SET for VALUEs that can be described using
+ cfa_base_rtx or cfa_base_rtx + CONST_INT, cselib already knows
+ all the needed equivalences and they shouldn't change depending
+ on which register holds that VALUE in some instruction. */
+ if (!frame_pointer_needed
+ && cfa_base_rtx
+ && cselib_sp_derived_value_p (v))
+ {
+ if (preserve)
+ preserve_value (v);
+ return;
+ }
+
nloc = replace_expr_with_values (oloc);
if (nloc)
oloc = nloc;
&& targetm.calls.struct_value_rtx (type, 0) == 0)
{
tree struct_addr = build_pointer_type (TREE_TYPE (type));
- machine_mode mode = TYPE_MODE (struct_addr);
+ function_arg_info arg (struct_addr, /*named=*/true);
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);
+ reg = targetm.calls.function_arg (args_so_far, arg);
+ targetm.calls.function_arg_advance (args_so_far, arg);
if (reg == NULL_RTX)
{
for (; link; link = XEXP (link, 1))
nargs);
if (obj_type_ref && TYPE_ARG_TYPES (type) != void_list_node)
{
- 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);
+ function_arg_info arg (TREE_VALUE (t), /*named=*/true);
+ this_arg = targetm.calls.function_arg (args_so_far, arg);
if (this_arg && !REG_P (this_arg))
this_arg = NULL_RTX;
else if (this_arg == NULL_RTX)
if (!frame_pointer_needed)
{
- struct adjust_mem_data amd;
+ class adjust_mem_data amd;
amd.mem_mode = VOIDmode;
amd.stack_adjust = -VTI (bb)->out.stack_adjust;
amd.store = true;
}
if (t && t != void_list_node)
{
- tree argtype = TREE_VALUE (t);
- 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))
+ function_arg_info arg (TREE_VALUE (t), /*named=*/true);
+ apply_pass_by_reference_rules (&args_so_far_v, arg);
+ reg = targetm.calls.function_arg (args_so_far, arg);
+ if (TREE_CODE (arg.type) == REFERENCE_TYPE
+ && INTEGRAL_TYPE_P (TREE_TYPE (arg.type))
&& reg
&& REG_P (reg)
- && GET_MODE (reg) == mode
- && (GET_MODE_CLASS (mode) == MODE_INT
- || GET_MODE_CLASS (mode) == MODE_PARTIAL_INT)
+ && GET_MODE (reg) == arg.mode
+ && (GET_MODE_CLASS (arg.mode) == MODE_INT
+ || GET_MODE_CLASS (arg.mode) == MODE_PARTIAL_INT)
&& REG_P (x)
&& REGNO (x) == REGNO (reg)
- && GET_MODE (x) == mode
+ && GET_MODE (x) == arg.mode
&& item)
{
machine_mode indmode
- = TYPE_MODE (TREE_TYPE (argtype));
+ = TYPE_MODE (TREE_TYPE (arg.type));
rtx mem = gen_rtx_MEM (indmode, x);
cselib_val *val = cselib_lookup (mem, indmode, 0, VOIDmode);
if (val && cselib_preserved_value_p (val))
}
}
}
- targetm.calls.function_arg_advance (args_so_far, mode,
- argtype, true);
+ targetm.calls.function_arg_advance (args_so_far, arg);
t = TREE_CHAIN (t);
}
}
insert notes before it without worrying about any
notes that MO_USEs might emit after the insn. */
cui.store_p = true;
- note_stores (PATTERN (insn), add_stores, &cui);
+ note_stores (insn, add_stores, &cui);
n2 = VTI (bb)->mos.length () - 1;
mos = VTI (bb)->mos.address ();
int *rc_order;
int i;
int htabsz = 0;
- int htabmax = PARAM_VALUE (PARAM_MAX_VARTRACK_SIZE);
+ int htabmax = param_max_vartrack_size;
bool success = true;
timevar_push (TV_VAR_TRACKING_DATAFLOW);
if (MAY_HAVE_DEBUG_BIND_INSNS)
inform (DECL_SOURCE_LOCATION (cfun->decl),
"variable tracking size limit exceeded with "
- "-fvar-tracking-assignments, retrying without");
+ "%<-fvar-tracking-assignments%>, retrying without");
else
inform (DECL_SOURCE_LOCATION (cfun->decl),
"variable tracking size limit exceeded");
static void
dump_vars (variable_table_type *vars)
{
- if (vars->elements () > 0)
+ if (!vars->is_empty ())
{
fprintf (dump_file, "Variables:\n");
vars->traverse <void *, dump_var_tracking_slot> (NULL);
/* Structure for passing some other parameters to function
vt_expand_loc_callback. */
-struct expand_loc_callback_data
+class expand_loc_callback_data
{
+public:
/* The variables and values active at this point. */
variable_table_type *vars;
vt_expand_var_loc_chain (variable *var, bitmap regs, void *data,
bool *pendrecp)
{
- struct expand_loc_callback_data *elcd
- = (struct expand_loc_callback_data *) data;
+ class expand_loc_callback_data *elcd
+ = (class expand_loc_callback_data *) data;
location_chain *loc, *next;
rtx result = NULL;
int first_child, result_first_child, last_child;
int max_depth ATTRIBUTE_UNUSED,
void *data)
{
- struct expand_loc_callback_data *elcd
- = (struct expand_loc_callback_data *) data;
+ class expand_loc_callback_data *elcd
+ = (class expand_loc_callback_data *) data;
decl_or_value dv;
variable *var;
rtx result, subreg;
/* Invalid SUBREGs are ok in debug info. ??? We could try
alternate expansions for the VALUE as well. */
- if (!result)
+ if (!result && GET_MODE (subreg) != VOIDmode)
result = gen_rtx_raw_SUBREG (GET_MODE (x), subreg, SUBREG_BYTE (x));
return result;
static rtx
vt_expand_loc (rtx loc, variable_table_type *vars)
{
- struct expand_loc_callback_data data;
+ class expand_loc_callback_data data;
rtx result;
if (!MAY_HAVE_DEBUG_BIND_INSNS)
static rtx
vt_expand_1pvar (variable *var, variable_table_type *vars)
{
- struct expand_loc_callback_data data;
+ class expand_loc_callback_data data;
rtx loc;
gcc_checking_assert (var->onepart && var->n_var_parts == 1);
&& GET_CODE (loc[n_var_parts]) == GET_CODE (loc2))
{
rtx new_loc = NULL;
+ poly_int64 offset2;
if (REG_P (loc[n_var_parts])
&& hard_regno_nregs (REGNO (loc[n_var_parts]), mode) * 2
else if (MEM_P (loc[n_var_parts])
&& GET_CODE (XEXP (loc2, 0)) == PLUS
&& REG_P (XEXP (XEXP (loc2, 0), 0))
- && CONST_INT_P (XEXP (XEXP (loc2, 0), 1)))
+ && poly_int_rtx_p (XEXP (XEXP (loc2, 0), 1), &offset2))
{
- if ((REG_P (XEXP (loc[n_var_parts], 0))
- && rtx_equal_p (XEXP (loc[n_var_parts], 0),
- XEXP (XEXP (loc2, 0), 0))
- && INTVAL (XEXP (XEXP (loc2, 0), 1)) == size)
- || (GET_CODE (XEXP (loc[n_var_parts], 0)) == PLUS
- && CONST_INT_P (XEXP (XEXP (loc[n_var_parts], 0), 1))
- && rtx_equal_p (XEXP (XEXP (loc[n_var_parts], 0), 0),
- XEXP (XEXP (loc2, 0), 0))
- && INTVAL (XEXP (XEXP (loc[n_var_parts], 0), 1)) + size
- == INTVAL (XEXP (XEXP (loc2, 0), 1))))
+ poly_int64 end1 = size;
+ rtx base1 = strip_offset_and_add (XEXP (loc[n_var_parts], 0),
+ &end1);
+ if (rtx_equal_p (base1, XEXP (XEXP (loc2, 0), 0))
+ && known_eq (end1, offset2))
new_loc = adjust_address_nv (loc[n_var_parts],
wider_mode, 0);
}
emit_note_data data;
variable_table_type *htab = shared_hash_htab (vars);
- if (!changed_variables->elements ())
+ if (changed_variables->is_empty ())
return;
if (MAY_HAVE_DEBUG_BIND_INSNS)
basic_block bb;
dataflow_set cur;
- gcc_assert (!changed_variables->elements ());
+ gcc_assert (changed_variables->is_empty ());
/* Free memory occupied by the out hash tables, as they aren't used
anymore. */
rewrite the incoming location of parameters passed on the stack
into MEMs based on the argument pointer, so that incoming doesn't
depend on a pseudo. */
+ poly_int64 incoming_offset = 0;
if (MEM_P (incoming)
- && (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)))))
+ && (strip_offset (XEXP (incoming, 0), &incoming_offset)
+ == crtl->args.internal_arg_pointer))
{
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 (Pmode,
- arg_pointer_rtx, off));
+ arg_pointer_rtx,
+ off + incoming_offset));
}
#ifdef HAVE_window_save
vt_initialize (void)
{
basic_block bb;
- HOST_WIDE_INT fp_cfa_offset = -1;
+ poly_int64 fp_cfa_offset = -1;
alloc_aux_for_blocks (sizeof (variable_tracking_info));
preserve_value (val);
if (reg != hard_frame_pointer_rtx && fixed_regs[REGNO (reg)])
cselib_preserve_cfa_base_value (val, REGNO (reg));
- expr = plus_constant (GET_MODE (stack_pointer_rtx),
- stack_pointer_rtx, -ofst);
- cselib_add_permanent_equiv (val, expr, get_insns ());
-
if (ofst)
{
- val = cselib_lookup_from_insn (stack_pointer_rtx,
- GET_MODE (stack_pointer_rtx), 1,
- VOIDmode, get_insns ());
- preserve_value (val);
+ cselib_val *valsp
+ = cselib_lookup_from_insn (stack_pointer_rtx,
+ GET_MODE (stack_pointer_rtx), 1,
+ VOIDmode, get_insns ());
+ preserve_value (valsp);
expr = plus_constant (GET_MODE (reg), reg, ofst);
- cselib_add_permanent_equiv (val, expr, get_insns ());
+ /* This cselib_add_permanent_equiv call needs to be done before
+ the other cselib_add_permanent_equiv a few lines later,
+ because after that one is done, cselib_lookup on this expr
+ will due to the cselib SP_DERIVED_VALUE_P optimizations
+ return valsp and so no permanent equivalency will be added. */
+ cselib_add_permanent_equiv (valsp, expr, get_insns ());
}
+
+ expr = plus_constant (GET_MODE (stack_pointer_rtx),
+ stack_pointer_rtx, -ofst);
+ cselib_add_permanent_equiv (val, expr, get_insns ());
}
/* In order to factor out the adjustments made to the stack pointer or to
{
if (GET_CODE (elim) == PLUS)
{
- fp_cfa_offset -= INTVAL (XEXP (elim, 1));
+ fp_cfa_offset -= rtx_to_poly_int64 (XEXP (elim, 1));
elim = XEXP (elim, 0);
}
if (elim != hard_frame_pointer_rtx)
vt_add_function_parameters ();
+ bool record_sp_value = false;
FOR_EACH_BB_FN (bb, cfun)
{
rtx_insn *insn;
- HOST_WIDE_INT pre, post = 0;
basic_block first_bb, last_bb;
if (MAY_HAVE_DEBUG_BIND_INSNS)
cselib_get_next_uid ());
}
+ if (MAY_HAVE_DEBUG_BIND_INSNS
+ && cfa_base_rtx
+ && !frame_pointer_needed
+ && record_sp_value)
+ cselib_record_sp_cfa_base_equiv (-cfa_base_offset
+ - VTI (bb)->in.stack_adjust,
+ BB_HEAD (bb));
+ record_sp_value = true;
+
first_bb = bb;
for (;;)
{
{
if (INSN_P (insn))
{
+ HOST_WIDE_INT pre = 0, post = 0;
+
if (!frame_pointer_needed)
{
insn_stack_adjust_offset_pre_post (insn, &pre, &post);
log_op_type (PATTERN (insn), bb, insn,
MO_ADJUST, dump_file);
VTI (bb)->mos.safe_push (mo);
- VTI (bb)->out.stack_adjust += pre;
}
}
cselib_hook_called = false;
adjust_insn (bb, insn);
+
+ if (pre)
+ VTI (bb)->out.stack_adjust += pre;
+
if (DEBUG_MARKER_INSN_P (insn))
{
reemit_marker_as_note (insn);
cselib_process_insn (insn);
if (dump_file && (dump_flags & TDF_DETAILS))
{
- print_rtl_single (dump_file, insn);
+ if (dump_flags & TDF_SLIM)
+ dump_insn_slim (dump_file, insn);
+ else
+ print_rtl_single (dump_file, insn);
dump_cselib_table (dump_file);
}
}
add_with_sets (insn, 0, 0);
cancel_changes (0);
- if (!frame_pointer_needed && post)
+ if (post)
{
micro_operation mo;
mo.type = MO_ADJUST;
VTI (bb)->out.stack_adjust += post;
}
- if (fp_cfa_offset != -1
- && hard_frame_pointer_adjustment == -1
+ if (maybe_ne (fp_cfa_offset, -1)
+ && known_eq (hard_frame_pointer_adjustment, -1)
&& fp_setter_insn (insn))
{
vt_init_cfa_base ();