/* Variable tracking routines for the GNU compiler.
- Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
+ the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful, but WITHOUT
License for more details.
You should have received a copy of the GNU General Public License
- along with GCC; see the file COPYING. If not, write to the Free
- Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301, USA. */
+ along with GCC; see the file COPYING3. If not see
+ <http://www.gnu.org/licenses/>. */
/* This file contains the variable tracking pass. It computes where
variables are located (which registers or where in memory) at each position
enum micro_operation_type type;
union {
- /* Location. */
+ /* Location. For MO_SET and MO_COPY, this is the SET that performs
+ the assignment, if known, otherwise it is the target of the
+ assignment. */
rtx loc;
/* Stack adjustment. */
/* The location (REG or MEM). */
rtx loc;
+
+ /* The "value" stored in this location. */
+ rtx set_src;
+
+ /* Initialized? */
+ enum var_init_status init;
} *location_chain;
/* Structure describing one part of variable. */
/* The variable parts. */
variable_part var_part[MAX_VAR_PARTS];
} *variable;
+typedef const struct variable_def *const_variable;
/* Hash function for DECL for VARIABLE_HTAB. */
#define VARIABLE_HASH_VAL(decl) (DECL_UID (decl))
/* Pointer to the BB's information specific to variable tracking pass. */
#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 (mem) ? INTVAL (MEM_OFFSET (mem)) : 0)
+
/* Alloc pool for struct attrs_def. */
static alloc_pool attrs_pool;
static void attrs_list_union (attrs *, attrs);
static void vars_clear (htab_t);
-static variable unshare_variable (dataflow_set *set, variable var);
+static variable unshare_variable (dataflow_set *set, variable var,
+ enum var_init_status);
static int vars_copy_1 (void **, void *);
static void vars_copy (htab_t, htab_t);
static tree var_debug_decl (tree);
-static void var_reg_set (dataflow_set *, rtx);
-static void var_reg_delete_and_set (dataflow_set *, rtx, bool);
+static void var_reg_set (dataflow_set *, rtx, enum var_init_status, rtx);
+static void var_reg_delete_and_set (dataflow_set *, rtx, bool,
+ enum var_init_status, rtx);
static void var_reg_delete (dataflow_set *, rtx, bool);
static void var_regno_delete (dataflow_set *, int);
-static void var_mem_set (dataflow_set *, rtx);
-static void var_mem_delete_and_set (dataflow_set *, rtx, bool);
+static void var_mem_set (dataflow_set *, rtx, enum var_init_status, rtx);
+static void var_mem_delete_and_set (dataflow_set *, rtx, bool,
+ enum var_init_status, rtx);
static void var_mem_delete (dataflow_set *, rtx, bool);
static void dataflow_set_init (dataflow_set *, int);
static bool same_variable_part_p (rtx, tree, HOST_WIDE_INT);
static int count_uses (rtx *, void *);
static void count_uses_1 (rtx *, void *);
-static void count_stores (rtx, rtx, void *);
+static void count_stores (rtx, const_rtx, void *);
static int add_uses (rtx *, void *);
static void add_uses_1 (rtx *, void *);
-static void add_stores (rtx, rtx, void *);
+static void add_stores (rtx, const_rtx, void *);
static bool compute_bb_dataflow (basic_block);
static void vt_find_locations (void);
static void dump_dataflow_sets (void);
static void variable_was_changed (variable, htab_t);
-static void set_variable_part (dataflow_set *, rtx, tree, HOST_WIDE_INT);
-static void clobber_variable_part (dataflow_set *, rtx, tree, HOST_WIDE_INT);
+static void set_variable_part (dataflow_set *, rtx, tree, HOST_WIDE_INT,
+ enum var_init_status, rtx);
+static void clobber_variable_part (dataflow_set *, rtx, tree, HOST_WIDE_INT,
+ rtx);
static void delete_variable_part (dataflow_set *, rtx, tree, HOST_WIDE_INT);
static int emit_note_insn_var_location (void **, void *);
static void emit_notes_for_changes (rtx, enum emit_note_where);
static hashval_t
variable_htab_hash (const void *x)
{
- const variable v = (const variable) x;
+ const_variable const v = (const_variable) x;
return (VARIABLE_HASH_VAL (v->decl));
}
static int
variable_htab_eq (const void *x, const void *y)
{
- const variable v = (const variable) x;
- const tree decl = (const tree) y;
+ const_variable const v = (const_variable) x;
+ const_tree const decl = (const_tree) y;
return (VARIABLE_HASH_VAL (v->decl) == VARIABLE_HASH_VAL (decl));
}
/* Return a copy of a variable VAR and insert it to dataflow set SET. */
static variable
-unshare_variable (dataflow_set *set, variable var)
+unshare_variable (dataflow_set *set, variable var,
+ enum var_init_status initialized)
{
void **slot;
variable new_var;
new_lc = pool_alloc (loc_chain_pool);
new_lc->next = NULL;
+ if (node->init > initialized)
+ new_lc->init = node->init;
+ else
+ new_lc->init = initialized;
+ if (node->set_src && !(MEM_P (node->set_src)))
+ new_lc->set_src = node->set_src;
+ else
+ new_lc->set_src = NULL;
new_lc->loc = node->loc;
*nextp = new_lc;
/* Set the register to contain REG_EXPR (LOC), REG_OFFSET (LOC). */
static void
-var_reg_set (dataflow_set *set, rtx loc)
+var_reg_set (dataflow_set *set, rtx loc, enum var_init_status initialized,
+ rtx set_src)
{
tree decl = REG_EXPR (loc);
HOST_WIDE_INT offset = REG_OFFSET (loc);
break;
if (!node)
attrs_list_insert (&set->regs[REGNO (loc)], decl, offset, loc);
- set_variable_part (set, loc, decl, offset);
+ set_variable_part (set, loc, decl, offset, initialized, set_src);
+}
+
+static int
+get_init_value (dataflow_set *set, rtx loc, tree decl)
+{
+ void **slot;
+ variable var;
+ int i;
+ int ret_val = VAR_INIT_STATUS_UNKNOWN;
+
+ if (! flag_var_tracking_uninit)
+ return VAR_INIT_STATUS_INITIALIZED;
+
+ slot = htab_find_slot_with_hash (set->vars, decl, VARIABLE_HASH_VAL (decl),
+ NO_INSERT);
+ if (slot)
+ {
+ var = * (variable *) slot;
+ for (i = 0; i < var->n_var_parts && ret_val == VAR_INIT_STATUS_UNKNOWN; i++)
+ {
+ location_chain nextp;
+ for (nextp = var->var_part[i].loc_chain; nextp; nextp = nextp->next)
+ if (rtx_equal_p (nextp->loc, loc))
+ {
+ ret_val = nextp->init;
+ break;
+ }
+ }
+ }
+
+ return ret_val;
}
/* Delete current content of register LOC in dataflow set SET and set
part. */
static void
-var_reg_delete_and_set (dataflow_set *set, rtx loc, bool modify)
+var_reg_delete_and_set (dataflow_set *set, rtx loc, bool modify,
+ enum var_init_status initialized, rtx set_src)
{
tree decl = REG_EXPR (loc);
HOST_WIDE_INT offset = REG_OFFSET (loc);
decl = var_debug_decl (decl);
+ if (initialized == VAR_INIT_STATUS_UNKNOWN)
+ initialized = get_init_value (set, loc, decl);
+
nextp = &set->regs[REGNO (loc)];
for (node = *nextp; node; node = next)
{
}
}
if (modify)
- clobber_variable_part (set, loc, decl, offset);
- var_reg_set (set, loc);
+ clobber_variable_part (set, loc, decl, offset, set_src);
+ var_reg_set (set, loc, initialized, set_src);
}
/* Delete current content of register LOC in dataflow set SET. If
decl = var_debug_decl (decl);
- clobber_variable_part (set, NULL, decl, offset);
+ clobber_variable_part (set, NULL, decl, offset, NULL);
}
for (node = *reg; node; node = next)
Adjust the address first if it is stack pointer based. */
static void
-var_mem_set (dataflow_set *set, rtx loc)
+var_mem_set (dataflow_set *set, rtx loc, enum var_init_status initialized,
+ rtx set_src)
{
tree decl = MEM_EXPR (loc);
- HOST_WIDE_INT offset = MEM_OFFSET (loc) ? INTVAL (MEM_OFFSET (loc)) : 0;
+ HOST_WIDE_INT offset = INT_MEM_OFFSET (loc);
decl = var_debug_decl (decl);
- set_variable_part (set, loc, decl, offset);
+ set_variable_part (set, loc, decl, offset, initialized, set_src);
}
/* Delete and set the location part of variable MEM_EXPR (LOC) in
Adjust the address first if it is stack pointer based. */
static void
-var_mem_delete_and_set (dataflow_set *set, rtx loc, bool modify)
+var_mem_delete_and_set (dataflow_set *set, rtx loc, bool modify,
+ enum var_init_status initialized, rtx set_src)
{
tree decl = MEM_EXPR (loc);
- HOST_WIDE_INT offset = MEM_OFFSET (loc) ? INTVAL (MEM_OFFSET (loc)) : 0;
+ HOST_WIDE_INT offset = INT_MEM_OFFSET (loc);
decl = var_debug_decl (decl);
+ if (initialized == VAR_INIT_STATUS_UNKNOWN)
+ initialized = get_init_value (set, loc, decl);
+
if (modify)
- clobber_variable_part (set, NULL, decl, offset);
- var_mem_set (set, loc);
+ clobber_variable_part (set, NULL, decl, offset, set_src);
+ var_mem_set (set, loc, initialized, set_src);
}
/* Delete the location part LOC from dataflow set SET. If CLOBBER is
var_mem_delete (dataflow_set *set, rtx loc, bool clobber)
{
tree decl = MEM_EXPR (loc);
- HOST_WIDE_INT offset = MEM_OFFSET (loc) ? INTVAL (MEM_OFFSET (loc)) : 0;
+ HOST_WIDE_INT offset = INT_MEM_OFFSET (loc);
decl = var_debug_decl (decl);
if (clobber)
- clobber_variable_part (set, NULL, decl, offset);
+ clobber_variable_part (set, NULL, decl, offset, NULL);
delete_variable_part (set, loc, decl, offset);
}
}
}
if (k < src->n_var_parts)
- unshare_variable (set, src);
+ {
+ enum var_init_status status = VAR_INIT_STATUS_UNKNOWN;
+
+ if (! flag_var_tracking_uninit)
+ status = VAR_INIT_STATUS_INITIALIZED;
+
+ unshare_variable (set, src, status);
+ }
else
*dstp = src;
gcc_assert (k <= MAX_VAR_PARTS);
if (dst->refcount > 1 && dst->n_var_parts != k)
- dst = unshare_variable (set, dst);
+ {
+ enum var_init_status status = VAR_INIT_STATUS_UNKNOWN;
+
+ if (! flag_var_tracking_uninit)
+ status = VAR_INIT_STATUS_INITIALIZED;
+ dst = unshare_variable (set, dst, status);
+ }
i = src->n_var_parts - 1;
j = dst->n_var_parts - 1;
&& REG_P (node->loc)
&& REGNO (node2->loc) == REGNO (node->loc))
|| rtx_equal_p (node2->loc, node->loc)))
- break;
+ {
+ if (node2->init < node->init)
+ node2->init = node->init;
+ break;
+ }
}
if (node || node2)
- dst = unshare_variable (set, dst);
+ dst = unshare_variable (set, dst, VAR_INIT_STATUS_UNKNOWN);
}
src_l = 0;
/* Copy the location from SRC. */
new_node = pool_alloc (loc_chain_pool);
new_node->loc = node->loc;
+ new_node->init = node->init;
+ if (!node->set_src || MEM_P (node->set_src))
+ new_node->set_src = NULL;
+ else
+ new_node->set_src = node->set_src;
vui[n].lc = new_node;
vui[n].pos_src = ii;
vui[n].pos_dst = src_l + dst_l;
new_lc = pool_alloc (loc_chain_pool);
new_lc->next = NULL;
+ new_lc->init = node->init;
+ if (!node->set_src || MEM_P (node->set_src))
+ new_lc->set_src = NULL;
+ else
+ new_lc->set_src = node->set_src;
new_lc->loc = node->loc;
*nextp = new_lc;
dst->var_part[k].cur_loc = NULL;
}
+ for (i = 0; i < src->n_var_parts && i < dst->n_var_parts; i++)
+ {
+ 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))
+ {
+ if (node->init > node2->init)
+ node2->init = node->init;
+ }
+ }
+
/* Continue traversing the hash table. */
return 1;
}
return 1;
}
+/* Return true if OFFSET is a valid offset for a register or memory
+ access we want to track. This is used to reject out-of-bounds
+ accesses that can cause assertions to fail later. Note that we
+ don't reject negative offsets because they can be generated for
+ paradoxical subregs on big-endian architectures. */
+
+static inline bool
+offset_valid_for_tracked_p (HOST_WIDE_INT offset)
+{
+ return (-MAX_VAR_PARTS < offset) && (offset < MAX_VAR_PARTS);
+}
+
/* Determine whether a given LOC refers to the same variable part as
EXPR+OFFSET. */
else if (MEM_P (loc))
{
expr2 = MEM_EXPR (loc);
- offset2 = MEM_OFFSET (loc) ? INTVAL (MEM_OFFSET (loc)) : 0;
+ offset2 = INT_MEM_OFFSET (loc);
}
else
return false;
return (expr == expr2 && offset == offset2);
}
+/* REG is a register we want to track. If not all of REG contains useful
+ information, return the mode of the lowpart that does contain useful
+ information, otherwise return the mode of REG.
+
+ If REG was a paradoxical subreg, its REG_ATTRS will describe the
+ whole subreg, but only the old inner part is really relevant. */
+
+static enum machine_mode
+mode_for_reg_attrs (rtx reg)
+{
+ enum machine_mode mode;
+
+ mode = GET_MODE (reg);
+ if (!HARD_REGISTER_NUM_P (ORIGINAL_REGNO (reg)))
+ {
+ enum machine_mode pseudo_mode;
+
+ pseudo_mode = PSEUDO_REGNO_MODE (ORIGINAL_REGNO (reg));
+ if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (pseudo_mode))
+ mode = pseudo_mode;
+ }
+ return mode;
+}
+
+/* Return the MODE lowpart of LOC, or null if LOC is not something we
+ want to track. When returning nonnull, make sure that the attributes
+ on the returned value are updated. */
+
+static rtx
+var_lowpart (enum machine_mode mode, rtx loc)
+{
+ unsigned int offset, regno;
+
+ if (!REG_P (loc) && !MEM_P (loc))
+ return NULL;
+
+ if (GET_MODE (loc) == mode)
+ return loc;
+
+ offset = subreg_lowpart_offset (mode, GET_MODE (loc));
+
+ if (MEM_P (loc))
+ return adjust_address_nv (loc, mode, offset);
+
+ regno = REGNO (loc) + subreg_regno_offset (REGNO (loc), GET_MODE (loc),
+ offset, mode);
+ return gen_rtx_REG_offset (loc, mode, regno, offset);
+}
/* Count uses (register and memory references) LOC which will be tracked.
INSN is instruction which the LOC is part of. */
}
else if (MEM_P (*loc)
&& MEM_EXPR (*loc)
- && track_expr_p (MEM_EXPR (*loc)))
+ && track_expr_p (MEM_EXPR (*loc))
+ && offset_valid_for_tracked_p (INT_MEM_OFFSET (*loc)))
{
VTI (bb)->n_mos++;
}
INSN is instruction which the LOC is part of. */
static void
-count_stores (rtx loc, rtx expr ATTRIBUTE_UNUSED, void *insn)
+count_stores (rtx loc, const_rtx expr ATTRIBUTE_UNUSED, void *insn)
{
count_uses (&loc, insn);
}
basic_block bb = BLOCK_FOR_INSN ((rtx) insn);
micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++;
- mo->type = ((REG_EXPR (*loc) && track_expr_p (REG_EXPR (*loc)))
- ? MO_USE : MO_USE_NO_VAR);
- mo->u.loc = *loc;
+ if (REG_EXPR (*loc)
+ && track_expr_p (REG_EXPR (*loc))
+ && offset_valid_for_tracked_p (REG_OFFSET (*loc)))
+ {
+ mo->type = MO_USE;
+ mo->u.loc = var_lowpart (mode_for_reg_attrs (*loc), *loc);
+ }
+ else
+ {
+ mo->type = MO_USE_NO_VAR;
+ mo->u.loc = *loc;
+ }
mo->insn = (rtx) insn;
}
else if (MEM_P (*loc)
&& MEM_EXPR (*loc)
- && track_expr_p (MEM_EXPR (*loc)))
+ && track_expr_p (MEM_EXPR (*loc))
+ && offset_valid_for_tracked_p (INT_MEM_OFFSET (*loc)))
{
basic_block bb = BLOCK_FOR_INSN ((rtx) insn);
micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++;
INSN is instruction which the LOC is part of. */
static void
-add_stores (rtx loc, rtx expr, void *insn)
+add_stores (rtx loc, const_rtx expr, void *insn)
{
if (REG_P (loc))
{
micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++;
if (GET_CODE (expr) == CLOBBER
- || ! REG_EXPR (loc)
- || ! track_expr_p (REG_EXPR (loc)))
- mo->type = MO_CLOBBER;
- else if (GET_CODE (expr) == SET
- && SET_DEST (expr) == loc
- && same_variable_part_p (SET_SRC (expr),
- REG_EXPR (loc),
- REG_OFFSET (loc)))
- mo->type = MO_COPY;
+ || !(REG_EXPR (loc)
+ && track_expr_p (REG_EXPR (loc))
+ && offset_valid_for_tracked_p (REG_OFFSET (loc))))
+ {
+ mo->type = MO_CLOBBER;
+ mo->u.loc = loc;
+ }
else
- mo->type = MO_SET;
- mo->u.loc = loc;
- mo->insn = NEXT_INSN ((rtx) insn);
+ {
+ enum machine_mode mode = mode_for_reg_attrs (loc);
+ rtx src = NULL;
+
+ if (GET_CODE (expr) == SET && SET_DEST (expr) == loc)
+ src = var_lowpart (mode, SET_SRC (expr));
+ loc = var_lowpart (mode, loc);
+
+ if (src == NULL)
+ {
+ mo->type = MO_SET;
+ mo->u.loc = loc;
+ }
+ else
+ {
+ if (SET_SRC (expr) != src)
+ expr = gen_rtx_SET (VOIDmode, loc, src);
+ if (same_variable_part_p (src, REG_EXPR (loc), REG_OFFSET (loc)))
+ mo->type = MO_COPY;
+ else
+ mo->type = MO_SET;
+ mo->u.loc = CONST_CAST_RTX (expr);
+ }
+ }
+ mo->insn = (rtx) insn;
}
else if (MEM_P (loc)
&& MEM_EXPR (loc)
- && track_expr_p (MEM_EXPR (loc)))
+ && track_expr_p (MEM_EXPR (loc))
+ && offset_valid_for_tracked_p (INT_MEM_OFFSET (loc)))
{
basic_block bb = BLOCK_FOR_INSN ((rtx) insn);
micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++;
if (GET_CODE (expr) == CLOBBER)
- mo->type = MO_CLOBBER;
- else if (GET_CODE (expr) == SET
- && SET_DEST (expr) == loc
- && same_variable_part_p (SET_SRC (expr),
- MEM_EXPR (loc),
- MEM_OFFSET (loc)
- ? INTVAL (MEM_OFFSET (loc)) : 0))
- mo->type = MO_COPY;
+ {
+ mo->type = MO_CLOBBER;
+ mo->u.loc = loc;
+ }
else
- mo->type = MO_SET;
- mo->u.loc = loc;
- mo->insn = NEXT_INSN ((rtx) insn);
+ {
+ rtx src = NULL;
+
+ if (GET_CODE (expr) == SET && SET_DEST (expr) == loc)
+ src = var_lowpart (GET_MODE (loc), SET_SRC (expr));
+
+ if (src == NULL)
+ {
+ mo->type = MO_SET;
+ mo->u.loc = loc;
+ }
+ else
+ {
+ if (same_variable_part_p (SET_SRC (expr),
+ MEM_EXPR (loc),
+ INT_MEM_OFFSET (loc)))
+ mo->type = MO_COPY;
+ else
+ mo->type = MO_SET;
+ mo->u.loc = CONST_CAST_RTX (expr);
+ }
+ }
+ mo->insn = (rtx) insn;
+ }
+}
+
+static enum var_init_status
+find_src_status (dataflow_set *in, rtx src)
+{
+ tree decl = NULL_TREE;
+ enum var_init_status status = VAR_INIT_STATUS_UNINITIALIZED;
+
+ if (! flag_var_tracking_uninit)
+ status = VAR_INIT_STATUS_INITIALIZED;
+
+ if (src && REG_P (src))
+ decl = var_debug_decl (REG_EXPR (src));
+ else if (src && MEM_P (src))
+ decl = var_debug_decl (MEM_EXPR (src));
+
+ if (src && decl)
+ status = get_init_value (in, src, decl);
+
+ return status;
+}
+
+/* SRC is the source of an assignment. Use SET to try to find what
+ was ultimately assigned to SRC. Return that value if known,
+ otherwise return SRC itself. */
+
+static rtx
+find_src_set_src (dataflow_set *set, rtx src)
+{
+ tree decl = NULL_TREE; /* The variable being copied around. */
+ rtx set_src = NULL_RTX; /* The value for "decl" stored in "src". */
+ void **slot;
+ variable var;
+ location_chain nextp;
+ int i;
+ bool found;
+
+ if (src && REG_P (src))
+ decl = var_debug_decl (REG_EXPR (src));
+ else if (src && MEM_P (src))
+ decl = var_debug_decl (MEM_EXPR (src));
+
+ if (src && decl)
+ {
+ slot = htab_find_slot_with_hash (set->vars, decl,
+ VARIABLE_HASH_VAL (decl), NO_INSERT);
+
+ if (slot)
+ {
+ var = *(variable *) slot;
+ found = false;
+ for (i = 0; i < var->n_var_parts && !found; i++)
+ for (nextp = var->var_part[i].loc_chain; nextp && !found;
+ nextp = nextp->next)
+ if (rtx_equal_p (nextp->loc, src))
+ {
+ set_src = nextp->set_src;
+ found = true;
+ }
+
+ }
}
+
+ return set_src;
}
/* Compute the changes of variable locations in the basic block BB. */
case MO_USE:
{
rtx loc = VTI (bb)->mos[i].u.loc;
+ enum var_init_status status = VAR_INIT_STATUS_UNINITIALIZED;
+
+ if (! flag_var_tracking_uninit)
+ status = VAR_INIT_STATUS_INITIALIZED;
if (GET_CODE (loc) == REG)
- var_reg_set (out, loc);
+ var_reg_set (out, loc, status, NULL);
else if (GET_CODE (loc) == MEM)
- var_mem_set (out, loc);
+ var_mem_set (out, loc, status, NULL);
}
break;
case MO_SET:
{
rtx loc = VTI (bb)->mos[i].u.loc;
+ rtx set_src = NULL;
+
+ if (GET_CODE (loc) == SET)
+ {
+ set_src = SET_SRC (loc);
+ loc = SET_DEST (loc);
+ }
if (REG_P (loc))
- var_reg_delete_and_set (out, loc, true);
+ var_reg_delete_and_set (out, loc, true, VAR_INIT_STATUS_INITIALIZED,
+ set_src);
else if (MEM_P (loc))
- var_mem_delete_and_set (out, loc, true);
+ var_mem_delete_and_set (out, loc, true, VAR_INIT_STATUS_INITIALIZED,
+ set_src);
}
break;
case MO_COPY:
{
rtx loc = VTI (bb)->mos[i].u.loc;
+ enum var_init_status src_status;
+ rtx set_src = NULL;
+
+ if (GET_CODE (loc) == SET)
+ {
+ set_src = SET_SRC (loc);
+ loc = SET_DEST (loc);
+ }
+
+ if (! flag_var_tracking_uninit)
+ src_status = VAR_INIT_STATUS_INITIALIZED;
+ else
+ src_status = find_src_status (in, set_src);
+
+ if (src_status == VAR_INIT_STATUS_UNKNOWN)
+ src_status = find_src_status (out, set_src);
+
+ set_src = find_src_set_src (in, set_src);
if (REG_P (loc))
- var_reg_delete_and_set (out, loc, false);
+ var_reg_delete_and_set (out, loc, false, src_status, set_src);
else if (MEM_P (loc))
- var_mem_delete_and_set (out, loc, false);
+ var_mem_delete_and_set (out, loc, false, src_status, set_src);
}
break;
int i;
location_chain node;
- fprintf (dump_file, " name: %s\n",
+ fprintf (dump_file, " name: %s",
IDENTIFIER_POINTER (DECL_NAME (var->decl)));
+ if (dump_flags & TDF_UID)
+ fprintf (dump_file, " D.%u\n", DECL_UID (var->decl));
+ else
+ fprintf (dump_file, "\n");
+
for (i = 0; i < var->n_var_parts; i++)
{
fprintf (dump_file, " offset %ld\n",
for (node = var->var_part[i].loc_chain; node; node = node->next)
{
fprintf (dump_file, " ");
+ if (node->init == VAR_INIT_STATUS_UNINITIALIZED)
+ fprintf (dump_file, "[uninit]");
print_rtl_single (dump_file, node->loc);
}
}
part's location by LOC. */
static void
-set_variable_part (dataflow_set *set, rtx loc, tree decl, HOST_WIDE_INT offset)
+set_variable_part (dataflow_set *set, rtx loc, tree decl, HOST_WIDE_INT offset,
+ enum var_init_status initialized, rtx set_src)
{
int pos;
location_chain node, next;
{
/* LOC is in the beginning of the chain so we have nothing
to do. */
+ if (node->init < initialized)
+ node->init = initialized;
+ if (set_src != NULL)
+ node->set_src = set_src;
+
+ *slot = var;
return;
}
else
{
/* We have to make a copy of a shared variable. */
if (var->refcount > 1)
- var = unshare_variable (set, var);
+ var = unshare_variable (set, var, initialized);
}
}
else
/* We have to make a copy of the shared variable. */
if (var->refcount > 1)
- var = unshare_variable (set, var);
+ var = unshare_variable (set, var, initialized);
/* We track only variables whose size is <= MAX_VAR_PARTS bytes
thus there are at most MAX_VAR_PARTS different offsets. */
&& REGNO (node->loc) == REGNO (loc))
|| rtx_equal_p (node->loc, loc))
{
+ /* Save these values, to assign to the new node, before
+ deleting this one. */
+ if (node->init > initialized)
+ initialized = node->init;
+ if (node->set_src != NULL && set_src == NULL)
+ set_src = node->set_src;
pool_free (loc_chain_pool, node);
*nextp = next;
break;
/* Add the location to the beginning. */
node = pool_alloc (loc_chain_pool);
node->loc = loc;
+ node->init = initialized;
+ node->set_src = set_src;
node->next = var->var_part[pos].loc_chain;
var->var_part[pos].loc_chain = node;
static void
clobber_variable_part (dataflow_set *set, rtx loc, tree decl,
- HOST_WIDE_INT offset)
+ HOST_WIDE_INT offset, rtx set_src)
{
void **slot;
for (node = next; node; node = next)
{
next = node->next;
- if (node->loc != loc)
+ if (node->loc != loc
+ && (!flag_var_tracking_uninit
+ || !set_src
+ || MEM_P (set_src)
+ || !rtx_equal_p (set_src, node->set_src)))
{
if (REG_P (node->loc))
{
&& REGNO (node->loc) == REGNO (loc))
|| rtx_equal_p (node->loc, loc))
{
- var = unshare_variable (set, var);
+ enum var_init_status status = VAR_INIT_STATUS_UNKNOWN;
+ if (! flag_var_tracking_uninit)
+ status = VAR_INIT_STATUS_INITIALIZED;
+ var = unshare_variable (set, var, status);
break;
}
}
rtx note;
int i, j, n_var_parts;
bool complete;
+ enum var_init_status initialized = VAR_INIT_STATUS_UNINITIALIZED;
HOST_WIDE_INT last_limit;
tree type_size_unit;
HOST_WIDE_INT offsets[MAX_VAR_PARTS];
gcc_assert (var->decl);
+ if (! flag_var_tracking_uninit)
+ initialized = VAR_INIT_STATUS_INITIALIZED;
+
complete = true;
last_limit = 0;
n_var_parts = 0;
offsets[n_var_parts] = var->var_part[i].offset;
loc[n_var_parts] = var->var_part[i].loc_chain->loc;
mode = GET_MODE (loc[n_var_parts]);
+ initialized = var->var_part[i].loc_chain->init;
last_limit = offsets[n_var_parts] + GET_MODE_SIZE (mode);
/* Attempt to merge adjacent registers or memory. */
else
note = emit_note_before (NOTE_INSN_VAR_LOCATION, insn);
+ if (! flag_var_tracking_uninit)
+ initialized = VAR_INIT_STATUS_INITIALIZED;
+
if (!complete)
{
NOTE_VAR_LOCATION (note) = gen_rtx_VAR_LOCATION (VOIDmode, var->decl,
- NULL_RTX);
+ NULL_RTX, (int) initialized);
}
else if (n_var_parts == 1)
{
= gen_rtx_EXPR_LIST (VOIDmode, loc[0], GEN_INT (offsets[0]));
NOTE_VAR_LOCATION (note) = gen_rtx_VAR_LOCATION (VOIDmode, var->decl,
- expr_list);
+ expr_list,
+ (int) initialized);
}
else if (n_var_parts)
{
parallel = gen_rtx_PARALLEL (VOIDmode,
gen_rtvec_v (n_var_parts, loc));
NOTE_VAR_LOCATION (note) = gen_rtx_VAR_LOCATION (VOIDmode, var->decl,
- parallel);
+ parallel,
+ (int) initialized);
}
htab_clear_slot (changed_variables, varp);
case MO_USE:
{
rtx loc = VTI (bb)->mos[i].u.loc;
-
+
+ enum var_init_status status = VAR_INIT_STATUS_UNINITIALIZED;
+ if (! flag_var_tracking_uninit)
+ status = VAR_INIT_STATUS_INITIALIZED;
if (GET_CODE (loc) == REG)
- var_reg_set (&set, loc);
+ var_reg_set (&set, loc, status, NULL);
else
- var_mem_set (&set, loc);
+ var_mem_set (&set, loc, status, NULL);
emit_notes_for_changes (insn, EMIT_NOTE_AFTER_INSN);
}
case MO_SET:
{
rtx loc = VTI (bb)->mos[i].u.loc;
+ rtx set_src = NULL;
+
+ if (GET_CODE (loc) == SET)
+ {
+ set_src = SET_SRC (loc);
+ loc = SET_DEST (loc);
+ }
if (REG_P (loc))
- var_reg_delete_and_set (&set, loc, true);
+ var_reg_delete_and_set (&set, loc, true, VAR_INIT_STATUS_INITIALIZED,
+ set_src);
else
- var_mem_delete_and_set (&set, loc, true);
+ var_mem_delete_and_set (&set, loc, true, VAR_INIT_STATUS_INITIALIZED,
+ set_src);
- emit_notes_for_changes (insn, EMIT_NOTE_BEFORE_INSN);
+ emit_notes_for_changes (NEXT_INSN (insn), EMIT_NOTE_BEFORE_INSN);
}
break;
case MO_COPY:
{
rtx loc = VTI (bb)->mos[i].u.loc;
+ enum var_init_status src_status;
+ rtx set_src = NULL;
+
+ if (GET_CODE (loc) == SET)
+ {
+ set_src = SET_SRC (loc);
+ loc = SET_DEST (loc);
+ }
+
+ src_status = find_src_status (&set, set_src);
+ set_src = find_src_set_src (&set, set_src);
if (REG_P (loc))
- var_reg_delete_and_set (&set, loc, false);
+ var_reg_delete_and_set (&set, loc, false, src_status, set_src);
else
- var_mem_delete_and_set (&set, loc, false);
+ var_mem_delete_and_set (&set, loc, false, src_status, set_src);
- emit_notes_for_changes (insn, EMIT_NOTE_BEFORE_INSN);
+ emit_notes_for_changes (NEXT_INSN (insn), EMIT_NOTE_BEFORE_INSN);
}
break;
else
var_mem_delete (&set, loc, true);
- emit_notes_for_changes (insn, EMIT_NOTE_BEFORE_INSN);
+ emit_notes_for_changes (NEXT_INSN (insn), EMIT_NOTE_BEFORE_INSN);
}
break;
if (MEM_ATTRS (rtl))
{
*declp = MEM_EXPR (rtl);
- *offsetp = MEM_OFFSET (rtl) ? INTVAL (MEM_OFFSET (rtl)) : 0;
+ *offsetp = INT_MEM_OFFSET (rtl);
return true;
}
}
gcc_assert (REGNO (incoming) < FIRST_PSEUDO_REGISTER);
attrs_list_insert (&out->regs[REGNO (incoming)],
parm, offset, incoming);
- set_variable_part (out, incoming, parm, offset);
+ set_variable_part (out, incoming, parm, offset, VAR_INIT_STATUS_INITIALIZED,
+ NULL);
}
else if (MEM_P (incoming))
- set_variable_part (out, incoming, parm, offset);
+ set_variable_part (out, incoming, parm, offset, VAR_INIT_STATUS_INITIALIZED,
+ NULL);
}
}
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- TODO_dump_func, /* todo_flags_finish */
+ TODO_dump_func | TODO_verify_rtl_sharing,/* todo_flags_finish */
'V' /* letter */
};