/* Variable tracking routines for the GNU compiler.
- Copyright (C) 2002-2013 Free Software Foundation, Inc.
+ Copyright (C) 2002-2016 Free Software Foundation, Inc.
This file is part of GCC.
#include "config.h"
#include "system.h"
#include "coretypes.h"
-#include "tm.h"
+#include "backend.h"
+#include "target.h"
#include "rtl.h"
#include "tree.h"
-#include "varasm.h"
-#include "stor-layout.h"
-#include "pointer-set.h"
-#include "hash-table.h"
-#include "basic-block.h"
+#include "cfghooks.h"
+#include "alloc-pool.h"
+#include "tree-pass.h"
#include "tm_p.h"
-#include "hard-reg-set.h"
-#include "flags.h"
#include "insn-config.h"
-#include "reload.h"
-#include "sbitmap.h"
-#include "alloc-pool.h"
-#include "fibheap.h"
#include "regs.h"
-#include "expr.h"
-#include "tree-pass.h"
-#include "bitmap.h"
+#include "emit-rtl.h"
+#include "recog.h"
+#include "diagnostic.h"
+#include "varasm.h"
+#include "stor-layout.h"
+#include "cfgrtl.h"
+#include "cfganal.h"
+#include "reload.h"
+#include "calls.h"
#include "tree-dfa.h"
#include "tree-ssa.h"
#include "cselib.h"
-#include "target.h"
#include "params.h"
-#include "diagnostic.h"
#include "tree-pretty-print.h"
-#include "recog.h"
-#include "tm_p.h"
-#include "alias.h"
+#include "rtl-iter.h"
+#include "fibonacci_heap.h"
+
+typedef fibonacci_heap <long, basic_block_def> bb_heap_t;
+typedef fibonacci_node <long, basic_block_def> bb_heap_node_t;
/* var-tracking.c assumes that tree code with the same value as VALUE rtx code
has no chance to appear in REG_EXPR/MEM_EXPRs and isn't a decl.
};
/* Structure holding information about micro operation. */
-typedef struct micro_operation_def
+struct micro_operation
{
/* Type of micro operation. */
enum micro_operation_type type;
instruction or note in the original flow (before any var-tracking
notes are inserted, to simplify emission of notes), for MO_SET
and MO_CLOBBER. */
- rtx insn;
+ rtx_insn *insn;
union {
/* Location. For MO_SET and MO_COPY, this is the SET that
/* Stack adjustment. */
HOST_WIDE_INT adjust;
} u;
-} micro_operation;
+};
/* A declaration of a variable, or an RTL value being handled like a
register is described by a chain of these structures.
The chains are pretty short (usually 1 or 2 elements) and thus
chain is the best data structure. */
-typedef struct attrs_def
+struct attrs
{
/* Pointer to next member of the list. */
- struct attrs_def *next;
+ attrs *next;
/* The rtx of register. */
rtx loc;
/* Offset from start of DECL. */
HOST_WIDE_INT offset;
-} *attrs;
+};
/* Structure for chaining the locations. */
-typedef struct location_chain_def
+struct location_chain
{
/* Next element in the chain. */
- struct location_chain_def *next;
+ location_chain *next;
/* The location (REG, MEM or VALUE). */
rtx loc;
/* Initialized? */
enum var_init_status init;
-} *location_chain;
+};
/* A vector of loc_exp_dep holds the active dependencies of a one-part
DV on VALUEs, i.e., the VALUEs expanded so as to form the current
location of DV. Each entry is also part of VALUE' s linked-list of
backlinks back to DV. */
-typedef struct loc_exp_dep_s
+struct loc_exp_dep
{
/* The dependent DV. */
decl_or_value dv;
/* The dependency VALUE or DECL_DEBUG. */
rtx value;
/* The next entry in VALUE's backlinks list. */
- struct loc_exp_dep_s *next;
+ struct loc_exp_dep *next;
/* A pointer to the pointer to this entry (head or prev's next) in
the doubly-linked list. */
- struct loc_exp_dep_s **pprev;
-} loc_exp_dep;
+ struct loc_exp_dep **pprev;
+};
/* This data structure holds information about the depth of a variable
expansion. */
-typedef struct expand_depth_struct
+struct expand_depth
{
/* This measures the complexity of the expanded expression. It
grows by one for each level of expansion that adds more than one
/* This counts the number of ENTRY_VALUE expressions in an
expansion. We want to minimize their use. */
int entryvals;
-} expand_depth;
+};
/* This data structure is allocated for one-part variables at the time
of emitting notes. */
};
/* Structure describing one part of variable. */
-typedef struct variable_part_def
+struct variable_part
{
/* Chain of locations of the part. */
- location_chain loc_chain;
+ location_chain *loc_chain;
/* Location which was last emitted to location list. */
rtx cur_loc;
/* Pointer to auxiliary data, if var->onepart and emit_notes. */
struct onepart_aux *onepaux;
} aux;
-} variable_part;
+};
/* Maximum number of location parts. */
#define MAX_VAR_PARTS 16
/* Enumeration type used to discriminate various types of one-part
variables. */
-typedef enum onepart_enum
+enum onepart_enum
{
/* Not a one-part variable. */
NOT_ONEPART = 0,
ONEPART_DEXPR = 2,
/* A VALUE. */
ONEPART_VALUE = 3
-} onepart_enum_t;
+};
/* Structure describing where the variable is located. */
-typedef struct variable_def
+struct variable
{
/* The declaration of the variable, or an RTL value being handled
like a declaration. */
/* The variable parts. */
variable_part var_part[1];
-} *variable;
-typedef const struct variable_def *const_variable;
+};
/* Pointer to the BB's information specific to variable tracking pass. */
-#define VTI(BB) ((variable_tracking_info) (BB)->aux)
+#define VTI(BB) ((variable_tracking_info *) (BB)->aux)
/* Macro to access MEM_OFFSET as an HOST_WIDE_INT. Evaluates MEM twice. */
#define INT_MEM_OFFSET(mem) (MEM_OFFSET_KNOWN_P (mem) ? MEM_OFFSET (mem) : 0)
-#if ENABLE_CHECKING && (GCC_VERSION >= 2007)
+#if CHECKING_P && (GCC_VERSION >= 2007)
/* Access VAR's Ith part's offset, checking that it's not a one-part
variable. */
#define VAR_PART_OFFSET(var, i) __extension__ \
-(*({ variable const __v = (var); \
+(*({ variable *const __v = (var); \
gcc_checking_assert (!__v->onepart); \
&__v->var_part[(i)].aux.offset; }))
/* Access VAR's one-part auxiliary data, checking that it is a
one-part variable. */
#define VAR_LOC_1PAUX(var) __extension__ \
-(*({ variable const __v = (var); \
+(*({ variable *const __v = (var); \
gcc_checking_assert (__v->onepart); \
&__v->var_part[0].aux.onepaux; }))
/* Variable hashtable helpers. */
-struct variable_hasher
+struct variable_hasher : pointer_hash <variable>
{
- typedef variable_def value_type;
- typedef void compare_type;
- static inline hashval_t hash (const value_type *);
- static inline bool equal (const value_type *, const compare_type *);
- static inline void remove (value_type *);
+ typedef void *compare_type;
+ static inline hashval_t hash (const variable *);
+ static inline bool equal (const variable *, const void *);
+ static inline void remove (variable *);
};
/* The hash function for variable_htab, computes the hash value
from the declaration of variable X. */
inline hashval_t
-variable_hasher::hash (const value_type *v)
+variable_hasher::hash (const variable *v)
{
return dv_htab_hash (v->dv);
}
/* Compare the declaration of variable X with declaration Y. */
inline bool
-variable_hasher::equal (const value_type *v, const compare_type *y)
+variable_hasher::equal (const variable *v, const void *y)
{
decl_or_value dv = CONST_CAST2 (decl_or_value, const void *, y);
/* Free the element of VARIABLE_HTAB (its type is struct variable_def). */
inline void
-variable_hasher::remove (value_type *var)
+variable_hasher::remove (variable *var)
{
variable_htab_free (var);
}
-typedef hash_table <variable_hasher> variable_table_type;
+typedef hash_table<variable_hasher> variable_table_type;
typedef variable_table_type::iterator variable_iterator_type;
/* Structure for passing some other parameters to function
emit_note_insn_var_location. */
-typedef struct emit_note_data_def
+struct emit_note_data
{
/* The instruction which the note will be emitted before/after. */
- rtx insn;
+ rtx_insn *insn;
/* Where the note will be emitted (before/after insn)? */
enum emit_note_where where;
/* The variables and values active at this point. */
- variable_table_type vars;
-} emit_note_data;
+ variable_table_type *vars;
+};
/* Structure holding a refcounted hash table. If refcount > 1,
it must be first unshared before modified. */
-typedef struct shared_hash_def
+struct shared_hash
{
/* Reference count. */
int refcount;
/* Actual hash table. */
- variable_table_type htab;
-} *shared_hash;
+ variable_table_type *htab;
+};
/* Structure holding the IN or OUT set for a basic block. */
-typedef struct dataflow_set_def
+struct dataflow_set
{
/* Adjustment of stack offset. */
HOST_WIDE_INT stack_adjust;
/* Attributes for registers (lists of attrs). */
- attrs regs[FIRST_PSEUDO_REGISTER];
+ attrs *regs[FIRST_PSEUDO_REGISTER];
/* Variable locations. */
- shared_hash vars;
+ shared_hash *vars;
/* Vars that is being traversed. */
- shared_hash traversed_vars;
-} dataflow_set;
+ shared_hash *traversed_vars;
+};
/* The structure (one for each basic block) containing the information
needed for variable tracking. */
-typedef struct variable_tracking_info_def
+struct variable_tracking_info
{
/* The vector of micro operations. */
vec<micro_operation> mos;
/* Has the block been flooded in VTA? */
bool flooded;
-} *variable_tracking_info;
+};
/* Alloc pool for struct attrs_def. */
-static alloc_pool attrs_pool;
+object_allocator<attrs> attrs_pool ("attrs pool");
/* Alloc pool for struct variable_def with MAX_VAR_PARTS entries. */
-static alloc_pool var_pool;
+
+static pool_allocator var_pool
+ ("variable_def pool", sizeof (variable) +
+ (MAX_VAR_PARTS - 1) * sizeof (((variable *)NULL)->var_part[0]));
/* Alloc pool for struct variable_def with a single var_part entry. */
-static alloc_pool valvar_pool;
+static pool_allocator valvar_pool
+ ("small variable_def pool", sizeof (variable));
-/* Alloc pool for struct location_chain_def. */
-static alloc_pool loc_chain_pool;
+/* Alloc pool for struct location_chain. */
+static object_allocator<location_chain> location_chain_pool
+ ("location_chain pool");
-/* Alloc pool for struct shared_hash_def. */
-static alloc_pool shared_hash_pool;
+/* Alloc pool for struct shared_hash. */
+static object_allocator<shared_hash> shared_hash_pool ("shared_hash pool");
/* Alloc pool for struct loc_exp_dep_s for NOT_ONEPART variables. */
-static alloc_pool loc_exp_dep_pool;
+object_allocator<loc_exp_dep> loc_exp_dep_pool ("loc_exp_dep pool");
/* Changed variables, notes will be emitted for them. */
-static variable_table_type changed_variables;
+static variable_table_type *changed_variables;
/* Shall notes be emitted? */
static bool emit_notes;
/* Values whose dynamic location lists have gone empty, but whose
cselib location lists are still usable. Use this to hold the
current location, the backlinks, etc, during emit_notes. */
-static variable_table_type dropped_values;
+static variable_table_type *dropped_values;
/* Empty shared hashtable. */
-static shared_hash empty_shared_hash;
+static shared_hash *empty_shared_hash;
/* Scratch register bitmap used by cselib_expand_value_rtx. */
static bitmap scratch_regs = NULL;
#ifdef HAVE_window_save
-typedef struct GTY(()) parm_reg {
+struct GTY(()) parm_reg {
rtx outgoing;
rtx incoming;
-} parm_reg_t;
+};
/* Vector of windowed parameter registers, if any. */
-static vec<parm_reg_t, va_gc> *windowed_parm_regs = NULL;
+static vec<parm_reg, va_gc> *windowed_parm_regs = NULL;
#endif
/* Variable used to tell whether cselib_process_insn called our hook. */
/* Local function prototypes. */
static void stack_adjust_offset_pre_post (rtx, HOST_WIDE_INT *,
HOST_WIDE_INT *);
-static void insn_stack_adjust_offset_pre_post (rtx, HOST_WIDE_INT *,
+static void insn_stack_adjust_offset_pre_post (rtx_insn *, HOST_WIDE_INT *,
HOST_WIDE_INT *);
static bool vt_stack_adjustments (void);
-static void init_attrs_list_set (attrs *);
-static void attrs_list_clear (attrs *);
-static attrs attrs_list_member (attrs, decl_or_value, HOST_WIDE_INT);
-static void attrs_list_insert (attrs *, decl_or_value, HOST_WIDE_INT, rtx);
-static void attrs_list_copy (attrs *, attrs);
-static void attrs_list_union (attrs *, attrs);
+static void init_attrs_list_set (attrs **);
+static void attrs_list_clear (attrs **);
+static attrs *attrs_list_member (attrs *, decl_or_value, HOST_WIDE_INT);
+static void attrs_list_insert (attrs **, decl_or_value, HOST_WIDE_INT, rtx);
+static void attrs_list_copy (attrs **, attrs *);
+static void attrs_list_union (attrs **, attrs *);
-static variable_def **unshare_variable (dataflow_set *set, variable_def **slot,
- variable var, enum var_init_status);
-static void vars_copy (variable_table_type, variable_table_type);
+static variable **unshare_variable (dataflow_set *set, variable **slot,
+ variable *var, enum var_init_status);
+static void vars_copy (variable_table_type *, variable_table_type *);
static tree var_debug_decl (tree);
static void var_reg_set (dataflow_set *, rtx, enum var_init_status, rtx);
static void var_reg_delete_and_set (dataflow_set *, rtx, bool,
static void dataflow_set_copy (dataflow_set *, dataflow_set *);
static int variable_union_info_cmp_pos (const void *, const void *);
static void dataflow_set_union (dataflow_set *, dataflow_set *);
-static location_chain find_loc_in_1pdv (rtx, variable, variable_table_type);
+static location_chain *find_loc_in_1pdv (rtx, variable *,
+ variable_table_type *);
static bool canon_value_cmp (rtx, rtx);
static int loc_cmp (rtx, rtx);
static bool variable_part_different_p (variable_part *, variable_part *);
-static bool onepart_variable_different_p (variable, variable);
-static bool variable_different_p (variable, variable);
+static bool onepart_variable_different_p (variable *, variable *);
+static bool variable_different_p (variable *, variable *);
static bool dataflow_set_different (dataflow_set *, dataflow_set *);
static void dataflow_set_destroy (dataflow_set *);
-static bool contains_symbol_ref (rtx);
static bool track_expr_p (tree, bool);
static bool same_variable_part_p (rtx, tree, HOST_WIDE_INT);
-static int add_uses (rtx *, void *);
static void add_uses_1 (rtx *, void *);
static void add_stores (rtx, const_rtx, void *);
static bool compute_bb_dataflow (basic_block);
static bool vt_find_locations (void);
-static void dump_attrs_list (attrs);
-static void dump_var (variable);
-static void dump_vars (variable_table_type);
+static void dump_attrs_list (attrs *);
+static void dump_var (variable *);
+static void dump_vars (variable_table_type *);
static void dump_dataflow_set (dataflow_set *);
static void dump_dataflow_sets (void);
static void set_dv_changed (decl_or_value, bool);
-static void variable_was_changed (variable, dataflow_set *);
-static variable_def **set_slot_part (dataflow_set *, rtx, variable_def **,
- decl_or_value, HOST_WIDE_INT,
- enum var_init_status, rtx);
+static void variable_was_changed (variable *, dataflow_set *);
+static variable **set_slot_part (dataflow_set *, rtx, variable **,
+ decl_or_value, HOST_WIDE_INT,
+ enum var_init_status, rtx);
static void set_variable_part (dataflow_set *, rtx,
decl_or_value, HOST_WIDE_INT,
enum var_init_status, rtx, enum insert_option);
-static variable_def **clobber_slot_part (dataflow_set *, rtx,
- variable_def **, HOST_WIDE_INT, rtx);
+static variable **clobber_slot_part (dataflow_set *, rtx,
+ variable **, HOST_WIDE_INT, rtx);
static void clobber_variable_part (dataflow_set *, rtx,
decl_or_value, HOST_WIDE_INT, rtx);
-static variable_def **delete_slot_part (dataflow_set *, rtx, variable_def **,
- HOST_WIDE_INT);
+static variable **delete_slot_part (dataflow_set *, rtx, variable **,
+ HOST_WIDE_INT);
static void delete_variable_part (dataflow_set *, rtx,
decl_or_value, HOST_WIDE_INT);
static void emit_notes_in_bb (basic_block, dataflow_set *);
static bool vt_initialize (void);
static void vt_finalize (void);
+/* Callback for stack_adjust_offset_pre_post, called via for_each_inc_dec. */
+
+static int
+stack_adjust_offset_pre_post_cb (rtx, rtx op, rtx dest, rtx src, rtx srcoff,
+ void *arg)
+{
+ if (dest != stack_pointer_rtx)
+ return 0;
+
+ switch (GET_CODE (op))
+ {
+ case PRE_INC:
+ case PRE_DEC:
+ ((HOST_WIDE_INT *)arg)[0] -= INTVAL (srcoff);
+ return 0;
+ case POST_INC:
+ case POST_DEC:
+ ((HOST_WIDE_INT *)arg)[1] -= INTVAL (srcoff);
+ return 0;
+ case PRE_MODIFY:
+ case POST_MODIFY:
+ /* We handle only adjustments by constant amount. */
+ gcc_assert (GET_CODE (src) == PLUS
+ && CONST_INT_P (XEXP (src, 1))
+ && XEXP (src, 0) == stack_pointer_rtx);
+ ((HOST_WIDE_INT *)arg)[GET_CODE (op) == POST_MODIFY]
+ -= INTVAL (XEXP (src, 1));
+ return 0;
+ default:
+ gcc_unreachable ();
+ }
+}
+
/* Given a SET, calculate the amount of stack adjustment it contains
PRE- and POST-modifying stack pointer.
This function is similar to stack_adjust_offset. */
*post += INTVAL (XEXP (src, 1));
else
*post -= INTVAL (XEXP (src, 1));
+ return;
}
- else if (MEM_P (dest))
- {
- /* (set (mem (pre_dec (reg sp))) (foo)) */
- src = XEXP (dest, 0);
- code = GET_CODE (src);
-
- switch (code)
- {
- case PRE_MODIFY:
- case POST_MODIFY:
- if (XEXP (src, 0) == stack_pointer_rtx)
- {
- rtx val = XEXP (XEXP (src, 1), 1);
- /* We handle only adjustments by constant amount. */
- gcc_assert (GET_CODE (XEXP (src, 1)) == PLUS &&
- CONST_INT_P (val));
-
- if (code == PRE_MODIFY)
- *pre -= INTVAL (val);
- else
- *post -= INTVAL (val);
- break;
- }
- return;
-
- case PRE_DEC:
- if (XEXP (src, 0) == stack_pointer_rtx)
- {
- *pre += GET_MODE_SIZE (GET_MODE (dest));
- break;
- }
- return;
-
- case POST_DEC:
- if (XEXP (src, 0) == stack_pointer_rtx)
- {
- *post += GET_MODE_SIZE (GET_MODE (dest));
- break;
- }
- return;
-
- case PRE_INC:
- if (XEXP (src, 0) == stack_pointer_rtx)
- {
- *pre -= GET_MODE_SIZE (GET_MODE (dest));
- break;
- }
- return;
-
- case POST_INC:
- if (XEXP (src, 0) == stack_pointer_rtx)
- {
- *post -= GET_MODE_SIZE (GET_MODE (dest));
- break;
- }
- return;
-
- default:
- return;
- }
- }
+ HOST_WIDE_INT res[2] = { 0, 0 };
+ for_each_inc_dec (pattern, stack_adjust_offset_pre_post_cb, res);
+ *pre += res[0];
+ *post += res[1];
}
/* Given an INSN, calculate the amount of stack adjustment it contains
PRE- and POST-modifying stack pointer. */
static void
-insn_stack_adjust_offset_pre_post (rtx insn, HOST_WIDE_INT *pre,
+insn_stack_adjust_offset_pre_post (rtx_insn *insn, HOST_WIDE_INT *pre,
HOST_WIDE_INT *post)
{
rtx pattern;
/* Initialize entry block. */
VTI (ENTRY_BLOCK_PTR_FOR_FN (cfun))->visited = true;
- VTI (ENTRY_BLOCK_PTR_FOR_FN (cfun))->in.stack_adjust =
- INCOMING_FRAME_SP_OFFSET;
- VTI (ENTRY_BLOCK_PTR_FOR_FN (cfun))->out.stack_adjust =
- INCOMING_FRAME_SP_OFFSET;
+ VTI (ENTRY_BLOCK_PTR_FOR_FN (cfun))->in.stack_adjust
+ = INCOMING_FRAME_SP_OFFSET;
+ VTI (ENTRY_BLOCK_PTR_FOR_FN (cfun))->out.stack_adjust
+ = INCOMING_FRAME_SP_OFFSET;
/* Allocate stack for back-tracking up CFG. */
stack = XNEWVEC (edge_iterator, n_basic_blocks_for_fn (cfun) + 1);
/* Check if the edge destination has been visited yet. */
if (!VTI (dest)->visited)
{
- rtx insn;
+ rtx_insn *insn;
HOST_WIDE_INT pre, post, offset;
VTI (dest)->visited = true;
VTI (dest)->in.stack_adjust = offset = VTI (src)->out.stack_adjust;
}
else
{
- /* Check whether the adjustments on the edges are the same. */
- if (VTI (dest)->in.stack_adjust != VTI (src)->out.stack_adjust)
+ /* We can end up with different stack adjustments for the exit block
+ of a shrink-wrapped function if stack_adjust_offset_pre_post
+ doesn't understand the rtx pattern used to restore the stack
+ pointer in the epilogue. For example, on s390(x), the stack
+ pointer is often restored via a load-multiple instruction
+ and so no stack_adjust offset is recorded for it. This means
+ that the stack offset at the end of the epilogue block is the
+ same as the offset before the epilogue, whereas other paths
+ to the exit block will have the correct stack_adjust.
+
+ It is safe to ignore these differences because (a) we never
+ use the stack_adjust for the exit block in this pass and
+ (b) dwarf2cfi checks whether the CFA notes in a shrink-wrapped
+ function are correct.
+
+ We must check whether the adjustments on other edges are
+ the same though. */
+ if (dest != EXIT_BLOCK_PTR_FOR_FN (cfun)
+ && VTI (dest)->in.stack_adjust != VTI (src)->out.stack_adjust)
{
free (stack);
return false;
struct adjust_mem_data
{
bool store;
- enum machine_mode mem_mode;
+ machine_mode mem_mode;
HOST_WIDE_INT stack_adjust;
- rtx side_effects;
+ rtx_expr_list *side_effects;
};
-/* Helper for adjust_mems. Return 1 if *loc is unsuitable for
- transformation of wider mode arithmetics to narrower mode,
- -1 if it is suitable and subexpressions shouldn't be
- traversed and 0 if it is suitable and subexpressions should
- be traversed. Called through for_each_rtx. */
+/* Helper for adjust_mems. Return true if X is suitable for
+ transformation of wider mode arithmetics to narrower mode. */
-static int
-use_narrower_mode_test (rtx *loc, void *data)
+static bool
+use_narrower_mode_test (rtx x, const_rtx subreg)
{
- rtx subreg = (rtx) data;
-
- if (CONSTANT_P (*loc))
- return -1;
- switch (GET_CODE (*loc))
+ subrtx_var_iterator::array_type array;
+ FOR_EACH_SUBRTX_VAR (iter, array, x, NONCONST)
{
- 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:
- case MULT:
- return 0;
- case ASHIFT:
- if (for_each_rtx (&XEXP (*loc, 0), use_narrower_mode_test, data))
- return 1;
+ rtx x = *iter;
+ if (CONSTANT_P (x))
+ iter.skip_subrtxes ();
else
- return -1;
- default:
- return 1;
+ switch (GET_CODE (x))
+ {
+ case REG:
+ if (cselib_lookup (x, GET_MODE (SUBREG_REG (subreg)), 0, VOIDmode))
+ return false;
+ if (!validate_subreg (GET_MODE (subreg), GET_MODE (x), x,
+ subreg_lowpart_offset (GET_MODE (subreg),
+ GET_MODE (x))))
+ return false;
+ break;
+ case PLUS:
+ case MINUS:
+ case MULT:
+ break;
+ case ASHIFT:
+ iter.substitute (XEXP (x, 0));
+ break;
+ default:
+ return false;
+ }
}
+ return true;
}
/* Transform X into narrower mode MODE from wider mode WMODE. */
static rtx
-use_narrower_mode (rtx x, enum machine_mode mode, enum machine_mode wmode)
+use_narrower_mode (rtx x, machine_mode mode, machine_mode wmode)
{
rtx op0, op1;
if (CONSTANT_P (x))
return simplify_gen_binary (GET_CODE (x), mode, op0, op1);
case ASHIFT:
op0 = use_narrower_mode (XEXP (x, 0), mode, wmode);
- return simplify_gen_binary (ASHIFT, mode, op0, XEXP (x, 1));
+ op1 = XEXP (x, 1);
+ /* Ensure shift amount is not wider than mode. */
+ if (GET_MODE (op1) == VOIDmode)
+ op1 = lowpart_subreg (mode, op1, wmode);
+ else if (GET_MODE_PRECISION (mode) < GET_MODE_PRECISION (GET_MODE (op1)))
+ op1 = lowpart_subreg (mode, op1, GET_MODE (op1));
+ return simplify_gen_binary (ASHIFT, mode, op0, op1);
default:
gcc_unreachable ();
}
{
struct adjust_mem_data *amd = (struct adjust_mem_data *) data;
rtx mem, addr = loc, tem;
- enum machine_mode mem_mode_save;
+ machine_mode mem_mode_save;
bool store_save;
switch (GET_CODE (loc))
{
? GET_MODE_SIZE (amd->mem_mode)
: -GET_MODE_SIZE (amd->mem_mode),
GET_MODE (loc)));
+ store_save = amd->store;
+ amd->store = false;
+ tem = simplify_replace_fn_rtx (tem, old_rtx, adjust_mems, data);
+ amd->store = store_save;
amd->side_effects = alloc_EXPR_LIST (0,
- gen_rtx_SET (VOIDmode,
- XEXP (loc, 0),
- tem),
+ gen_rtx_SET (XEXP (loc, 0), tem),
amd->side_effects);
return addr;
case PRE_MODIFY:
addr = XEXP (loc, 0);
gcc_assert (amd->mem_mode != VOIDmode);
addr = simplify_replace_fn_rtx (addr, old_rtx, adjust_mems, data);
+ store_save = amd->store;
+ amd->store = false;
+ tem = simplify_replace_fn_rtx (XEXP (loc, 1), old_rtx,
+ adjust_mems, data);
+ amd->store = store_save;
amd->side_effects = alloc_EXPR_LIST (0,
- gen_rtx_SET (VOIDmode,
- XEXP (loc, 0),
- XEXP (loc, 1)),
+ gen_rtx_SET (XEXP (loc, 0), tem),
amd->side_effects);
return addr;
case SUBREG:
|| GET_CODE (SUBREG_REG (tem)) == MINUS
|| GET_CODE (SUBREG_REG (tem)) == MULT
|| GET_CODE (SUBREG_REG (tem)) == ASHIFT)
- && GET_MODE_CLASS (GET_MODE (tem)) == MODE_INT
- && GET_MODE_CLASS (GET_MODE (SUBREG_REG (tem))) == MODE_INT
- && GET_MODE_SIZE (GET_MODE (tem))
- < GET_MODE_SIZE (GET_MODE (SUBREG_REG (tem)))
+ && (GET_MODE_CLASS (GET_MODE (tem)) == MODE_INT
+ || GET_MODE_CLASS (GET_MODE (tem)) == MODE_PARTIAL_INT)
+ && (GET_MODE_CLASS (GET_MODE (SUBREG_REG (tem))) == MODE_INT
+ || GET_MODE_CLASS (GET_MODE (SUBREG_REG (tem))) == MODE_PARTIAL_INT)
+ && GET_MODE_PRECISION (GET_MODE (tem))
+ < GET_MODE_PRECISION (GET_MODE (SUBREG_REG (tem)))
&& subreg_lowpart_p (tem)
- && !for_each_rtx (&SUBREG_REG (tem), use_narrower_mode_test, tem))
+ && use_narrower_mode_test (SUBREG_REG (tem), tem))
return use_narrower_mode (SUBREG_REG (tem), GET_MODE (tem),
GET_MODE (SUBREG_REG (tem)));
return tem;
as other sets to the insn. */
static void
-adjust_insn (basic_block bb, rtx insn)
+adjust_insn (basic_block bb, rtx_insn *insn)
{
struct adjust_mem_data amd;
rtx set;
{
unsigned int i, nregs = vec_safe_length (windowed_parm_regs);
rtx rtl = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (nregs * 2));
- parm_reg_t *p;
+ parm_reg *p;
FOR_EACH_VEC_SAFE_ELT (windowed_parm_regs, i, p)
{
XVECEXP (rtl, 0, i * 2)
- = gen_rtx_SET (VOIDmode, p->incoming, p->outgoing);
+ = gen_rtx_SET (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),
amd.mem_mode = VOIDmode;
amd.stack_adjust = -VTI (bb)->out.stack_adjust;
- amd.side_effects = NULL_RTX;
+ amd.side_effects = NULL;
amd.store = true;
note_stores (PATTERN (insn), adjust_mem_stores, &amd);
/* Return nonzero if a decl_or_value must not have more than one
variable part. The returned value discriminates among various
kinds of one-part DVs ccording to enum onepart_enum. */
-static inline onepart_enum_t
+static inline onepart_enum
dv_onepart_p (decl_or_value dv)
{
tree decl;
}
/* Return the variable pool to be used for a dv of type ONEPART. */
-static inline alloc_pool
-onepart_pool (onepart_enum_t onepart)
+static inline pool_allocator &
+onepart_pool (onepart_enum onepart)
{
return onepart ? valvar_pool : var_pool;
}
+/* Allocate a variable_def from the corresponding variable pool. */
+static inline variable *
+onepart_pool_allocate (onepart_enum onepart)
+{
+ return (variable*) onepart_pool (onepart).allocate ();
+}
+
/* Build a decl_or_value out of a decl. */
static inline decl_or_value
dv_from_decl (tree decl)
debug_generic_stmt (dv_as_decl (dv));
}
-static void loc_exp_dep_clear (variable var);
+static void loc_exp_dep_clear (variable *var);
/* Free the element of VARIABLE_HTAB (its type is struct variable_def). */
variable_htab_free (void *elem)
{
int i;
- variable var = (variable) elem;
- location_chain node, next;
+ variable *var = (variable *) elem;
+ location_chain *node, *next;
gcc_checking_assert (var->refcount > 0);
for (node = var->var_part[i].loc_chain; node; node = next)
{
next = node->next;
- pool_free (loc_chain_pool, node);
+ delete node;
}
var->var_part[i].loc_chain = NULL;
}
if (var->onepart == ONEPART_DEXPR)
set_dv_changed (var->dv, true);
}
- pool_free (onepart_pool (var->onepart), var);
+ onepart_pool (var->onepart).remove (var);
}
/* Initialize the set (array) SET of attrs to empty lists. */
static void
-init_attrs_list_set (attrs *set)
+init_attrs_list_set (attrs **set)
{
int i;
/* Make the list *LISTP empty. */
static void
-attrs_list_clear (attrs *listp)
+attrs_list_clear (attrs **listp)
{
- attrs list, next;
+ attrs *list, *next;
for (list = *listp; list; list = next)
{
next = list->next;
- pool_free (attrs_pool, list);
+ delete list;
}
*listp = NULL;
}
/* Return true if the pair of DECL and OFFSET is the member of the LIST. */
-static attrs
-attrs_list_member (attrs list, decl_or_value dv, HOST_WIDE_INT offset)
+static attrs *
+attrs_list_member (attrs *list, decl_or_value dv, HOST_WIDE_INT offset)
{
for (; list; list = list->next)
if (dv_as_opaque (list->dv) == dv_as_opaque (dv) && list->offset == offset)
/* Insert the triplet DECL, OFFSET, LOC to the list *LISTP. */
static void
-attrs_list_insert (attrs *listp, decl_or_value dv,
+attrs_list_insert (attrs **listp, decl_or_value dv,
HOST_WIDE_INT offset, rtx loc)
{
- attrs list;
-
- list = (attrs) pool_alloc (attrs_pool);
+ attrs *list = new attrs;
list->loc = loc;
list->dv = dv;
list->offset = offset;
/* Copy all nodes from SRC and create a list *DSTP of the copies. */
static void
-attrs_list_copy (attrs *dstp, attrs src)
+attrs_list_copy (attrs **dstp, attrs *src)
{
- attrs n;
-
attrs_list_clear (dstp);
for (; src; src = src->next)
{
- n = (attrs) pool_alloc (attrs_pool);
+ attrs *n = new attrs;
n->loc = src->loc;
n->dv = src->dv;
n->offset = src->offset;
/* Add all nodes from SRC which are not in *DSTP to *DSTP. */
static void
-attrs_list_union (attrs *dstp, attrs src)
+attrs_list_union (attrs **dstp, attrs *src)
{
for (; src; src = src->next)
{
*DSTP. */
static void
-attrs_list_mpdv_union (attrs *dstp, attrs src, attrs src2)
+attrs_list_mpdv_union (attrs **dstp, attrs *src, attrs *src2)
{
gcc_assert (!*dstp);
for (; src; src = src->next)
/* Return true if VARS is shared. */
static inline bool
-shared_hash_shared (shared_hash vars)
+shared_hash_shared (shared_hash *vars)
{
return vars->refcount > 1;
}
/* Return the hash table for VARS. */
-static inline variable_table_type
-shared_hash_htab (shared_hash vars)
+static inline variable_table_type *
+shared_hash_htab (shared_hash *vars)
{
return vars->htab;
}
/* Return true if VAR is shared, or maybe because VARS is shared. */
static inline bool
-shared_var_p (variable var, shared_hash vars)
+shared_var_p (variable *var, shared_hash *vars)
{
/* Don't count an entry in the changed_variables table as a duplicate. */
return ((var->refcount > 1 + (int) var->in_changed_variables)
/* Copy variables into a new hash table. */
-static shared_hash
-shared_hash_unshare (shared_hash vars)
+static shared_hash *
+shared_hash_unshare (shared_hash *vars)
{
- shared_hash new_vars = (shared_hash) pool_alloc (shared_hash_pool);
+ shared_hash *new_vars = new shared_hash;
gcc_assert (vars->refcount > 1);
new_vars->refcount = 1;
- new_vars->htab.create (vars->htab.elements () + 3);
+ new_vars->htab = new variable_table_type (vars->htab->elements () + 3);
vars_copy (new_vars->htab, vars->htab);
vars->refcount--;
return new_vars;
/* Increment reference counter on VARS and return it. */
-static inline shared_hash
-shared_hash_copy (shared_hash vars)
+static inline shared_hash *
+shared_hash_copy (shared_hash *vars)
{
vars->refcount++;
return vars;
anymore. */
static void
-shared_hash_destroy (shared_hash vars)
+shared_hash_destroy (shared_hash *vars)
{
gcc_checking_assert (vars->refcount > 0);
if (--vars->refcount == 0)
{
- vars->htab.dispose ();
- pool_free (shared_hash_pool, vars);
+ delete vars->htab;
+ delete vars;
}
}
/* Unshare *PVARS if shared and return slot for DV. If INS is
INSERT, insert it if not already present. */
-static inline variable_def **
-shared_hash_find_slot_unshare_1 (shared_hash *pvars, decl_or_value dv,
+static inline variable **
+shared_hash_find_slot_unshare_1 (shared_hash **pvars, decl_or_value dv,
hashval_t dvhash, enum insert_option ins)
{
if (shared_hash_shared (*pvars))
*pvars = shared_hash_unshare (*pvars);
- return shared_hash_htab (*pvars).find_slot_with_hash (dv, dvhash, ins);
+ return shared_hash_htab (*pvars)->find_slot_with_hash (dv, dvhash, ins);
}
-static inline variable_def **
-shared_hash_find_slot_unshare (shared_hash *pvars, decl_or_value dv,
+static inline variable **
+shared_hash_find_slot_unshare (shared_hash **pvars, decl_or_value dv,
enum insert_option ins)
{
return shared_hash_find_slot_unshare_1 (pvars, dv, dv_htab_hash (dv), ins);
If it is not present, insert it only VARS is not shared, otherwise
return NULL. */
-static inline variable_def **
-shared_hash_find_slot_1 (shared_hash vars, decl_or_value dv, hashval_t dvhash)
+static inline variable **
+shared_hash_find_slot_1 (shared_hash *vars, decl_or_value dv, hashval_t dvhash)
{
- return shared_hash_htab (vars).find_slot_with_hash (dv, dvhash,
- shared_hash_shared (vars)
- ? NO_INSERT : INSERT);
+ return shared_hash_htab (vars)->find_slot_with_hash (dv, dvhash,
+ shared_hash_shared (vars)
+ ? NO_INSERT : INSERT);
}
-static inline variable_def **
-shared_hash_find_slot (shared_hash vars, decl_or_value dv)
+static inline variable **
+shared_hash_find_slot (shared_hash *vars, decl_or_value dv)
{
return shared_hash_find_slot_1 (vars, dv, dv_htab_hash (dv));
}
/* Return slot for DV only if it is already present in the hash table. */
-static inline variable_def **
-shared_hash_find_slot_noinsert_1 (shared_hash vars, decl_or_value dv,
+static inline variable **
+shared_hash_find_slot_noinsert_1 (shared_hash *vars, decl_or_value dv,
hashval_t dvhash)
{
- return shared_hash_htab (vars).find_slot_with_hash (dv, dvhash, NO_INSERT);
+ return shared_hash_htab (vars)->find_slot_with_hash (dv, dvhash, NO_INSERT);
}
-static inline variable_def **
-shared_hash_find_slot_noinsert (shared_hash vars, decl_or_value dv)
+static inline variable **
+shared_hash_find_slot_noinsert (shared_hash *vars, decl_or_value dv)
{
return shared_hash_find_slot_noinsert_1 (vars, dv, dv_htab_hash (dv));
}
/* Return variable for DV or NULL if not already present in the hash
table. */
-static inline variable
-shared_hash_find_1 (shared_hash vars, decl_or_value dv, hashval_t dvhash)
+static inline variable *
+shared_hash_find_1 (shared_hash *vars, decl_or_value dv, hashval_t dvhash)
{
- return shared_hash_htab (vars).find_with_hash (dv, dvhash);
+ return shared_hash_htab (vars)->find_with_hash (dv, dvhash);
}
-static inline variable
-shared_hash_find (shared_hash vars, decl_or_value dv)
+static inline variable *
+shared_hash_find (shared_hash *vars, decl_or_value dv)
{
return shared_hash_find_1 (vars, dv, dv_htab_hash (dv));
}
/* Return a copy of a variable VAR and insert it to dataflow set SET. */
-static variable_def **
-unshare_variable (dataflow_set *set, variable_def **slot, variable var,
+static variable **
+unshare_variable (dataflow_set *set, variable **slot, variable *var,
enum var_init_status initialized)
{
- variable new_var;
+ variable *new_var;
int i;
- new_var = (variable) pool_alloc (onepart_pool (var->onepart));
+ new_var = onepart_pool_allocate (var->onepart);
new_var->dv = var->dv;
new_var->refcount = 1;
var->refcount--;
for (i = 0; i < var->n_var_parts; i++)
{
- location_chain node;
- location_chain *nextp;
+ location_chain *node;
+ location_chain **nextp;
if (i == 0 && var->onepart)
{
nextp = &new_var->var_part[i].loc_chain;
for (node = var->var_part[i].loc_chain; node; node = node->next)
{
- location_chain new_lc;
+ location_chain *new_lc;
- new_lc = (location_chain) pool_alloc (loc_chain_pool);
+ new_lc = new location_chain;
new_lc->next = NULL;
if (node->init > initialized)
new_lc->init = node->init;
*slot = new_var;
if (var->in_changed_variables)
{
- variable_def **cslot
- = changed_variables.find_slot_with_hash (var->dv,
- dv_htab_hash (var->dv), NO_INSERT);
+ variable **cslot
+ = changed_variables->find_slot_with_hash (var->dv,
+ dv_htab_hash (var->dv),
+ NO_INSERT);
gcc_assert (*cslot == (void *) var);
var->in_changed_variables = false;
variable_htab_free (var);
/* Copy all variables from hash table SRC to hash table DST. */
static void
-vars_copy (variable_table_type dst, variable_table_type src)
+vars_copy (variable_table_type *dst, variable_table_type *src)
{
variable_iterator_type hi;
- variable var;
+ variable *var;
- FOR_EACH_HASH_TABLE_ELEMENT (src, var, variable, hi)
+ FOR_EACH_HASH_TABLE_ELEMENT (*src, var, variable, hi)
{
- variable_def **dstp;
+ variable **dstp;
var->refcount++;
- dstp = dst.find_slot_with_hash (var->dv, dv_htab_hash (var->dv), INSERT);
+ dstp = dst->find_slot_with_hash (var->dv, dv_htab_hash (var->dv),
+ INSERT);
*dstp = var;
}
}
decl_or_value dv, HOST_WIDE_INT offset, rtx set_src,
enum insert_option iopt)
{
- attrs node;
+ attrs *node;
bool decl_p = dv_is_decl_p (dv);
if (decl_p)
static enum var_init_status
get_init_value (dataflow_set *set, rtx loc, decl_or_value dv)
{
- variable var;
+ variable *var;
int i;
enum var_init_status ret_val = VAR_INIT_STATUS_UNKNOWN;
{
for (i = 0; i < var->n_var_parts && ret_val == VAR_INIT_STATUS_UNKNOWN; i++)
{
- location_chain nextp;
+ location_chain *nextp;
for (nextp = var->var_part[i].loc_chain; nextp; nextp = nextp->next)
if (rtx_equal_p (nextp->loc, loc))
{
{
tree decl = REG_EXPR (loc);
HOST_WIDE_INT offset = REG_OFFSET (loc);
- attrs node, next;
- attrs *nextp;
+ attrs *node, *next;
+ attrs **nextp;
decl = var_debug_decl (decl);
if (dv_as_opaque (node->dv) != decl || node->offset != offset)
{
delete_variable_part (set, node->loc, node->dv, node->offset);
- pool_free (attrs_pool, node);
+ delete node;
*nextp = next;
}
else
static void
var_reg_delete (dataflow_set *set, rtx loc, bool clobber)
{
- attrs *nextp = &set->regs[REGNO (loc)];
- attrs node, next;
+ attrs **nextp = &set->regs[REGNO (loc)];
+ attrs *node, *next;
if (clobber)
{
if (clobber || !dv_onepart_p (node->dv))
{
delete_variable_part (set, node->loc, node->dv, node->offset);
- pool_free (attrs_pool, node);
+ delete node;
*nextp = next;
}
else
static void
var_regno_delete (dataflow_set *set, int regno)
{
- attrs *reg = &set->regs[regno];
- attrs node, next;
+ attrs **reg = &set->regs[regno];
+ attrs *node, *next;
for (node = *reg; node; node = next)
{
next = node->next;
delete_variable_part (set, node->loc, node->dv, node->offset);
- pool_free (attrs_pool, node);
+ delete node;
}
*reg = NULL;
}
/* This caches canonicalized addresses for VALUEs, computed using
information in the global cselib table. */
-static struct pointer_map_t *global_get_addr_cache;
+static hash_map<rtx, rtx> *global_get_addr_cache;
/* This caches canonicalized addresses for VALUEs, computed using
information from the global cache and information pertaining to a
basic block being analyzed. */
-static struct pointer_map_t *local_get_addr_cache;
+static hash_map<rtx, rtx> *local_get_addr_cache;
static rtx vt_canonicalize_addr (dataflow_set *, rtx);
get_addr_from_global_cache (rtx const loc)
{
rtx x;
- void **slot;
gcc_checking_assert (GET_CODE (loc) == VALUE);
-
- slot = pointer_map_insert (global_get_addr_cache, loc);
- if (*slot)
- return (rtx)*slot;
+
+ bool existed;
+ rtx *slot = &global_get_addr_cache->get_or_insert (loc, &existed);
+ if (existed)
+ return *slot;
x = canon_rtx (get_addr (loc));
{
/* The table may have moved during recursion, recompute
SLOT. */
- slot = pointer_map_contains (global_get_addr_cache, loc);
- *slot = x = nx;
+ *global_get_addr_cache->get (loc) = x = nx;
}
}
get_addr_from_local_cache (dataflow_set *set, rtx const loc)
{
rtx x;
- void **slot;
decl_or_value dv;
- variable var;
- location_chain l;
+ variable *var;
+ location_chain *l;
gcc_checking_assert (GET_CODE (loc) == VALUE);
-
- slot = pointer_map_insert (local_get_addr_cache, loc);
- if (*slot)
- return (rtx)*slot;
+
+ bool existed;
+ rtx *slot = &local_get_addr_cache->get_or_insert (loc, &existed);
+ if (existed)
+ return *slot;
x = get_addr_from_global_cache (loc);
-
+
/* Tentative, avoiding infinite recursion. */
*slot = x;
rtx nx = vt_canonicalize_addr (set, x);
if (nx != x)
{
- slot = pointer_map_contains (local_get_addr_cache, loc);
+ slot = local_get_addr_cache->get (loc);
*slot = x = nx;
}
return x;
rtx nx = vt_canonicalize_addr (set, l->loc);
if (x != nx)
{
- slot = pointer_map_contains (local_get_addr_cache, loc);
+ slot = local_get_addr_cache->get (loc);
*slot = x = nx;
}
break;
vt_canonicalize_addr (dataflow_set *set, rtx oloc)
{
HOST_WIDE_INT ofst = 0;
- enum machine_mode mode = GET_MODE (oloc);
+ machine_mode mode = GET_MODE (oloc);
rtx loc = oloc;
rtx x;
bool retry = true;
};
/* Remove all MEMs that overlap with COMS->LOC from the location list
- of a hash table entry for a value. COMS->ADDR must be a
+ of a hash table entry for a onepart variable. COMS->ADDR must be a
canonicalized form of COMS->LOC's address, and COMS->LOC must be
canonicalized itself. */
int
-drop_overlapping_mem_locs (variable_def **slot, overlapping_mems *coms)
+drop_overlapping_mem_locs (variable **slot, overlapping_mems *coms)
{
dataflow_set *set = coms->set;
rtx mloc = coms->loc, addr = coms->addr;
- variable var = *slot;
+ variable *var = *slot;
- if (var->onepart == ONEPART_VALUE)
+ if (var->onepart != NOT_ONEPART)
{
- location_chain loc, *locp;
+ location_chain *loc, **locp;
bool changed = false;
rtx cur_loc;
if (VAR_LOC_1PAUX (var))
VAR_LOC_FROM (var) = NULL;
}
- pool_free (loc_chain_pool, loc);
+ delete loc;
}
if (!var->var_part[0].loc_chain)
set->traversed_vars = set->vars;
shared_hash_htab (set->vars)
- .traverse <overlapping_mems*, drop_overlapping_mem_locs> (&coms);
+ ->traverse <overlapping_mems*, drop_overlapping_mem_locs> (&coms);
set->traversed_vars = NULL;
}
values bound to it. */
static void
-val_store (dataflow_set *set, rtx val, rtx loc, rtx insn, bool modified)
+val_store (dataflow_set *set, rtx val, rtx loc, rtx_insn *insn,
+ bool modified)
{
cselib_val *v = CSELIB_VAL_PTR (val);
/* Clear (canonical address) slots that reference X. */
-static bool
-local_get_addr_clear_given_value (const void *v ATTRIBUTE_UNUSED,
- void **slot, void *x)
+bool
+local_get_addr_clear_given_value (rtx const &, rtx *slot, rtx x)
{
- if (vt_get_canonicalize_base ((rtx)*slot) == x)
+ if (vt_get_canonicalize_base (*slot) == x)
*slot = NULL;
return true;
}
static void
val_reset (dataflow_set *set, decl_or_value dv)
{
- variable var = shared_hash_find (set->vars, dv) ;
- location_chain node;
+ variable *var = shared_hash_find (set->vars, dv) ;
+ location_chain *node;
rtx cval;
if (!var || !var->n_var_parts)
if (var->onepart == ONEPART_VALUE)
{
rtx x = dv_as_value (dv);
- void **slot;
-
+
/* Relationships in the global cache don't change, so reset the
local cache entry only. */
- slot = pointer_map_contains (local_get_addr_cache, x);
+ rtx *slot = local_get_addr_cache->get (x);
if (slot)
{
/* If the value resolved back to itself, odds are that other
old X but resolved to something else remain ok as long as
that something else isn't also reset. */
if (*slot == x)
- pointer_map_traverse (local_get_addr_cache,
- local_get_addr_clear_given_value, x);
+ local_get_addr_cache
+ ->traverse<rtx, local_get_addr_clear_given_value> (x);
*slot = NULL;
}
}
value. */
static void
-val_resolve (dataflow_set *set, rtx val, rtx loc, rtx insn)
+val_resolve (dataflow_set *set, rtx val, rtx loc, rtx_insn *insn)
{
decl_or_value dv = dv_from_value (val);
if (REG_P (loc))
{
- attrs node, found = NULL;
+ attrs *node, *found = NULL;
for (node = set->regs[REGNO (loc)]; node; node = node->next)
if (dv_is_value_p (node->dv)
struct variable_union_info
{
/* Node of the location chain. */
- location_chain lc;
+ location_chain *lc;
/* The sum of positions in the input chains. */
int pos;
we keep the newest locations in the beginning. */
static int
-variable_union (variable src, dataflow_set *set)
+variable_union (variable *src, dataflow_set *set)
{
- variable dst;
- variable_def **dstp;
+ variable *dst;
+ variable **dstp;
int i, j, k;
dstp = shared_hash_find_slot (set->vars, src->dv);
entries are in canonical order. */
if (src->onepart)
{
- location_chain *nodep, dnode, snode;
+ location_chain **nodep, *dnode, *snode;
gcc_assert (src->n_var_parts == 1
&& dst->n_var_parts == 1);
if (r > 0)
{
- location_chain nnode;
+ location_chain *nnode;
if (shared_var_p (dst, set->vars))
{
goto restart_onepart_unshared;
}
- *nodep = nnode = (location_chain) pool_alloc (loc_chain_pool);
+ *nodep = nnode = new location_chain;
nnode->loc = snode->loc;
nnode->init = snode->init;
if (!snode->set_src || MEM_P (snode->set_src))
for (k--; k >= 0; k--)
{
- location_chain node, node2;
+ location_chain *node, *node2;
if (i >= 0 && j >= 0
&& VAR_PART_OFFSET (src, i) == VAR_PART_OFFSET (dst, j))
{
dstp = unshare_variable (set, dstp, dst,
VAR_INIT_STATUS_UNKNOWN);
- dst = (variable)*dstp;
+ dst = (variable *)*dstp;
}
}
if (dst_l == 1)
{
/* The most common case, much simpler, no qsort is needed. */
- location_chain dstnode = dst->var_part[j].loc_chain;
+ location_chain *dstnode = dst->var_part[j].loc_chain;
dst->var_part[k].loc_chain = dstnode;
VAR_PART_OFFSET (dst, k) = VAR_PART_OFFSET (dst, j);
node2 = dstnode;
&& REGNO (dstnode->loc) == REGNO (node->loc))
|| rtx_equal_p (dstnode->loc, node->loc)))
{
- location_chain new_node;
+ location_chain *new_node;
/* Copy the location from SRC. */
- new_node = (location_chain) pool_alloc (loc_chain_pool);
+ new_node = new location_chain;
new_node->loc = node->loc;
new_node->init = node->init;
if (!node->set_src || MEM_P (node->set_src))
}
if (jj >= dst_l) /* The location has not been found. */
{
- location_chain new_node;
+ location_chain *new_node;
/* Copy the location from SRC. */
- new_node = (location_chain) pool_alloc (loc_chain_pool);
+ new_node = new location_chain;
new_node->loc = node->loc;
new_node->init = node->init;
if (!node->set_src || MEM_P (node->set_src))
&& VAR_PART_OFFSET (src, i) > VAR_PART_OFFSET (dst, j))
|| j < 0)
{
- location_chain *nextp;
+ location_chain **nextp;
/* Copy the chain from SRC. */
nextp = &dst->var_part[k].loc_chain;
for (node = src->var_part[i].loc_chain; node; node = node->next)
{
- location_chain new_lc;
+ location_chain *new_lc;
- new_lc = (location_chain) pool_alloc (loc_chain_pool);
+ new_lc = new location_chain;
new_lc->next = NULL;
new_lc->init = node->init;
if (!node->set_src || MEM_P (node->set_src))
if (flag_var_tracking_uninit)
for (i = 0; i < src->n_var_parts && i < dst->n_var_parts; i++)
{
- location_chain node, node2;
+ location_chain *node, *node2;
for (node = src->var_part[i].loc_chain; node; node = node->next)
for (node2 = dst->var_part[i].loc_chain; node2; node2 = node2->next)
if (rtx_equal_p (node->loc, node2->loc))
else
{
variable_iterator_type hi;
- variable var;
+ variable *var;
- FOR_EACH_HASH_TABLE_ELEMENT (shared_hash_htab (src->vars),
+ FOR_EACH_HASH_TABLE_ELEMENT (*shared_hash_htab (src->vars),
var, variable, hi)
variable_union (var, dst);
}
any values recursively mentioned in the location lists. VARS must
be in star-canonical form. */
-static location_chain
-find_loc_in_1pdv (rtx loc, variable var, variable_table_type vars)
+static location_chain *
+find_loc_in_1pdv (rtx loc, variable *var, variable_table_type *vars)
{
- location_chain node;
+ location_chain *node;
enum rtx_code loc_code;
if (!var)
for (node = var->var_part[0].loc_chain; node; node = node->next)
{
decl_or_value dv;
- variable rvar;
+ variable *rvar;
if (GET_CODE (node->loc) != loc_code)
{
gcc_checking_assert (!node->next);
dv = dv_from_value (node->loc);
- rvar = vars.find_with_hash (dv, dv_htab_hash (dv));
+ rvar = vars->find_with_hash (dv, dv_htab_hash (dv));
return find_loc_in_1pdv (loc, rvar, vars);
}
loc_cmp order, and it is maintained as such. */
static void
-insert_into_intersection (location_chain *nodep, rtx loc,
+insert_into_intersection (location_chain **nodep, rtx loc,
enum var_init_status status)
{
- location_chain node;
+ location_chain *node;
int r;
for (node = *nodep; node; nodep = &node->next, node = *nodep)
else if (r > 0)
break;
- node = (location_chain) pool_alloc (loc_chain_pool);
+ node = new location_chain;
node->loc = loc;
node->set_src = NULL;
DSM->dst. */
static void
-intersect_loc_chains (rtx val, location_chain *dest, struct dfset_merge *dsm,
- location_chain s1node, variable s2var)
+intersect_loc_chains (rtx val, location_chain **dest, struct dfset_merge *dsm,
+ location_chain *s1node, variable *s2var)
{
dataflow_set *s1set = dsm->cur;
dataflow_set *s2set = dsm->src;
- location_chain found;
+ location_chain *found;
if (s2var)
{
- location_chain s2node;
+ location_chain *s2node;
gcc_checking_assert (s2var->onepart);
&& !VALUE_RECURSED_INTO (s1node->loc))
{
decl_or_value dv = dv_from_value (s1node->loc);
- variable svar = shared_hash_find (s1set->vars, dv);
+ variable *svar = shared_hash_find (s1set->vars, dv);
if (svar)
{
if (svar->n_var_parts == 1)
default:
gcc_unreachable ();
}
+ if (CONST_WIDE_INT_P (x))
+ {
+ /* Compare the vector length first. */
+ if (CONST_WIDE_INT_NUNITS (x) >= CONST_WIDE_INT_NUNITS (y))
+ return 1;
+ else if (CONST_WIDE_INT_NUNITS (x) < CONST_WIDE_INT_NUNITS (y))
+ return -1;
+
+ /* Compare the vectors elements. */;
+ for (j = CONST_WIDE_INT_NUNITS (x) - 1; j >= 0 ; j--)
+ {
+ if (CONST_WIDE_INT_ELT (x, j) < CONST_WIDE_INT_ELT (y, j))
+ return -1;
+ if (CONST_WIDE_INT_ELT (x, j) > CONST_WIDE_INT_ELT (y, j))
+ return 1;
+ }
+ }
return 0;
}
-#if ENABLE_CHECKING
/* Check the order of entries in one-part variables. */
int
-canonicalize_loc_order_check (variable_def **slot,
+canonicalize_loc_order_check (variable **slot,
dataflow_set *data ATTRIBUTE_UNUSED)
{
- variable var = *slot;
- location_chain node, next;
+ variable *var = *slot;
+ location_chain *node, *next;
#ifdef ENABLE_RTL_CHECKING
int i;
return 1;
}
-#endif
/* Mark with VALUE_RECURSED_INTO values that have neighbors that are
more likely to be chosen as canonical for an equivalence set.
the connections bidirectional. */
int
-canonicalize_values_mark (variable_def **slot, dataflow_set *set)
+canonicalize_values_mark (variable **slot, dataflow_set *set)
{
- variable var = *slot;
+ variable *var = *slot;
decl_or_value dv = var->dv;
rtx val;
- location_chain node;
+ location_chain *node;
if (!dv_is_value_p (dv))
return 1;
else
{
decl_or_value odv = dv_from_value (node->loc);
- variable_def **oslot;
+ variable **oslot;
oslot = shared_hash_find_slot_noinsert (set->vars, odv);
set_slot_part (set, val, oslot, odv, 0,
variables, canonicalizing equivalence sets into star shapes. */
int
-canonicalize_values_star (variable_def **slot, dataflow_set *set)
+canonicalize_values_star (variable **slot, dataflow_set *set)
{
- variable var = *slot;
+ variable *var = *slot;
decl_or_value dv = var->dv;
- location_chain node;
+ location_chain *node;
decl_or_value cdv;
rtx val, cval;
- variable_def **cslot;
+ variable **cslot;
bool has_value;
bool has_marks;
}
else if (GET_CODE (node->loc) == REG)
{
- attrs list = set->regs[REGNO (node->loc)], *listp;
+ attrs *list = set->regs[REGNO (node->loc)], **listp;
/* Change an existing attribute referring to dv so that it
refers to cdv, removing any duplicate this might
if (dv_as_opaque (list->dv) == dv_as_opaque (cdv))
{
*listp = list->next;
- pool_free (attrs_pool, list);
+ delete list;
list = *listp;
break;
}
if (dv_as_opaque (list->dv) == dv_as_opaque (dv))
{
*listp = list->next;
- pool_free (attrs_pool, list);
+ delete list;
list = *listp;
break;
}
else
gcc_unreachable ();
-#if ENABLE_CHECKING
- while (list)
- {
- if (list->offset == 0
- && (dv_as_opaque (list->dv) == dv_as_opaque (dv)
- || dv_as_opaque (list->dv) == dv_as_opaque (cdv)))
- gcc_unreachable ();
+ if (flag_checking)
+ while (list)
+ {
+ if (list->offset == 0
+ && (dv_as_opaque (list->dv) == dv_as_opaque (dv)
+ || dv_as_opaque (list->dv) == dv_as_opaque (cdv)))
+ gcc_unreachable ();
- list = list->next;
- }
-#endif
+ list = list->next;
+ }
}
}
get to a variable that references another member of the set. */
int
-canonicalize_vars_star (variable_def **slot, dataflow_set *set)
+canonicalize_vars_star (variable **slot, dataflow_set *set)
{
- variable var = *slot;
+ variable *var = *slot;
decl_or_value dv = var->dv;
- location_chain node;
+ location_chain *node;
rtx cval;
decl_or_value cdv;
- variable_def **cslot;
- variable cvar;
- location_chain cnode;
+ variable **cslot;
+ variable *cvar;
+ location_chain *cnode;
if (!var->onepart || var->onepart == ONEPART_VALUE)
return 1;
intersection. */
static int
-variable_merge_over_cur (variable s1var, struct dfset_merge *dsm)
+variable_merge_over_cur (variable *s1var, struct dfset_merge *dsm)
{
dataflow_set *dst = dsm->dst;
- variable_def **dstslot;
- variable s2var, dvar = NULL;
+ variable **dstslot;
+ variable *s2var, *dvar = NULL;
decl_or_value dv = s1var->dv;
- onepart_enum_t onepart = s1var->onepart;
+ onepart_enum onepart = s1var->onepart;
rtx val;
hashval_t dvhash;
- location_chain node, *nodep;
+ location_chain *node, **nodep;
/* If the incoming onepart variable has an empty location list, then
the intersection will be just as empty. For other variables,
{
if (node)
{
- dvar = (variable) pool_alloc (onepart_pool (onepart));
+ dvar = onepart_pool_allocate (onepart);
dvar->dv = dv;
dvar->refcount = 1;
dvar->n_var_parts = 1;
nodep = &dvar->var_part[0].loc_chain;
while ((node = *nodep))
{
- location_chain *nextp = &node->next;
+ location_chain **nextp = &node->next;
if (GET_CODE (node->loc) == REG)
{
- attrs list;
+ attrs *list;
for (list = dst->regs[REGNO (node->loc)]; list; list = list->next)
if (GET_MODE (node->loc) == GET_MODE (list->loc)
if (GET_CODE (node->loc) == VALUE)
{
decl_or_value dv = dv_from_value (node->loc);
- variable_def **slot = NULL;
+ variable **slot = NULL;
if (shared_hash_shared (dst->vars))
slot = shared_hash_find_slot_noinsert (dst->vars, dv);
INSERT);
if (!*slot)
{
- variable var = (variable) pool_alloc (onepart_pool
- (ONEPART_VALUE));
+ variable *var = onepart_pool_allocate (ONEPART_VALUE);
var->dv = dv;
var->refcount = 1;
var->n_var_parts = 1;
variable_merge_over_cur(). */
static int
-variable_merge_over_src (variable s2var, struct dfset_merge *dsm)
+variable_merge_over_src (variable *s2var, struct dfset_merge *dsm)
{
dataflow_set *dst = dsm->dst;
decl_or_value dv = s2var->dv;
if (!s2var->onepart)
{
- variable_def **dstp = shared_hash_find_slot (dst->vars, dv);
+ variable **dstp = shared_hash_find_slot (dst->vars, dv);
*dstp = s2var;
s2var->refcount++;
return 1;
int i;
size_t src1_elems, src2_elems;
variable_iterator_type hi;
- variable var;
+ variable *var;
- src1_elems = shared_hash_htab (src1->vars).elements ();
- src2_elems = shared_hash_htab (src2->vars).elements ();
+ src1_elems = shared_hash_htab (src1->vars)->elements ();
+ src2_elems = shared_hash_htab (src2->vars)->elements ();
dataflow_set_init (dst);
dst->stack_adjust = cur.stack_adjust;
shared_hash_destroy (dst->vars);
- dst->vars = (shared_hash) pool_alloc (shared_hash_pool);
+ dst->vars = new shared_hash;
dst->vars->refcount = 1;
- dst->vars->htab.create (MAX (src1_elems, src2_elems));
+ dst->vars->htab = new variable_table_type (MAX (src1_elems, src2_elems));
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
attrs_list_mpdv_union (&dst->regs[i], src1->regs[i], src2->regs[i]);
dsm.cur = src1;
dsm.src_onepart_cnt = 0;
- FOR_EACH_HASH_TABLE_ELEMENT (shared_hash_htab (dsm.src->vars),
+ FOR_EACH_HASH_TABLE_ELEMENT (*shared_hash_htab (dsm.src->vars),
var, variable, hi)
variable_merge_over_src (var, &dsm);
- FOR_EACH_HASH_TABLE_ELEMENT (shared_hash_htab (dsm.cur->vars),
+ FOR_EACH_HASH_TABLE_ELEMENT (*shared_hash_htab (dsm.cur->vars),
var, variable, hi)
variable_merge_over_cur (var, &dsm);
dataflow_set_equiv_regs (dataflow_set *set)
{
int i;
- attrs list, *listp;
+ attrs *list, **listp;
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
{
if (list->offset == 0 && dv_onepart_p (list->dv))
{
rtx cval = canon[(int)GET_MODE (list->loc)];
- variable_def **slot;
+ variable **slot;
if (!cval)
continue;
be unshared and 1-part. */
static void
-remove_duplicate_values (variable var)
+remove_duplicate_values (variable *var)
{
- location_chain node, *nodep;
+ location_chain *node, **nodep;
gcc_assert (var->onepart);
gcc_assert (var->n_var_parts == 1);
{
/* Remove duplicate value node. */
*nodep = node->next;
- pool_free (loc_chain_pool, node);
+ delete node;
continue;
}
else
variables that don't have value numbers for them. */
int
-variable_post_merge_new_vals (variable_def **slot, dfset_post_merge *dfpm)
+variable_post_merge_new_vals (variable **slot, dfset_post_merge *dfpm)
{
dataflow_set *set = dfpm->set;
- variable var = *slot;
- location_chain node;
+ variable *var = *slot;
+ location_chain *node;
if (!var->onepart || !var->n_var_parts)
return 1;
gcc_assert (!VALUE_RECURSED_INTO (node->loc));
else if (GET_CODE (node->loc) == REG)
{
- attrs att, *attp, *curp = NULL;
+ attrs *att, **attp, **curp = NULL;
if (var->refcount != 1)
{
to be added when we bring perm in. */
att = *curp;
*curp = att->next;
- pool_free (attrs_pool, att);
+ delete att;
}
}
chosen expression. */
int
-variable_post_merge_perm_vals (variable_def **pslot, dfset_post_merge *dfpm)
+variable_post_merge_perm_vals (variable **pslot, dfset_post_merge *dfpm)
{
dataflow_set *set = dfpm->set;
- variable pvar = *pslot, var;
- location_chain pnode;
+ variable *pvar = *pslot, *var;
+ location_chain *pnode;
decl_or_value dv;
- attrs att;
+ attrs *att;
gcc_assert (dv_is_value_p (pvar->dv)
&& pvar->n_var_parts == 1);
dfpm.permp = permp;
shared_hash_htab (set->vars)
- .traverse <dfset_post_merge*, variable_post_merge_new_vals> (&dfpm);
+ ->traverse <dfset_post_merge*, variable_post_merge_new_vals> (&dfpm);
if (*permp)
shared_hash_htab ((*permp)->vars)
- .traverse <dfset_post_merge*, variable_post_merge_perm_vals> (&dfpm);
+ ->traverse <dfset_post_merge*, variable_post_merge_perm_vals> (&dfpm);
shared_hash_htab (set->vars)
- .traverse <dataflow_set *, canonicalize_values_star> (set);
+ ->traverse <dataflow_set *, canonicalize_values_star> (set);
shared_hash_htab (set->vars)
- .traverse <dataflow_set *, canonicalize_vars_star> (set);
+ ->traverse <dataflow_set *, canonicalize_vars_star> (set);
}
/* Return a node whose loc is a MEM that refers to EXPR in the
location list of a one-part variable or value VAR, or in that of
any values recursively mentioned in the location lists. */
-static location_chain
-find_mem_expr_in_1pdv (tree expr, rtx val, variable_table_type vars)
+static location_chain *
+find_mem_expr_in_1pdv (tree expr, rtx val, variable_table_type *vars)
{
- location_chain node;
+ location_chain *node;
decl_or_value dv;
- variable var;
- location_chain where = NULL;
+ variable *var;
+ location_chain *where = NULL;
if (!val)
return NULL;
&& !VALUE_RECURSED_INTO (val));
dv = dv_from_value (val);
- var = vars.find_with_hash (dv, dv_htab_hash (dv));
+ var = vars->find_with_hash (dv, dv_htab_hash (dv));
if (!var)
return NULL;
the variable itself, directly or within a VALUE. */
int
-dataflow_set_preserve_mem_locs (variable_def **slot, dataflow_set *set)
+dataflow_set_preserve_mem_locs (variable **slot, dataflow_set *set)
{
- variable var = *slot;
+ variable *var = *slot;
if (var->onepart == ONEPART_VDECL || var->onepart == ONEPART_DEXPR)
{
tree decl = dv_as_decl (var->dv);
- location_chain loc, *locp;
+ location_chain *loc, **locp;
bool changed = false;
if (!var->n_var_parts)
{
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 don't refer to DECL. */
if (GET_CODE (loc->loc) == MEM
&& (MEM_EXPR (loc->loc) != decl
|| INT_MEM_OFFSET (loc->loc) != 0)
- && !mem_dies_at_call (loc->loc))
+ && mem_dies_at_call (loc->loc))
break;
/* We want to move here MEMs that do refer to DECL. */
else if (GET_CODE (loc->loc) == VALUE
rtx old_loc = loc->loc;
if (GET_CODE (old_loc) == VALUE)
{
- location_chain mem_node
+ location_chain *mem_node
= find_mem_expr_in_1pdv (decl, loc->loc,
shared_hash_htab (set->vars));
}
}
*locp = loc->next;
- pool_free (loc_chain_pool, loc);
+ delete loc;
}
if (!var->var_part[0].loc_chain)
}
/* Remove all MEMs from the location list of a hash table entry for a
- value. */
+ onepart variable. */
int
-dataflow_set_remove_mem_locs (variable_def **slot, dataflow_set *set)
+dataflow_set_remove_mem_locs (variable **slot, dataflow_set *set)
{
- variable var = *slot;
+ variable *var = *slot;
- if (var->onepart == ONEPART_VALUE)
+ if (var->onepart != NOT_ONEPART)
{
- location_chain loc, *locp;
+ location_chain *loc, **locp;
bool changed = false;
rtx cur_loc;
if (VAR_LOC_1PAUX (var))
VAR_LOC_FROM (var) = NULL;
}
- pool_free (loc_chain_pool, loc);
+ delete loc;
}
if (!var->var_part[0].loc_chain)
registers, as well as associations between MEMs and VALUEs. */
static void
-dataflow_set_clear_at_call (dataflow_set *set)
+dataflow_set_clear_at_call (dataflow_set *set, rtx_insn *call_insn)
{
unsigned int r;
hard_reg_set_iterator hrsi;
+ HARD_REG_SET invalidated_regs;
- EXECUTE_IF_SET_IN_HARD_REG_SET (regs_invalidated_by_call, 0, r, hrsi)
+ get_call_reg_set_usage (call_insn, &invalidated_regs,
+ regs_invalidated_by_call);
+
+ EXECUTE_IF_SET_IN_HARD_REG_SET (invalidated_regs, 0, r, hrsi)
var_regno_delete (set, r);
if (MAY_HAVE_DEBUG_INSNS)
{
set->traversed_vars = set->vars;
shared_hash_htab (set->vars)
- .traverse <dataflow_set *, dataflow_set_preserve_mem_locs> (set);
+ ->traverse <dataflow_set *, dataflow_set_preserve_mem_locs> (set);
set->traversed_vars = set->vars;
shared_hash_htab (set->vars)
- .traverse <dataflow_set *, dataflow_set_remove_mem_locs> (set);
+ ->traverse <dataflow_set *, dataflow_set_remove_mem_locs> (set);
set->traversed_vars = NULL;
}
}
static bool
variable_part_different_p (variable_part *vp1, variable_part *vp2)
{
- location_chain lc1, lc2;
+ location_chain *lc1, *lc2;
for (lc1 = vp1->loc_chain; lc1; lc1 = lc1->next)
{
They must be in canonical order. */
static bool
-onepart_variable_different_p (variable var1, variable var2)
+onepart_variable_different_p (variable *var1, variable *var2)
{
- location_chain lc1, lc2;
+ location_chain *lc1, *lc2;
if (var1 == var2)
return false;
return lc1 != lc2;
}
+/* Return true if one-part variables VAR1 and VAR2 are different.
+ They must be in canonical order. */
+
+static void
+dump_onepart_variable_differences (variable *var1, variable *var2)
+{
+ location_chain *lc1, *lc2;
+
+ gcc_assert (var1 != var2);
+ gcc_assert (dump_file);
+ gcc_assert (dv_as_opaque (var1->dv) == dv_as_opaque (var2->dv));
+ gcc_assert (var1->n_var_parts == 1
+ && var2->n_var_parts == 1);
+
+ lc1 = var1->var_part[0].loc_chain;
+ lc2 = var2->var_part[0].loc_chain;
+
+ gcc_assert (lc1 && lc2);
+
+ while (lc1 && lc2)
+ {
+ switch (loc_cmp (lc1->loc, lc2->loc))
+ {
+ case -1:
+ fprintf (dump_file, "removed: ");
+ print_rtl_single (dump_file, lc1->loc);
+ lc1 = lc1->next;
+ continue;
+ case 0:
+ break;
+ case 1:
+ fprintf (dump_file, "added: ");
+ print_rtl_single (dump_file, lc2->loc);
+ lc2 = lc2->next;
+ continue;
+ default:
+ gcc_unreachable ();
+ }
+ lc1 = lc1->next;
+ lc2 = lc2->next;
+ }
+
+ while (lc1)
+ {
+ fprintf (dump_file, "removed: ");
+ print_rtl_single (dump_file, lc1->loc);
+ lc1 = lc1->next;
+ }
+
+ while (lc2)
+ {
+ fprintf (dump_file, "added: ");
+ print_rtl_single (dump_file, lc2->loc);
+ lc2 = lc2->next;
+ }
+}
+
/* Return true if variables VAR1 and VAR2 are different. */
static bool
-variable_different_p (variable var1, variable var2)
+variable_different_p (variable *var1, variable *var2)
{
int i;
dataflow_set_different (dataflow_set *old_set, dataflow_set *new_set)
{
variable_iterator_type hi;
- variable var1;
+ variable *var1;
+ bool diffound = false;
+ bool details = (dump_file && (dump_flags & TDF_DETAILS));
+
+#define RETRUE \
+ do \
+ { \
+ if (!details) \
+ return true; \
+ else \
+ diffound = true; \
+ } \
+ while (0)
if (old_set->vars == new_set->vars)
return false;
- if (shared_hash_htab (old_set->vars).elements ()
- != shared_hash_htab (new_set->vars).elements ())
- return true;
+ if (shared_hash_htab (old_set->vars)->elements ()
+ != shared_hash_htab (new_set->vars)->elements ())
+ RETRUE;
- FOR_EACH_HASH_TABLE_ELEMENT (shared_hash_htab (old_set->vars),
+ FOR_EACH_HASH_TABLE_ELEMENT (*shared_hash_htab (old_set->vars),
var1, variable, hi)
{
- variable_table_type htab = shared_hash_htab (new_set->vars);
- variable var2 = htab.find_with_hash (var1->dv, dv_htab_hash (var1->dv));
+ variable_table_type *htab = shared_hash_htab (new_set->vars);
+ variable *var2 = htab->find_with_hash (var1->dv, dv_htab_hash (var1->dv));
+
if (!var2)
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "dataflow difference found: removal of:\n");
dump_var (var1);
}
- return true;
+ RETRUE;
}
-
- if (variable_different_p (var1, var2))
+ else if (variable_different_p (var1, var2))
{
- if (dump_file && (dump_flags & TDF_DETAILS))
+ if (details)
{
fprintf (dump_file, "dataflow difference found: "
"old and new follow:\n");
dump_var (var1);
+ if (dv_onepart_p (var1->dv))
+ dump_onepart_variable_differences (var1, var2);
dump_var (var2);
}
- return true;
+ RETRUE;
}
}
- /* No need to traverse the second hashtab, if both have the same number
- of elements and the second one had all entries found in the first one,
- then it can't have any extra entries. */
- return false;
+ /* There's no need to traverse the second hashtab unless we want to
+ print the details. If both have the same number of elements and
+ the second one had all entries found in the first one, then the
+ second can't have any extra entries. */
+ if (!details)
+ return diffound;
+
+ FOR_EACH_HASH_TABLE_ELEMENT (*shared_hash_htab (new_set->vars),
+ var1, variable, hi)
+ {
+ variable_table_type *htab = shared_hash_htab (old_set->vars);
+ variable *var2 = htab->find_with_hash (var1->dv, dv_htab_hash (var1->dv));
+ if (!var2)
+ {
+ if (details)
+ {
+ fprintf (dump_file, "dataflow difference found: addition of:\n");
+ dump_var (var1);
+ }
+ RETRUE;
+ }
+ }
+
+#undef RETRUE
+
+ return diffound;
}
/* Free the contents of dataflow set SET. */
set->vars = NULL;
}
-/* Return true if RTL X contains a SYMBOL_REF. */
+/* Return true if T is a tracked parameter with non-degenerate record type. */
static bool
-contains_symbol_ref (rtx x)
+tracked_record_parameter_p (tree t)
{
- const char *fmt;
- RTX_CODE code;
- int i;
+ if (TREE_CODE (t) != PARM_DECL)
+ return false;
- if (!x)
+ if (DECL_MODE (t) == BLKmode)
return false;
- code = GET_CODE (x);
- if (code == SYMBOL_REF)
- return true;
+ tree type = TREE_TYPE (t);
+ if (TREE_CODE (type) != RECORD_TYPE)
+ return false;
- fmt = GET_RTX_FORMAT (code);
- for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
- {
- if (fmt[i] == 'e')
- {
- if (contains_symbol_ref (XEXP (x, i)))
- return true;
- }
- else if (fmt[i] == 'E')
- {
- int j;
- for (j = 0; j < XVECLEN (x, i); j++)
- if (contains_symbol_ref (XVECEXP (x, i, j)))
- return true;
- }
- }
+ if (TYPE_FIELDS (type) == NULL_TREE
+ || DECL_CHAIN (TYPE_FIELDS (type)) == NULL_TREE)
+ return false;
- return false;
+ return true;
}
/* Shall EXPR be tracked? */
&& TREE_CODE (TREE_OPERAND (realdecl, 0)) == ADDR_EXPR))
{
HOST_WIDE_INT bitsize, bitpos, maxsize;
+ bool reverse;
tree innerdecl
= get_ref_base_and_extent (realdecl, &bitpos, &bitsize,
- &maxsize);
+ &maxsize, &reverse);
if (!DECL_P (innerdecl)
|| DECL_IGNORED_P (innerdecl)
- /* Do not track declarations for parts of tracked parameters
- since we want to track them as a whole instead. */
- || (TREE_CODE (innerdecl) == PARM_DECL
- && DECL_MODE (innerdecl) != BLKmode
- && TREE_CODE (TREE_TYPE (innerdecl)) != UNION_TYPE)
+ /* Do not track declarations for parts of tracked record
+ parameters since we want to track them as a whole. */
+ || tracked_record_parameter_p (innerdecl)
|| TREE_STATIC (innerdecl)
|| bitsize <= 0
|| bitpos + bitsize > 256
char **_dl_argv;
*/
if (decl_rtl && MEM_P (decl_rtl)
- && contains_symbol_ref (XEXP (decl_rtl, 0)))
+ && contains_symbol_ref_p (XEXP (decl_rtl, 0)))
return 0;
/* If RTX is a memory it should not be very large (because it would be
static bool
track_loc_p (rtx loc, tree expr, HOST_WIDE_INT offset, bool store_reg_p,
- enum machine_mode *mode_out, HOST_WIDE_INT *offset_out)
+ machine_mode *mode_out, HOST_WIDE_INT *offset_out)
{
- enum machine_mode mode;
+ machine_mode mode;
if (expr == NULL || !track_expr_p (expr, true))
return false;
mode = GET_MODE (loc);
if (REG_P (loc) && !HARD_REGISTER_NUM_P (ORIGINAL_REGNO (loc)))
{
- enum machine_mode pseudo_mode;
+ machine_mode pseudo_mode;
pseudo_mode = PSEUDO_REGNO_MODE (ORIGINAL_REGNO (loc));
if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (pseudo_mode))
on the returned value are updated. */
static rtx
-var_lowpart (enum machine_mode mode, rtx loc)
+var_lowpart (machine_mode mode, rtx loc)
{
unsigned int offset, reg_offset, regno;
struct count_use_info
{
/* The insn where the RTX is. */
- rtx insn;
+ rtx_insn *insn;
/* The basic block where insn is. */
basic_block bb;
/* Find a VALUE corresponding to X. */
static inline cselib_val *
-find_use_val (rtx x, enum machine_mode mode, struct count_use_info *cui)
+find_use_val (rtx x, machine_mode mode, struct count_use_info *cui)
{
int i;
return cselib_subst_to_values (loc, VOIDmode);
}
-/* Return true if *X is a DEBUG_EXPR. Usable as an argument to
- for_each_rtx to tell whether there are any DEBUG_EXPRs within
- RTX. */
+/* Return true if X contains a DEBUG_EXPR. */
-static int
-rtx_debug_expr_p (rtx *x, void *data ATTRIBUTE_UNUSED)
+static bool
+rtx_debug_expr_p (const_rtx x)
{
- rtx loc = *x;
-
- return GET_CODE (loc) == DEBUG_EXPR;
+ subrtx_iterator::array_type array;
+ FOR_EACH_SUBRTX (iter, array, x, ALL)
+ if (GET_CODE (*iter) == DEBUG_EXPR)
+ return true;
+ return false;
}
/* Determine what kind of micro operation to choose for a USE. Return
MO_CLOBBER if no micro operation is to be generated. */
static enum micro_operation_type
-use_type (rtx loc, struct count_use_info *cui, enum machine_mode *modep)
+use_type (rtx loc, struct count_use_info *cui, machine_mode *modep)
{
tree expr;
DEBUG_EXPRs (only happens in the presence of debug
insns). */
&& (!MAY_HAVE_DEBUG_INSNS
- || !for_each_rtx (&XEXP (loc, 0), rtx_debug_expr_p, NULL)))
+ || !rtx_debug_expr_p (XEXP (loc, 0))))
return MO_USE;
else
return MO_CLOBBER;
INSN of BB. */
static inline void
-log_op_type (rtx x, basic_block bb, rtx insn,
+log_op_type (rtx x, basic_block bb, rtx_insn *insn,
enum micro_operation_type mopt, FILE *out)
{
fprintf (out, "bb %i op %i insn %i %s ",
any rtxes not suitable for CONST use not replaced by VALUEs
are discovered. */
-static int
-non_suitable_const (rtx *x, void *data ATTRIBUTE_UNUSED)
+static bool
+non_suitable_const (const_rtx x)
{
- if (*x == NULL_RTX)
- return 0;
-
- switch (GET_CODE (*x))
+ subrtx_iterator::array_type array;
+ FOR_EACH_SUBRTX (iter, array, x, ALL)
{
- case REG:
- case DEBUG_EXPR:
- case PC:
- case SCRATCH:
- case CC0:
- case ASM_INPUT:
- case ASM_OPERANDS:
- return 1;
- case MEM:
- return !MEM_READONLY_P (*x);
- default:
- return 0;
+ const_rtx x = *iter;
+ switch (GET_CODE (x))
+ {
+ case REG:
+ case DEBUG_EXPR:
+ case PC:
+ case SCRATCH:
+ case CC0:
+ case ASM_INPUT:
+ case ASM_OPERANDS:
+ return true;
+ case MEM:
+ if (!MEM_READONLY_P (x))
+ return true;
+ break;
+ default:
+ break;
+ }
}
+ return false;
}
/* Add uses (register and memory references) LOC which will be tracked
- to VTI (bb)->mos. INSN is instruction which the LOC is part of. */
+ to VTI (bb)->mos. */
-static int
-add_uses (rtx *ploc, void *data)
+static void
+add_uses (rtx loc, struct count_use_info *cui)
{
- rtx loc = *ploc;
- enum machine_mode mode = VOIDmode;
- struct count_use_info *cui = (struct count_use_info *)data;
+ machine_mode mode = VOIDmode;
enum micro_operation_type type = use_type (loc, cui, &mode);
if (type != MO_CLOBBER)
&& !MEM_P (XEXP (vloc, 0)))
{
rtx mloc = vloc;
- enum machine_mode address_mode = get_address_mode (mloc);
+ machine_mode address_mode = get_address_mode (mloc);
cselib_val *val
= cselib_lookup (XEXP (mloc, 0), address_mode, 0,
GET_MODE (mloc));
}
if (CONSTANT_P (vloc)
- && (GET_CODE (vloc) != CONST
- || for_each_rtx (&vloc, non_suitable_const, NULL)))
+ && (GET_CODE (vloc) != CONST || non_suitable_const (vloc)))
/* For constants don't look up any value. */;
else if (!VAR_LOC_UNKNOWN_P (vloc) && !unsuitable_loc (vloc)
&& (val = find_use_val (vloc, GET_MODE (oloc), cui)))
{
- enum machine_mode mode2;
+ machine_mode mode2;
enum micro_operation_type type2;
rtx nloc = NULL;
bool resolvable = REG_P (vloc) || MEM_P (vloc);
}
else if (type == MO_VAL_USE)
{
- enum machine_mode mode2 = VOIDmode;
+ machine_mode mode2 = VOIDmode;
enum micro_operation_type type2;
cselib_val *val = find_use_val (loc, GET_MODE (loc), cui);
rtx vloc, oloc = loc, nloc;
&& !MEM_P (XEXP (oloc, 0)))
{
rtx mloc = oloc;
- enum machine_mode address_mode = get_address_mode (mloc);
+ machine_mode address_mode = get_address_mode (mloc);
cselib_val *val
= cselib_lookup (XEXP (mloc, 0), address_mode, 0,
GET_MODE (mloc));
log_op_type (mo.u.loc, cui->bb, cui->insn, mo.type, dump_file);
VTI (bb)->mos.safe_push (mo);
}
-
- return 0;
}
/* Helper function for finding all uses of REG/MEM in X in insn INSN. */
static void
add_uses_1 (rtx *x, void *cui)
{
- for_each_rtx (x, add_uses, cui);
+ subrtx_var_iterator::array_type array;
+ FOR_EACH_SUBRTX_VAR (iter, array, *x, NONCONST)
+ add_uses (*iter, (struct count_use_info *) cui);
}
/* This is the value used during expansion of locations. We want it
no longer live we can express its value as VAL - 6. */
static void
-reverse_op (rtx val, const_rtx expr, rtx insn)
+reverse_op (rtx val, const_rtx expr, rtx_insn *insn)
{
rtx src, arg, ret;
cselib_val *v;
return;
}
ret = simplify_gen_binary (code, GET_MODE (val), val, arg);
- if (ret == val)
- /* Ensure ret isn't VALUE itself (which can happen e.g. for
- (plus (reg1) (reg2)) when reg2 is known to be 0), as that
- breaks a lot of routines during var-tracking. */
- ret = gen_rtx_fmt_ee (PLUS, GET_MODE (val), val, const0_rtx);
break;
default:
gcc_unreachable ();
static void
add_stores (rtx loc, const_rtx expr, void *cuip)
{
- enum machine_mode mode = VOIDmode, mode2;
+ machine_mode mode = VOIDmode, mode2;
struct count_use_info *cui = (struct count_use_info *)cuip;
basic_block bb = cui->bb;
micro_operation mo;
&& find_use_val (loc, mode, cui))
{
gcc_checking_assert (type == MO_VAL_SET);
- mo.u.loc = gen_rtx_SET (VOIDmode, loc, SET_SRC (expr));
+ mo.u.loc = gen_rtx_SET (loc, SET_SRC (expr));
}
}
else
}
else
{
- rtx xexpr = gen_rtx_SET (VOIDmode, loc, src);
+ rtx xexpr = gen_rtx_SET (loc, src);
if (same_variable_part_p (src, REG_EXPR (loc), REG_OFFSET (loc)))
{
/* If this is an instruction copying (part of) a parameter
&& !MEM_P (XEXP (loc, 0)))
{
rtx mloc = loc;
- enum machine_mode address_mode = get_address_mode (mloc);
+ machine_mode address_mode = get_address_mode (mloc);
cselib_val *val = cselib_lookup (XEXP (mloc, 0),
address_mode, 0,
GET_MODE (mloc));
}
else
{
- rtx xexpr = gen_rtx_SET (VOIDmode, loc, src);
+ rtx xexpr = gen_rtx_SET (loc, src);
if (same_variable_part_p (SET_SRC (xexpr),
MEM_EXPR (loc),
INT_MEM_OFFSET (loc)))
if (type != MO_VAL_SET)
goto log_and_return;
- /* We cannot track values for multiple-part variables, so we track only
- locations for tracked parameters passed either by invisible reference
- or directly in multiple locations. */
- if (track_p
- && REG_P (loc)
- && REG_EXPR (loc)
- && TREE_CODE (REG_EXPR (loc)) == PARM_DECL
- && DECL_MODE (REG_EXPR (loc)) != BLKmode
- && ((MEM_P (DECL_INCOMING_RTL (REG_EXPR (loc)))
- && XEXP (DECL_INCOMING_RTL (REG_EXPR (loc)), 0) != arg_pointer_rtx)
- || (GET_CODE (DECL_INCOMING_RTL (REG_EXPR (loc))) == PARALLEL
- && XVECLEN (DECL_INCOMING_RTL (REG_EXPR (loc)), 0) > 1)))
- goto log_and_return;
-
v = find_use_val (oloc, mode, cui);
if (!v)
resolve = preserve = !cselib_preserved_value_p (v);
+ /* We cannot track values for multiple-part variables, so we track only
+ locations for tracked record parameters. */
+ if (track_p
+ && REG_P (loc)
+ && REG_EXPR (loc)
+ && tracked_record_parameter_p (REG_EXPR (loc)))
+ {
+ /* Although we don't use the value here, it could be used later by the
+ mere virtue of its existence as the operand of the reverse operation
+ that gave rise to it (typically extension/truncation). Make sure it
+ is preserved as required by vt_expand_var_loc_chain. */
+ if (preserve)
+ preserve_value (v);
+ goto log_and_return;
+ }
+
if (loc == stack_pointer_rtx
&& hard_frame_pointer_adjustment != -1
&& preserve)
{
cselib_val *oval = cselib_lookup (oloc, GET_MODE (oloc), 0, VOIDmode);
- gcc_assert (oval != v);
+ if (oval == v)
+ return;
gcc_assert (REG_P (oloc) || MEM_P (oloc));
if (oval && !cselib_preserved_value_p (oval))
}
if (nloc && nloc != SET_SRC (mo.u.loc))
- oloc = gen_rtx_SET (GET_MODE (mo.u.loc), oloc, nloc);
+ oloc = gen_rtx_SET (oloc, nloc);
else
{
if (oloc == SET_DEST (mo.u.loc))
/* Compute call_arguments. */
static void
-prepare_call_arguments (basic_block bb, rtx insn)
+prepare_call_arguments (basic_block bb, rtx_insn *insn)
{
rtx link, x, call;
rtx prev, cur, next;
&& 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);
+ machine_mode mode = TYPE_MODE (struct_addr);
rtx reg;
INIT_CUMULATIVE_ARGS (args_so_far_v, type, NULL_RTX, fndecl,
nargs + 1);
nargs);
if (obj_type_ref && TYPE_ARG_TYPES (type) != void_list_node)
{
- enum machine_mode mode;
+ machine_mode mode;
t = TYPE_ARG_TYPES (type);
mode = TYPE_MODE (TREE_VALUE (t));
this_arg = targetm.calls.function_arg (args_so_far, mode,
if (GET_MODE (link) == VOIDmode
|| GET_MODE (link) == BLKmode
|| (GET_MODE (link) != GET_MODE (x)
- && (GET_MODE_CLASS (GET_MODE (link)) != MODE_INT
- || GET_MODE_CLASS (GET_MODE (x)) != MODE_INT)))
+ && ((GET_MODE_CLASS (GET_MODE (link)) != MODE_INT
+ && GET_MODE_CLASS (GET_MODE (link)) != MODE_PARTIAL_INT)
+ || (GET_MODE_CLASS (GET_MODE (x)) != MODE_INT
+ && GET_MODE_CLASS (GET_MODE (x)) != MODE_PARTIAL_INT))))
/* Can't do anything for these, if the original type mode
isn't known or can't be converted. */;
else if (REG_P (x))
cselib_val *val = cselib_lookup (x, GET_MODE (x), 0, VOIDmode);
if (val && cselib_preserved_value_p (val))
item = val->val_rtx;
- else if (GET_MODE_CLASS (GET_MODE (x)) == MODE_INT)
+ else if (GET_MODE_CLASS (GET_MODE (x)) == MODE_INT
+ || GET_MODE_CLASS (GET_MODE (x)) == MODE_PARTIAL_INT)
{
- enum machine_mode mode = GET_MODE (x);
+ machine_mode mode = GET_MODE (x);
while ((mode = GET_MODE_WIDER_MODE (mode)) != VOIDmode
&& GET_MODE_BITSIZE (mode) <= BITS_PER_WORD)
struct adjust_mem_data amd;
amd.mem_mode = VOIDmode;
amd.stack_adjust = -VTI (bb)->out.stack_adjust;
- amd.side_effects = NULL_RTX;
+ amd.side_effects = NULL;
amd.store = true;
mem = simplify_replace_fn_rtx (mem, NULL_RTX, adjust_mems,
&amd);
val = cselib_lookup (mem, GET_MODE (mem), 0, VOIDmode);
if (val && cselib_preserved_value_p (val))
item = val->val_rtx;
- else if (GET_MODE_CLASS (GET_MODE (mem)) != MODE_INT)
+ else if (GET_MODE_CLASS (GET_MODE (mem)) != MODE_INT
+ && GET_MODE_CLASS (GET_MODE (mem)) != MODE_PARTIAL_INT)
{
/* For non-integer stack argument see also if they weren't
initialized by integers. */
- enum machine_mode imode = int_mode_for_mode (GET_MODE (mem));
+ machine_mode imode = int_mode_for_mode (GET_MODE (mem));
if (imode != GET_MODE (mem) && imode != BLKmode)
{
val = cselib_lookup (adjust_address_nv (mem, imode, 0),
if (t && t != void_list_node)
{
tree argtype = TREE_VALUE (t);
- enum machine_mode mode = TYPE_MODE (argtype);
+ machine_mode mode = TYPE_MODE (argtype);
rtx reg;
if (pass_by_reference (&args_so_far_v, mode, argtype, true))
{
&& reg
&& REG_P (reg)
&& GET_MODE (reg) == mode
- && GET_MODE_CLASS (mode) == MODE_INT
+ && (GET_MODE_CLASS (mode) == MODE_INT
+ || GET_MODE_CLASS (mode) == MODE_PARTIAL_INT)
&& REG_P (x)
&& REGNO (x) == REGNO (reg)
&& GET_MODE (x) == mode
&& item)
{
- enum machine_mode indmode
+ machine_mode indmode
= TYPE_MODE (TREE_TYPE (argtype));
rtx mem = gen_rtx_MEM (indmode, x);
cselib_val *val = cselib_lookup (mem, indmode, 0, VOIDmode);
{
rtx item;
tree dtemp = (**debug_args)[ix + 1];
- enum machine_mode mode = DECL_MODE (dtemp);
+ machine_mode mode = DECL_MODE (dtemp);
item = gen_rtx_DEBUG_PARAMETER_REF (mode, param);
item = gen_rtx_CONCAT (mode, item, DECL_RTL_KNOWN_SET (dtemp));
call_arguments = gen_rtx_EXPR_LIST (VOIDmode, item,
}
if (this_arg)
{
- enum machine_mode mode
+ 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
first place, in which case sets and n_sets will be 0). */
static void
-add_with_sets (rtx insn, struct cselib_set *sets, int n_sets)
+add_with_sets (rtx_insn *insn, struct cselib_set *sets, int n_sets)
{
basic_block bb = BLOCK_FOR_INSN (insn);
int n1, n2;
while (n1 < n2 && mos[n2].type != MO_USE)
n2--;
if (n1 < n2)
- {
- micro_operation sw;
-
- sw = mos[n1];
- mos[n1] = mos[n2];
- mos[n2] = sw;
- }
+ std::swap (mos[n1], mos[n2]);
}
n2 = VTI (bb)->mos.length () - 1;
while (n1 < n2 && mos[n2].type == MO_VAL_LOC)
n2--;
if (n1 < n2)
- {
- micro_operation sw;
-
- sw = mos[n1];
- mos[n1] = mos[n2];
- mos[n2] = sw;
- }
+ std::swap (mos[n1], mos[n2]);
}
if (CALL_P (insn))
while (n1 < n2 && mos[n2].type != MO_VAL_USE)
n2--;
if (n1 < n2)
- {
- micro_operation sw;
-
- sw = mos[n1];
- mos[n1] = mos[n2];
- mos[n2] = sw;
- }
+ std::swap (mos[n1], mos[n2]);
}
n2 = VTI (bb)->mos.length () - 1;
while (n1 < n2 && mos[n2].type != MO_CLOBBER)
n2--;
if (n1 < n2)
- {
- micro_operation sw;
-
- sw = mos[n1];
- mos[n1] = mos[n2];
- mos[n2] = sw;
- }
+ std::swap (mos[n1], mos[n2]);
}
}
{
tree decl = NULL_TREE; /* The variable being copied around. */
rtx set_src = NULL_RTX; /* The value for "decl" stored in "src". */
- variable var;
- location_chain nextp;
+ variable *var;
+ location_chain *nextp;
int i;
bool found;
dataflow_set_copy (out, in);
if (MAY_HAVE_DEBUG_INSNS)
- local_get_addr_cache = pointer_map_create ();
+ local_get_addr_cache = new hash_map<rtx, rtx>;
FOR_EACH_VEC_ELT (VTI (bb)->mos, i, mo)
{
- rtx insn = mo->insn;
+ rtx_insn *insn = mo->insn;
switch (mo->type)
{
case MO_CALL:
- dataflow_set_clear_at_call (out);
+ dataflow_set_clear_at_call (out, insn);
break;
case MO_USE:
if (MAY_HAVE_DEBUG_INSNS)
{
- pointer_map_destroy (local_get_addr_cache);
+ delete local_get_addr_cache;
local_get_addr_cache = NULL;
dataflow_set_equiv_regs (out);
shared_hash_htab (out->vars)
- .traverse <dataflow_set *, canonicalize_values_mark> (out);
+ ->traverse <dataflow_set *, canonicalize_values_mark> (out);
shared_hash_htab (out->vars)
- .traverse <dataflow_set *, canonicalize_values_star> (out);
-#if ENABLE_CHECKING
- shared_hash_htab (out->vars)
- .traverse <dataflow_set *, canonicalize_loc_order_check> (out);
-#endif
+ ->traverse <dataflow_set *, canonicalize_values_star> (out);
+ if (flag_checking)
+ shared_hash_htab (out->vars)
+ ->traverse <dataflow_set *, canonicalize_loc_order_check> (out);
}
changed = dataflow_set_different (&old_out, out);
dataflow_set_destroy (&old_out);
static bool
vt_find_locations (void)
{
- fibheap_t worklist, pending, fibheap_swap;
- sbitmap visited, in_worklist, in_pending, sbitmap_swap;
+ bb_heap_t *worklist = new bb_heap_t (LONG_MIN);
+ bb_heap_t *pending = new bb_heap_t (LONG_MIN);
+ sbitmap visited, in_worklist, in_pending;
basic_block bb;
edge e;
int *bb_order;
bb_order[rc_order[i]] = i;
free (rc_order);
- worklist = fibheap_new ();
- pending = fibheap_new ();
visited = sbitmap_alloc (last_basic_block_for_fn (cfun));
in_worklist = sbitmap_alloc (last_basic_block_for_fn (cfun));
in_pending = sbitmap_alloc (last_basic_block_for_fn (cfun));
bitmap_clear (in_worklist);
FOR_EACH_BB_FN (bb, cfun)
- fibheap_insert (pending, bb_order[bb->index], bb);
+ pending->insert (bb_order[bb->index], bb);
bitmap_ones (in_pending);
- while (success && !fibheap_empty (pending))
+ while (success && !pending->empty ())
{
- fibheap_swap = pending;
- pending = worklist;
- worklist = fibheap_swap;
- sbitmap_swap = in_pending;
- in_pending = in_worklist;
- in_worklist = sbitmap_swap;
+ std::swap (worklist, pending);
+ std::swap (in_worklist, in_pending);
bitmap_clear (visited);
- while (!fibheap_empty (worklist))
+ while (!worklist->empty ())
{
- bb = (basic_block) fibheap_extract_min (worklist);
+ bb = worklist->extract_min ();
bitmap_clear_bit (in_worklist, bb->index);
gcc_assert (!bitmap_bit_p (visited, bb->index));
if (!bitmap_bit_p (visited, bb->index))
if (VTI (bb)->in.vars)
{
htabsz
- -= shared_hash_htab (VTI (bb)->in.vars).size ()
- + shared_hash_htab (VTI (bb)->out.vars).size ();
- oldinsz = shared_hash_htab (VTI (bb)->in.vars).elements ();
- oldoutsz = shared_hash_htab (VTI (bb)->out.vars).elements ();
+ -= shared_hash_htab (VTI (bb)->in.vars)->size ()
+ + shared_hash_htab (VTI (bb)->out.vars)->size ();
+ oldinsz = shared_hash_htab (VTI (bb)->in.vars)->elements ();
+ oldoutsz
+ = shared_hash_htab (VTI (bb)->out.vars)->elements ();
}
else
oldinsz = oldoutsz = 0;
if (adjust)
{
dataflow_post_merge_adjust (in, &VTI (bb)->permp);
-#if ENABLE_CHECKING
- /* Merge and merge_adjust should keep entries in
- canonical order. */
- shared_hash_htab (in->vars)
- .traverse <dataflow_set *,
- canonicalize_loc_order_check> (in);
-#endif
+
+ if (flag_checking)
+ /* Merge and merge_adjust should keep entries in
+ canonical order. */
+ shared_hash_htab (in->vars)
+ ->traverse <dataflow_set *,
+ canonicalize_loc_order_check> (in);
+
if (dst_can_be_shared)
{
shared_hash_destroy (in->vars);
}
changed = compute_bb_dataflow (bb);
- htabsz += shared_hash_htab (VTI (bb)->in.vars).size ()
- + shared_hash_htab (VTI (bb)->out.vars).size ();
+ htabsz += shared_hash_htab (VTI (bb)->in.vars)->size ()
+ + shared_hash_htab (VTI (bb)->out.vars)->size ();
if (htabmax && htabsz > htabmax)
{
{
/* Send E->DEST to next round. */
bitmap_set_bit (in_pending, e->dest->index);
- fibheap_insert (pending,
- bb_order[e->dest->index],
- e->dest);
+ pending->insert (bb_order[e->dest->index],
+ e->dest);
}
}
else if (!bitmap_bit_p (in_worklist, e->dest->index))
{
/* Add E->DEST to current round. */
bitmap_set_bit (in_worklist, e->dest->index);
- fibheap_insert (worklist, bb_order[e->dest->index],
- e->dest);
+ worklist->insert (bb_order[e->dest->index],
+ e->dest);
}
}
}
fprintf (dump_file,
"BB %i: in %i (was %i), out %i (was %i), rem %i + %i, tsz %i\n",
bb->index,
- (int)shared_hash_htab (VTI (bb)->in.vars).size (),
+ (int)shared_hash_htab (VTI (bb)->in.vars)->size (),
oldinsz,
- (int)shared_hash_htab (VTI (bb)->out.vars).size (),
+ (int)shared_hash_htab (VTI (bb)->out.vars)->size (),
oldoutsz,
- (int)worklist->nodes, (int)pending->nodes, htabsz);
+ (int)worklist->nodes (), (int)pending->nodes (),
+ htabsz);
if (dump_file && (dump_flags & TDF_DETAILS))
{
gcc_assert (VTI (bb)->flooded);
free (bb_order);
- fibheap_delete (worklist);
- fibheap_delete (pending);
+ delete worklist;
+ delete pending;
sbitmap_free (visited);
sbitmap_free (in_worklist);
sbitmap_free (in_pending);
/* Print the content of the LIST to dump file. */
static void
-dump_attrs_list (attrs list)
+dump_attrs_list (attrs *list)
{
for (; list; list = list->next)
{
/* Print the information about variable *SLOT to dump file. */
int
-dump_var_tracking_slot (variable_def **slot, void *data ATTRIBUTE_UNUSED)
+dump_var_tracking_slot (variable **slot, void *data ATTRIBUTE_UNUSED)
{
- variable var = *slot;
+ variable *var = *slot;
dump_var (var);
/* Print the information about variable VAR to dump file. */
static void
-dump_var (variable var)
+dump_var (variable *var)
{
int i;
- location_chain node;
+ location_chain *node;
if (dv_is_decl_p (var->dv))
{
/* Print the information about variables from hash table VARS to dump file. */
static void
-dump_vars (variable_table_type vars)
+dump_vars (variable_table_type *vars)
{
- if (vars.elements () > 0)
+ if (vars->elements () > 0)
{
fprintf (dump_file, "Variables:\n");
- vars.traverse <void *, dump_var_tracking_slot> (NULL);
+ vars->traverse <void *, dump_var_tracking_slot> (NULL);
}
}
/* Return the variable for DV in dropped_values, inserting one if
requested with INSERT. */
-static inline variable
+static inline variable *
variable_from_dropped (decl_or_value dv, enum insert_option insert)
{
- variable_def **slot;
- variable empty_var;
- onepart_enum_t onepart;
+ variable **slot;
+ variable *empty_var;
+ onepart_enum onepart;
- slot = dropped_values.find_slot_with_hash (dv, dv_htab_hash (dv), insert);
+ slot = dropped_values->find_slot_with_hash (dv, dv_htab_hash (dv), insert);
if (!slot)
return NULL;
gcc_checking_assert (onepart == ONEPART_VALUE || onepart == ONEPART_DEXPR);
- empty_var = (variable) pool_alloc (onepart_pool (onepart));
+ empty_var = onepart_pool_allocate (onepart);
empty_var->dv = dv;
empty_var->refcount = 1;
empty_var->n_var_parts = 0;
/* Recover the one-part aux from dropped_values. */
static struct onepart_aux *
-recover_dropped_1paux (variable var)
+recover_dropped_1paux (variable *var)
{
- variable dvar;
+ variable *dvar;
gcc_checking_assert (var->onepart);
if it has no locations delete it from SET's hash table. */
static void
-variable_was_changed (variable var, dataflow_set *set)
+variable_was_changed (variable *var, dataflow_set *set)
{
hashval_t hash = dv_htab_hash (var->dv);
if (emit_notes)
{
- variable_def **slot;
+ variable **slot;
/* Remember this decl or VALUE has been added to changed_variables. */
set_dv_changed (var->dv, true);
- slot = changed_variables.find_slot_with_hash (var->dv, hash, INSERT);
+ slot = changed_variables->find_slot_with_hash (var->dv, hash, INSERT);
if (*slot)
{
- variable old_var = *slot;
+ variable *old_var = *slot;
gcc_assert (old_var->in_changed_variables);
old_var->in_changed_variables = false;
if (var != old_var && var->onepart)
if (set && var->n_var_parts == 0)
{
- onepart_enum_t onepart = var->onepart;
- variable empty_var = NULL;
- variable_def **dslot = NULL;
+ onepart_enum onepart = var->onepart;
+ variable *empty_var = NULL;
+ variable **dslot = NULL;
if (onepart == ONEPART_VALUE || onepart == ONEPART_DEXPR)
{
- dslot = dropped_values.find_slot_with_hash (var->dv,
- dv_htab_hash (var->dv),
- INSERT);
+ dslot = dropped_values->find_slot_with_hash (var->dv,
+ dv_htab_hash (var->dv),
+ INSERT);
empty_var = *dslot;
if (empty_var)
if (!empty_var)
{
- empty_var = (variable) pool_alloc (onepart_pool (onepart));
+ empty_var = onepart_pool_allocate (onepart);
empty_var->dv = var->dv;
empty_var->refcount = 1;
empty_var->n_var_parts = 0;
gcc_assert (set);
if (var->n_var_parts == 0)
{
- variable_def **slot;
+ variable **slot;
drop_var:
slot = shared_hash_find_slot_noinsert (set->vars, var->dv);
if (shared_hash_shared (set->vars))
slot = shared_hash_find_slot_unshare (&set->vars, var->dv,
NO_INSERT);
- shared_hash_htab (set->vars).clear_slot (slot);
+ shared_hash_htab (set->vars)->clear_slot (slot);
}
}
}
have, if it should be inserted. */
static inline int
-find_variable_location_part (variable var, HOST_WIDE_INT offset,
+find_variable_location_part (variable *var, HOST_WIDE_INT offset,
int *insertion_point)
{
int pos, low, high;
return -1;
}
-static variable_def **
-set_slot_part (dataflow_set *set, rtx loc, variable_def **slot,
+static variable **
+set_slot_part (dataflow_set *set, rtx loc, variable **slot,
decl_or_value dv, HOST_WIDE_INT offset,
enum var_init_status initialized, rtx set_src)
{
int pos;
- location_chain node, next;
- location_chain *nextp;
- variable var;
- onepart_enum_t onepart;
+ location_chain *node, *next;
+ location_chain **nextp;
+ variable *var;
+ onepart_enum onepart;
var = *slot;
if (!var)
{
/* Create new variable information. */
- var = (variable) pool_alloc (onepart_pool (onepart));
+ var = onepart_pool_allocate (onepart);
var->dv = dv;
var->refcount = 1;
var->n_var_parts = 1;
set_src = node->set_src;
if (var->var_part[pos].cur_loc == node->loc)
var->var_part[pos].cur_loc = NULL;
- pool_free (loc_chain_pool, node);
+ delete node;
*nextp = next;
break;
}
}
/* Add the location to the beginning. */
- node = (location_chain) pool_alloc (loc_chain_pool);
+ node = new location_chain;
node->loc = loc;
node->init = initialized;
node->set_src = set_src;
enum var_init_status initialized, rtx set_src,
enum insert_option iopt)
{
- variable_def **slot;
+ variable **slot;
if (iopt == NO_INSERT)
slot = shared_hash_find_slot_noinsert (set->vars, dv);
The variable part is specified by variable's declaration or value
DV and offset OFFSET. */
-static variable_def **
-clobber_slot_part (dataflow_set *set, rtx loc, variable_def **slot,
+static variable **
+clobber_slot_part (dataflow_set *set, rtx loc, variable **slot,
HOST_WIDE_INT offset, rtx set_src)
{
- variable var = *slot;
+ variable *var = *slot;
int pos = find_variable_location_part (var, offset, NULL);
if (pos >= 0)
{
- location_chain node, next;
+ location_chain *node, *next;
/* Remove the register locations from the dataflow set. */
next = var->var_part[pos].loc_chain;
{
if (REG_P (node->loc))
{
- attrs anode, anext;
- attrs *anextp;
+ attrs *anode, *anext;
+ attrs **anextp;
/* Remove the variable part from the register's
list, but preserve any other variable parts
if (dv_as_opaque (anode->dv) == dv_as_opaque (var->dv)
&& anode->offset == offset)
{
- pool_free (attrs_pool, anode);
+ delete anode;
*anextp = anext;
}
else
clobber_variable_part (dataflow_set *set, rtx loc, decl_or_value dv,
HOST_WIDE_INT offset, rtx set_src)
{
- variable_def **slot;
+ variable **slot;
if (!dv_as_opaque (dv)
|| (!dv_is_value_p (dv) && ! DECL_P (dv_as_decl (dv))))
variable part is specified by its SET->vars slot SLOT and offset
OFFSET and the part's location by LOC. */
-static variable_def **
-delete_slot_part (dataflow_set *set, rtx loc, variable_def **slot,
+static variable **
+delete_slot_part (dataflow_set *set, rtx loc, variable **slot,
HOST_WIDE_INT offset)
{
- variable var = *slot;
+ variable *var = *slot;
int pos = find_variable_location_part (var, offset, NULL);
if (pos >= 0)
{
- location_chain node, next;
- location_chain *nextp;
+ location_chain *node, *next;
+ location_chain **nextp;
bool changed;
rtx cur_loc;
if (pos == 0 && var->onepart && VAR_LOC_1PAUX (var))
VAR_LOC_FROM (var) = NULL;
}
- pool_free (loc_chain_pool, node);
+ delete node;
*nextp = next;
break;
}
delete_variable_part (dataflow_set *set, rtx loc, decl_or_value dv,
HOST_WIDE_INT offset)
{
- variable_def **slot = shared_hash_find_slot_noinsert (set->vars, dv);
+ variable **slot = shared_hash_find_slot_noinsert (set->vars, dv);
if (!slot)
return;
struct expand_loc_callback_data
{
/* The variables and values active at this point. */
- variable_table_type vars;
+ variable_table_type *vars;
/* Stack of values and debug_exprs under expansion, and their
children. */
- stack_vec<rtx, 4> expanding;
+ auto_vec<rtx, 4> expanding;
/* Stack of values and debug_exprs whose expansion hit recursion
cycles. They will have VALUE_RECURSED_INTO marked when added to
resolves to a valid location. So, if the flag remains set at the
end of the search, we know no valid location for this one can
possibly exist. */
- stack_vec<rtx, 4> pending;
+ auto_vec<rtx, 4> pending;
/* The maximum depth among the sub-expressions under expansion.
Zero indicates no expansion so far. */
room for COUNT dependencies. */
static void
-loc_exp_dep_alloc (variable var, int count)
+loc_exp_dep_alloc (variable *var, int count)
{
size_t allocsize;
removing them from the back-links lists too. */
static void
-loc_exp_dep_clear (variable var)
+loc_exp_dep_clear (variable *var)
{
while (VAR_LOC_DEP_VEC (var) && !VAR_LOC_DEP_VEC (var)->is_empty ())
{
back-links in VARS. */
static void
-loc_exp_insert_dep (variable var, rtx x, variable_table_type vars)
+loc_exp_insert_dep (variable *var, rtx x, variable_table_type *vars)
{
decl_or_value dv;
- variable xvar;
+ variable *xvar;
loc_exp_dep *led;
dv = dv_from_rtx (x);
/* ??? Build a vector of variables parallel to EXPANDING, to avoid
an additional look up? */
- xvar = vars.find_with_hash (dv, dv_htab_hash (dv));
+ xvar = vars->find_with_hash (dv, dv_htab_hash (dv));
if (!xvar)
{
return;
if (var->onepart == NOT_ONEPART)
- led = (loc_exp_dep *) pool_alloc (loc_exp_dep_pool);
+ led = new loc_exp_dep;
else
{
loc_exp_dep empty;
true if we found any pending-recursion results. */
static bool
-loc_exp_dep_set (variable var, rtx result, rtx *value, int count,
- variable_table_type vars)
+loc_exp_dep_set (variable *var, rtx result, rtx *value, int count,
+ variable_table_type *vars)
{
bool pending_recursion = false;
attempt to compute a current location. */
static void
-notify_dependents_of_resolved_value (variable ivar, variable_table_type vars)
+notify_dependents_of_resolved_value (variable *ivar, variable_table_type *vars)
{
loc_exp_dep *led, *next;
for (led = VAR_LOC_DEP_LST (ivar); led; led = next)
{
decl_or_value dv = led->dv;
- variable var;
+ variable *var;
next = led->next;
continue;
}
- var = vars.find_with_hash (dv, dv_htab_hash (dv));
+ var = vars->find_with_hash (dv, dv_htab_hash (dv));
if (!var)
var = variable_from_dropped (dv, NO_INSERT);
it is pending recursion resolution. */
static inline rtx
-vt_expand_var_loc_chain (variable var, bitmap regs, void *data, bool *pendrecp)
+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;
- location_chain loc, next;
+ location_chain *loc, *next;
rtx result = NULL;
int first_child, result_first_child, last_child;
bool pending_recursion;
struct expand_loc_callback_data *elcd
= (struct expand_loc_callback_data *) data;
decl_or_value dv;
- variable var;
+ variable *var;
rtx result, subreg;
bool pending_recursion = false;
bool from_empty = false;
return NULL;
}
- var = elcd->vars.find_with_hash (dv, dv_htab_hash (dv));
+ var = elcd->vars->find_with_hash (dv, dv_htab_hash (dv));
if (!var)
{
equivalences in VARS, updating their CUR_LOCs in the process. */
static rtx
-vt_expand_loc (rtx loc, variable_table_type vars)
+vt_expand_loc (rtx loc, variable_table_type *vars)
{
struct expand_loc_callback_data data;
rtx result;
in VARS, updating their CUR_LOCs in the process. */
static rtx
-vt_expand_1pvar (variable var, variable_table_type vars)
+vt_expand_1pvar (variable *var, variable_table_type *vars)
{
struct expand_loc_callback_data data;
rtx loc;
before or after instruction INSN. */
int
-emit_note_insn_var_location (variable_def **varp, emit_note_data *data)
+emit_note_insn_var_location (variable **varp, emit_note_data *data)
{
- variable var = *varp;
- rtx insn = data->insn;
+ variable *var = *varp;
+ rtx_insn *insn = data->insn;
enum emit_note_where where = data->where;
- variable_table_type vars = data->vars;
- rtx note, note_vl;
+ variable_table_type *vars = data->vars;
+ rtx_note *note;
+ rtx note_vl;
int i, j, n_var_parts;
bool complete;
enum var_init_status initialized = VAR_INIT_STATUS_UNINITIALIZED;
HOST_WIDE_INT offsets[MAX_VAR_PARTS];
rtx loc[MAX_VAR_PARTS];
tree decl;
- location_chain lc;
+ location_chain *lc;
gcc_checking_assert (var->onepart == NOT_ONEPART
|| var->onepart == ONEPART_VDECL);
var->var_part[i].cur_loc = var->var_part[i].loc_chain->loc;
for (i = 0; i < var->n_var_parts; i++)
{
- enum machine_mode mode, wider_mode;
+ machine_mode mode, wider_mode;
rtx loc2;
HOST_WIDE_INT offset;
note_vl = NULL_RTX;
if (!complete)
- note_vl = gen_rtx_VAR_LOCATION (VOIDmode, decl, NULL_RTX,
- (int) initialized);
+ note_vl = gen_rtx_VAR_LOCATION (VOIDmode, decl, NULL_RTX, initialized);
else if (n_var_parts == 1)
{
rtx expr_list;
else
expr_list = loc[0];
- note_vl = gen_rtx_VAR_LOCATION (VOIDmode, decl, expr_list,
- (int) initialized);
+ note_vl = gen_rtx_VAR_LOCATION (VOIDmode, decl, expr_list, initialized);
}
else if (n_var_parts)
{
parallel = gen_rtx_PARALLEL (VOIDmode,
gen_rtvec_v (n_var_parts, loc));
note_vl = gen_rtx_VAR_LOCATION (VOIDmode, decl,
- parallel, (int) initialized);
+ parallel, initialized);
}
if (where != EMIT_NOTE_BEFORE_INSN)
set_dv_changed (var->dv, false);
gcc_assert (var->in_changed_variables);
var->in_changed_variables = false;
- changed_variables.clear_slot (varp);
+ changed_variables->clear_slot (varp);
/* Continue traversing the hash table. */
return 1;
values) entries that aren't user variables. */
int
-var_track_values_to_stack (variable_def **slot,
+var_track_values_to_stack (variable **slot,
vec<rtx, va_heap> *changed_values_stack)
{
- variable var = *slot;
+ variable *var = *slot;
if (var->onepart == ONEPART_VALUE)
changed_values_stack->safe_push (dv_as_value (var->dv));
remove_value_from_changed_variables (rtx val)
{
decl_or_value dv = dv_from_rtx (val);
- variable_def **slot;
- variable var;
+ variable **slot;
+ variable *var;
- slot = changed_variables.find_slot_with_hash (dv, dv_htab_hash (dv),
+ slot = changed_variables->find_slot_with_hash (dv, dv_htab_hash (dv),
NO_INSERT);
var = *slot;
var->in_changed_variables = false;
- changed_variables.clear_slot (slot);
+ changed_variables->clear_slot (slot);
}
/* If VAL (a value or debug_expr) has backlinks to variables actively
have dependencies of their own to notify. */
static void
-notify_dependents_of_changed_value (rtx val, variable_table_type htab,
+notify_dependents_of_changed_value (rtx val, variable_table_type *htab,
vec<rtx, va_heap> *changed_values_stack)
{
- variable_def **slot;
- variable var;
+ variable **slot;
+ variable *var;
loc_exp_dep *led;
decl_or_value dv = dv_from_rtx (val);
- slot = changed_variables.find_slot_with_hash (dv, dv_htab_hash (dv),
+ slot = changed_variables->find_slot_with_hash (dv, dv_htab_hash (dv),
NO_INSERT);
if (!slot)
- slot = htab.find_slot_with_hash (dv, dv_htab_hash (dv), NO_INSERT);
+ slot = htab->find_slot_with_hash (dv, dv_htab_hash (dv), NO_INSERT);
if (!slot)
- slot = dropped_values.find_slot_with_hash (dv, dv_htab_hash (dv),
- NO_INSERT);
+ slot = dropped_values->find_slot_with_hash (dv, dv_htab_hash (dv),
+ NO_INSERT);
var = *slot;
while ((led = VAR_LOC_DEP_LST (var)))
{
decl_or_value ldv = led->dv;
- variable ivar;
+ variable *ivar;
/* Deactivate and remove the backlink, as it was “used up”. It
makes no sense to attempt to notify the same entity again:
break;
case ONEPART_VDECL:
- ivar = htab.find_with_hash (ldv, dv_htab_hash (ldv));
+ ivar = htab->find_with_hash (ldv, dv_htab_hash (ldv));
gcc_checking_assert (!VAR_LOC_DEP_LST (ivar));
variable_was_changed (ivar, NULL);
break;
case NOT_ONEPART:
- pool_free (loc_exp_dep_pool, led);
- ivar = htab.find_with_hash (ldv, dv_htab_hash (ldv));
+ delete led;
+ ivar = htab->find_with_hash (ldv, dv_htab_hash (ldv));
if (ivar)
{
int i = ivar->n_var_parts;
CHANGED_VARIABLES. */
static void
-process_changed_values (variable_table_type htab)
+process_changed_values (variable_table_type *htab)
{
int i, n;
rtx val;
- stack_vec<rtx, 20> changed_values_stack;
+ auto_vec<rtx, 20> changed_values_stack;
/* Move values from changed_variables to changed_values_stack. */
changed_variables
- .traverse <vec<rtx, va_heap>*, var_track_values_to_stack>
+ ->traverse <vec<rtx, va_heap>*, var_track_values_to_stack>
(&changed_values_stack);
/* Back-propagate change notifications in values while popping
the notes shall be emitted before of after instruction INSN. */
static void
-emit_notes_for_changes (rtx insn, enum emit_note_where where,
- shared_hash vars)
+emit_notes_for_changes (rtx_insn *insn, enum emit_note_where where,
+ shared_hash *vars)
{
emit_note_data data;
- variable_table_type htab = shared_hash_htab (vars);
+ variable_table_type *htab = shared_hash_htab (vars);
- if (!changed_variables.elements ())
+ if (!changed_variables->elements ())
return;
if (MAY_HAVE_DEBUG_INSNS)
data.vars = htab;
changed_variables
- .traverse <emit_note_data*, emit_note_insn_var_location> (&data);
+ ->traverse <emit_note_data*, emit_note_insn_var_location> (&data);
}
/* Add variable *SLOT to the chain CHANGED_VARIABLES if it differs from the
same variable in hash table DATA or is not there at all. */
int
-emit_notes_for_differences_1 (variable_def **slot, variable_table_type new_vars)
+emit_notes_for_differences_1 (variable **slot, variable_table_type *new_vars)
{
- variable old_var, new_var;
+ variable *old_var, *new_var;
old_var = *slot;
- new_var = new_vars.find_with_hash (old_var->dv, dv_htab_hash (old_var->dv));
+ new_var = new_vars->find_with_hash (old_var->dv, dv_htab_hash (old_var->dv));
if (!new_var)
{
/* Variable has disappeared. */
- variable empty_var = NULL;
+ variable *empty_var = NULL;
if (old_var->onepart == ONEPART_VALUE
|| old_var->onepart == ONEPART_DEXPR)
if (!empty_var)
{
- empty_var = (variable) pool_alloc (onepart_pool (old_var->onepart));
+ empty_var = onepart_pool_allocate (old_var->onepart);
empty_var->dv = old_var->dv;
empty_var->refcount = 0;
empty_var->n_var_parts = 0;
table DATA. */
int
-emit_notes_for_differences_2 (variable_def **slot, variable_table_type old_vars)
+emit_notes_for_differences_2 (variable **slot, variable_table_type *old_vars)
{
- variable old_var, new_var;
+ variable *old_var, *new_var;
new_var = *slot;
- old_var = old_vars.find_with_hash (new_var->dv, dv_htab_hash (new_var->dv));
+ old_var = old_vars->find_with_hash (new_var->dv, dv_htab_hash (new_var->dv));
if (!old_var)
{
int i;
NEW_SET. */
static void
-emit_notes_for_differences (rtx insn, dataflow_set *old_set,
+emit_notes_for_differences (rtx_insn *insn, dataflow_set *old_set,
dataflow_set *new_set)
{
shared_hash_htab (old_set->vars)
- .traverse <variable_table_type, emit_notes_for_differences_1>
+ ->traverse <variable_table_type *, emit_notes_for_differences_1>
(shared_hash_htab (new_set->vars));
shared_hash_htab (new_set->vars)
- .traverse <variable_table_type, emit_notes_for_differences_2>
+ ->traverse <variable_table_type *, emit_notes_for_differences_2>
(shared_hash_htab (old_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)
+static rtx_insn *
+next_non_note_insn_var_location (rtx_insn *insn)
{
while (insn)
{
FOR_EACH_VEC_ELT (VTI (bb)->mos, i, mo)
{
- rtx insn = mo->insn;
- rtx next_insn = next_non_note_insn_var_location (insn);
+ rtx_insn *insn = mo->insn;
+ rtx_insn *next_insn = next_non_note_insn_var_location (insn);
switch (mo->type)
{
case MO_CALL:
- dataflow_set_clear_at_call (set);
+ dataflow_set_clear_at_call (set, insn);
emit_notes_for_changes (insn, EMIT_NOTE_AFTER_CALL_INSN, set->vars);
{
- rtx arguments = mo->u.loc, *p = &arguments, note;
+ rtx arguments = mo->u.loc, *p = &arguments;
+ rtx_note *note;
while (*p)
{
XEXP (XEXP (*p, 0), 1)
basic_block bb;
dataflow_set cur;
- gcc_assert (!changed_variables.elements ());
+ gcc_assert (!changed_variables->elements ());
/* Free memory occupied by the out hash tables, as they aren't used
anymore. */
if (MAY_HAVE_DEBUG_INSNS)
{
- dropped_values.create (cselib_get_next_uid () * 2);
- loc_exp_dep_pool = create_alloc_pool ("loc_exp_dep pool",
- sizeof (loc_exp_dep), 64);
+ dropped_values = new variable_table_type (cselib_get_next_uid () * 2);
}
dataflow_set_init (&cur);
emit_notes_for_differences (BB_HEAD (bb), &cur, &VTI (bb)->in);
if (MAY_HAVE_DEBUG_INSNS)
- local_get_addr_cache = pointer_map_create ();
+ local_get_addr_cache = new hash_map<rtx, rtx>;
/* Emit the notes for the changes in the basic block itself. */
emit_notes_in_bb (bb, &cur);
if (MAY_HAVE_DEBUG_INSNS)
- pointer_map_destroy (local_get_addr_cache);
+ delete local_get_addr_cache;
local_get_addr_cache = NULL;
/* Free memory occupied by the in hash table, we won't need it
again. */
dataflow_set_clear (&VTI (bb)->in);
}
-#ifdef ENABLE_CHECKING
- shared_hash_htab (cur.vars)
- .traverse <variable_table_type, emit_notes_for_differences_1>
- (shared_hash_htab (empty_shared_hash));
-#endif
+
+ if (flag_checking)
+ shared_hash_htab (cur.vars)
+ ->traverse <variable_table_type *, emit_notes_for_differences_1>
+ (shared_hash_htab (empty_shared_hash));
+
dataflow_set_destroy (&cur);
if (MAY_HAVE_DEBUG_INSNS)
- dropped_values.dispose ();
+ delete dropped_values;
+ dropped_values = NULL;
emit_notes = false;
}
rtx decl_rtl = DECL_RTL_IF_SET (parm);
rtx incoming = DECL_INCOMING_RTL (parm);
tree decl;
- enum machine_mode mode;
+ machine_mode mode;
HOST_WIDE_INT offset;
dataflow_set *out;
decl_or_value dv;
&& HARD_REGISTER_P (incoming)
&& OUTGOING_REGNO (REGNO (incoming)) != REGNO (incoming))
{
- parm_reg_t p;
+ parm_reg p;
p.incoming = incoming;
incoming
= gen_rtx_REG_offset (incoming, GET_MODE (incoming),
for (i = 0; i < XVECLEN (incoming, 0); i++)
{
rtx reg = XEXP (XVECEXP (incoming, 0, i), 0);
- parm_reg_t p;
+ parm_reg p;
p.incoming = reg;
reg = gen_rtx_REG_offset (reg, GET_MODE (reg),
OUTGOING_REGNO (REGNO (reg)), 0);
rtx reg = XEXP (incoming, 0);
if (OUTGOING_REGNO (REGNO (reg)) != REGNO (reg))
{
- parm_reg_t p;
+ parm_reg p;
p.incoming = reg;
reg = gen_raw_REG (GET_MODE (reg), OUTGOING_REGNO (REGNO (reg)));
p.outgoing = reg;
if (TREE_CODE (TREE_TYPE (parm)) == REFERENCE_TYPE
&& INTEGRAL_TYPE_P (TREE_TYPE (TREE_TYPE (parm))))
{
- enum machine_mode indmode
+ machine_mode indmode
= TYPE_MODE (TREE_TYPE (TREE_TYPE (parm)));
rtx mem = gen_rtx_MEM (indmode, incoming);
cselib_val *val = cselib_lookup_from_insn (mem, indmode, true,
for (parm = DECL_ARGUMENTS (current_function_decl);
parm; parm = DECL_CHAIN (parm))
- vt_add_function_parameter (parm);
+ if (!POINTER_BOUNDS_P (parm))
+ vt_add_function_parameter (parm);
if (DECL_HAS_VALUE_EXPR_P (DECL_RESULT (current_function_decl)))
{
basic_block bb;
HOST_WIDE_INT fp_cfa_offset = -1;
- alloc_aux_for_blocks (sizeof (struct variable_tracking_info_def));
-
- attrs_pool = create_alloc_pool ("attrs_def pool",
- sizeof (struct attrs_def), 1024);
- var_pool = create_alloc_pool ("variable_def pool",
- sizeof (struct variable_def)
- + (MAX_VAR_PARTS - 1)
- * sizeof (((variable)NULL)->var_part[0]), 64);
- loc_chain_pool = create_alloc_pool ("location_chain_def pool",
- sizeof (struct location_chain_def),
- 1024);
- shared_hash_pool = create_alloc_pool ("shared_hash_def pool",
- sizeof (struct shared_hash_def), 256);
- empty_shared_hash = (shared_hash) pool_alloc (shared_hash_pool);
+ alloc_aux_for_blocks (sizeof (variable_tracking_info));
+
+ empty_shared_hash = shared_hash_pool.allocate ();
empty_shared_hash->refcount = 1;
- empty_shared_hash->htab.create (1);
- changed_variables.create (10);
+ empty_shared_hash->htab = new variable_table_type (1);
+ changed_variables = new variable_table_type (10);
/* Init the IN and OUT sets. */
FOR_ALL_BB_FN (bb, cfun)
{
cselib_init (CSELIB_RECORD_MEMORY | CSELIB_PRESERVE_CONSTANTS);
scratch_regs = BITMAP_ALLOC (NULL);
- valvar_pool = create_alloc_pool ("small variable_def pool",
- sizeof (struct variable_def), 256);
preserved_values.create (256);
- global_get_addr_cache = pointer_map_create ();
+ global_get_addr_cache = new hash_map<rtx, rtx>;
}
else
{
scratch_regs = NULL;
- valvar_pool = NULL;
global_get_addr_cache = NULL;
}
val = cselib_lookup_from_insn (reg, GET_MODE (reg), 1,
VOIDmode, get_insns ());
preserve_value (val);
- cselib_preserve_cfa_base_value (val, REGNO (reg));
+ 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 ());
FOR_EACH_BB_FN (bb, cfun)
{
- rtx insn;
+ rtx_insn *insn;
HOST_WIDE_INT pre, post = 0;
basic_block first_bb, last_bb;
delete_debug_insns (void)
{
basic_block bb;
- rtx insn, next;
+ rtx_insn *insn, *next;
if (!MAY_HAVE_DEBUG_INSNS)
return;
}
}
free_aux_for_blocks ();
- empty_shared_hash->htab.dispose ();
- changed_variables.dispose ();
- free_alloc_pool (attrs_pool);
- free_alloc_pool (var_pool);
- free_alloc_pool (loc_chain_pool);
- free_alloc_pool (shared_hash_pool);
+ delete empty_shared_hash->htab;
+ empty_shared_hash->htab = NULL;
+ delete changed_variables;
+ changed_variables = NULL;
+ attrs_pool.release ();
+ var_pool.release ();
+ location_chain_pool.release ();
+ shared_hash_pool.release ();
if (MAY_HAVE_DEBUG_INSNS)
{
if (global_get_addr_cache)
- pointer_map_destroy (global_get_addr_cache);
+ delete global_get_addr_cache;
global_get_addr_cache = NULL;
- if (loc_exp_dep_pool)
- free_alloc_pool (loc_exp_dep_pool);
- loc_exp_dep_pool = NULL;
- free_alloc_pool (valvar_pool);
+ loc_exp_dep_pool.release ();
+ valvar_pool.release ();
preserved_values.release ();
cselib_finish ();
BITMAP_FREE (scratch_regs);
{
bool success;
- if (flag_var_tracking_assignments < 0)
+ if (flag_var_tracking_assignments < 0
+ /* Var-tracking right now assumes the IR doesn't contain
+ any pseudos at this point. */
+ || targetm.no_register_allocation)
{
delete_debug_insns ();
return 0;
return ret;
}
\f
-static bool
-gate_handle_var_tracking (void)
-{
- return (flag_var_tracking && !targetm.delay_vartrack);
-}
-
-
-
namespace {
const pass_data pass_data_variable_tracking =
RTL_PASS, /* type */
"vartrack", /* name */
OPTGROUP_NONE, /* optinfo_flags */
- true, /* has_gate */
- true, /* has_execute */
TV_VAR_TRACKING, /* tv_id */
0, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- ( TODO_verify_rtl_sharing | TODO_verify_flow ), /* todo_flags_finish */
+ 0, /* todo_flags_finish */
};
class pass_variable_tracking : public rtl_opt_pass
{}
/* opt_pass methods: */
- bool gate () { return gate_handle_var_tracking (); }
- unsigned int execute () { return variable_tracking_main (); }
+ virtual bool gate (function *)
+ {
+ return (flag_var_tracking && !targetm.delay_vartrack);
+ }
+
+ virtual unsigned int execute (function *)
+ {
+ return variable_tracking_main ();
+ }
}; // class pass_variable_tracking