/* Variable tracking routines for the GNU compiler.
- Copyright (C) 2002, 2003, 2004 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, 59 Temple Place - Suite 330, Boston, MA
- 02111-1307, 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
#include "alloc-pool.h"
#include "fibheap.h"
#include "hashtab.h"
+#include "regs.h"
+#include "expr.h"
+#include "timevar.h"
+#include "tree-pass.h"
/* Type of micro operation. */
enum micro_operation_type
MO_USE_NO_VAR,/* Use location which is not associated with a variable
or the variable is not trackable. */
MO_SET, /* Set location. */
+ MO_COPY, /* Copy the same portion of a variable from one
+ location to another. */
MO_CLOBBER, /* Clobber location. */
MO_CALL, /* Call insn. */
- MO_ADJUST /* Adjust stack pointer. */
+ MO_ADJUST /* Adjust stack pointer. */
};
/* Where shall the note be emitted? BEFORE or AFTER the instruction. */
HOST_WIDE_INT adjust;
} u;
- /* The instruction which the micro operation is in. */
+ /* The instruction which the micro operation is in, for MO_USE,
+ MO_USE_NO_VAR, MO_CALL and MO_ADJUST, or the subsequent
+ 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;
} micro_operation;
/* 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 declaration of the variable. */
tree decl;
+ /* Reference count. */
+ int refcount;
+
/* Number of variable parts. */
int n_var_parts;
/* 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) ((size_t) (decl))
+#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)
/* Shall notes be emitted? */
static bool emit_notes;
-/* Fake variable for stack pointer. */
-tree frame_base_decl;
-
/* 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 *,
HOST_WIDE_INT *);
static void bb_stack_adjust_offset (basic_block);
-static HOST_WIDE_INT prologue_stack_adjust (void);
static bool vt_stack_adjustments (void);
static rtx adjust_stack_reference (rtx, HOST_WIDE_INT);
static hashval_t variable_htab_hash (const void *);
static void attrs_list_union (attrs *, attrs);
static void vars_clear (htab_t);
+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 void var_reg_delete_and_set (dataflow_set *, rtx);
-static void var_reg_delete (dataflow_set *, rtx);
+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,
+ 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_delete_and_set (dataflow_set *, rtx);
-static void var_mem_delete (dataflow_set *, rtx);
+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 void dataflow_set_clear (dataflow_set *);
static int variable_union (void **, void *);
static void dataflow_set_union (dataflow_set *, dataflow_set *);
static bool variable_part_different_p (variable_part *, variable_part *);
-static bool variable_different_p (variable, variable);
+static bool variable_different_p (variable, variable, bool);
static int dataflow_set_different_1 (void **, void *);
static int dataflow_set_different_2 (void **, void *);
static bool dataflow_set_different (dataflow_set *, dataflow_set *);
static bool contains_symbol_ref (rtx);
static bool track_expr_p (tree);
+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_frame_base_location (dataflow_set *, rtx);
-static void set_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);
else
*post -= INTVAL (XEXP (src, 1));
}
- else if (GET_CODE (dest) == MEM)
+ else if (MEM_P (dest))
{
/* (set (mem (pre_dec (reg sp))) (foo)) */
src = XEXP (dest, 0);
{
rtx val = XEXP (XEXP (src, 1), 1);
/* We handle only adjustments by constant amount. */
- if (GET_CODE (XEXP (src, 1)) != PLUS ||
- GET_CODE (val) != CONST_INT)
- abort ();
+ gcc_assert (GET_CODE (XEXP (src, 1)) == PLUS &&
+ GET_CODE (val) == CONST_INT);
+
if (code == PRE_MODIFY)
*pre -= INTVAL (val);
else
}
}
-/* Compute stack adjustnment in basic block BB. */
+/* Compute stack adjustment in basic block BB. */
static void
bb_stack_adjust_offset (basic_block bb)
offset += VTI (bb)->mos[i].u.adjust;
else if (VTI (bb)->mos[i].type != MO_CALL)
{
- if (GET_CODE (VTI (bb)->mos[i].u.loc) == MEM)
+ if (MEM_P (VTI (bb)->mos[i].u.loc))
{
VTI (bb)->mos[i].u.loc
= adjust_stack_reference (VTI (bb)->mos[i].u.loc, -offset);
VTI (bb)->out.stack_adjust = offset;
}
-/* Compute stack adjustment caused by function prolog. */
-
-static HOST_WIDE_INT
-prologue_stack_adjust (void)
-{
- HOST_WIDE_INT offset = 0;
- basic_block bb = ENTRY_BLOCK_PTR->next_bb;
- rtx insn;
- rtx end;
-
- if (!BB_END (bb))
- return 0;
-
- end = NEXT_INSN (BB_END (bb));
- for (insn = BB_HEAD (bb); insn != end; insn = NEXT_INSN (insn))
- {
- if (GET_CODE (insn) == NOTE
- && NOTE_LINE_NUMBER (insn) == NOTE_INSN_PROLOGUE_END)
- break;
-
- if (INSN_P (insn))
- {
- HOST_WIDE_INT tmp;
-
- insn_stack_adjust_offset_pre_post (insn, &tmp, &tmp);
- offset += tmp;
- }
- }
-
- return offset;
-}
-
/* Compute stack adjustments for all blocks by traversing DFS tree.
Return true when the adjustments on all incoming edges are consistent.
- Heavily borrowed from flow_depth_first_order_compute. */
+ Heavily borrowed from pre_and_rev_post_order_compute. */
static bool
vt_stack_adjustments (void)
{
- edge *stack;
+ edge_iterator *stack;
int sp;
- /* Initialize enttry block. */
+ /* Initialize entry block. */
VTI (ENTRY_BLOCK_PTR)->visited = true;
- VTI (ENTRY_BLOCK_PTR)->out.stack_adjust = 0;
+ VTI (ENTRY_BLOCK_PTR)->out.stack_adjust = INCOMING_FRAME_SP_OFFSET;
/* Allocate stack for back-tracking up CFG. */
- stack = xmalloc ((n_basic_blocks + 1) * sizeof (edge));
+ stack = XNEWVEC (edge_iterator, n_basic_blocks + 1);
sp = 0;
/* Push the first edge on to the stack. */
- stack[sp++] = ENTRY_BLOCK_PTR->succ;
+ stack[sp++] = ei_start (ENTRY_BLOCK_PTR->succs);
while (sp)
{
- edge e;
+ edge_iterator ei;
basic_block src;
basic_block dest;
/* Look at the edge on the top of the stack. */
- e = stack[sp - 1];
- src = e->src;
- dest = e->dest;
+ ei = stack[sp - 1];
+ src = ei_edge (ei)->src;
+ dest = ei_edge (ei)->dest;
/* Check if the edge destination has been visited yet. */
if (!VTI (dest)->visited)
VTI (dest)->in.stack_adjust = VTI (src)->out.stack_adjust;
bb_stack_adjust_offset (dest);
- if (dest->succ)
+ if (EDGE_COUNT (dest->succs) > 0)
/* Since the DEST node has been visited for the first
time, check its successors. */
- stack[sp++] = dest->succ;
+ stack[sp++] = ei_start (dest->succs);
}
else
{
return false;
}
- if (e->succ_next)
+ if (! ei_one_before_end_p (ei))
/* Go to the next edge. */
- stack[sp - 1] = e->succ_next;
+ ei_next (&stack[sp - 1]);
else
/* Return to previous level if there are no more edges. */
sp--;
return true;
}
-/* Adjust stack reference MEM by ADJUSTMENT bytes and return the new rtx. */
+/* Adjust stack reference MEM by ADJUSTMENT bytes and make it relative
+ to the argument pointer. Return the new rtx. */
static rtx
adjust_stack_reference (rtx mem, HOST_WIDE_INT adjustment)
{
- rtx adjusted_mem;
- rtx tmp;
+ rtx addr, cfa, tmp;
- adjusted_mem = copy_rtx (mem);
- XEXP (adjusted_mem, 0) = replace_rtx (XEXP (adjusted_mem, 0),
- stack_pointer_rtx,
- gen_rtx_PLUS (Pmode, stack_pointer_rtx,
- GEN_INT (adjustment)));
- tmp = simplify_rtx (XEXP (adjusted_mem, 0));
+#ifdef FRAME_POINTER_CFA_OFFSET
+ adjustment -= FRAME_POINTER_CFA_OFFSET (current_function_decl);
+ cfa = plus_constant (frame_pointer_rtx, adjustment);
+#else
+ adjustment -= ARG_POINTER_CFA_OFFSET (current_function_decl);
+ cfa = plus_constant (arg_pointer_rtx, adjustment);
+#endif
+
+ addr = replace_rtx (copy_rtx (XEXP (mem, 0)), stack_pointer_rtx, cfa);
+ tmp = simplify_rtx (addr);
if (tmp)
- XEXP (adjusted_mem, 0) = tmp;
+ addr = tmp;
- return adjusted_mem;
+ return replace_equiv_address_nv (mem, addr);
}
/* The hash function for variable_htab, computes the hash value
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));
}
variable var = (variable) elem;
location_chain node, next;
+ gcc_assert (var->refcount > 0);
+
+ var->refcount--;
+ if (var->refcount > 0)
+ return;
+
for (i = 0; i < var->n_var_parts; i++)
{
for (node = var->var_part[i].loc_chain; node; node = next)
htab_empty (vars);
}
-/* Copy one variable from *SLOT to hash table DATA. */
+/* Return a copy of a variable VAR and insert it to dataflow set SET. */
-static int
-vars_copy_1 (void **slot, void *data)
+static variable
+unshare_variable (dataflow_set *set, variable var,
+ enum var_init_status initialized)
{
- htab_t dst = (htab_t) data;
- variable src, *dstp, var;
+ void **slot;
+ variable new_var;
int i;
- src = *(variable *) slot;
- dstp = (variable *) htab_find_slot_with_hash (dst, src->decl,
- VARIABLE_HASH_VAL (src->decl),
- INSERT);
- var = pool_alloc (var_pool);
- var->decl = src->decl;
- var->n_var_parts = src->n_var_parts;
- *dstp = (void *) var;
+ new_var = pool_alloc (var_pool);
+ new_var->decl = var->decl;
+ new_var->refcount = 1;
+ var->refcount--;
+ new_var->n_var_parts = var->n_var_parts;
for (i = 0; i < var->n_var_parts; i++)
{
- location_chain last, node;
+ location_chain node;
+ location_chain *nextp;
- var->var_part[i].offset = src->var_part[i].offset;
- last = NULL;
- for (node = src->var_part[i].loc_chain; node; node = node->next)
+ new_var->var_part[i].offset = var->var_part[i].offset;
+ nextp = &new_var->var_part[i].loc_chain;
+ for (node = var->var_part[i].loc_chain; node; node = node->next)
{
location_chain new_lc;
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;
- if (last)
- last->next = new_lc;
- else
- var->var_part[i].loc_chain = new_lc;
- last = new_lc;
+ *nextp = new_lc;
+ nextp = &new_lc->next;
}
/* We are at the basic block boundary when copying variable description
so set the CUR_LOC to be the first element of the chain. */
- if (var->var_part[i].loc_chain)
- var->var_part[i].cur_loc = var->var_part[i].loc_chain->loc;
+ if (new_var->var_part[i].loc_chain)
+ new_var->var_part[i].cur_loc = new_var->var_part[i].loc_chain->loc;
else
- var->var_part[i].cur_loc = NULL;
+ new_var->var_part[i].cur_loc = NULL;
}
+ slot = htab_find_slot_with_hash (set->vars, new_var->decl,
+ VARIABLE_HASH_VAL (new_var->decl),
+ INSERT);
+ *slot = new_var;
+ return new_var;
+}
+
+/* Add a variable from *SLOT to hash table DATA and increase its reference
+ count. */
+
+static int
+vars_copy_1 (void **slot, void *data)
+{
+ htab_t dst = (htab_t) data;
+ variable src, *dstp;
+
+ src = *(variable *) slot;
+ src->refcount++;
+
+ dstp = (variable *) htab_find_slot_with_hash (dst, src->decl,
+ VARIABLE_HASH_VAL (src->decl),
+ INSERT);
+ *dstp = src;
+
/* Continue traversing the hash table. */
return 1;
}
htab_traverse (src, vars_copy_1, dst);
}
-/* Delete current content of register LOC in dataflow set SET
- and set the register to contain REG_EXPR (LOC), REG_OFFSET (LOC). */
+/* Map a decl to its main debug decl. */
+
+static inline tree
+var_debug_decl (tree decl)
+{
+ if (decl && DECL_P (decl)
+ && DECL_DEBUG_EXPR_IS_FROM (decl) && DECL_DEBUG_EXPR (decl)
+ && DECL_P (DECL_DEBUG_EXPR (decl)))
+ decl = DECL_DEBUG_EXPR (decl);
+
+ return decl;
+}
+
+/* Set the register to contain REG_EXPR (LOC), REG_OFFSET (LOC). */
static void
-var_reg_delete_and_set (dataflow_set *set, rtx loc)
+var_reg_set (dataflow_set *set, rtx loc, enum var_init_status initialized,
+ rtx set_src)
{
- attrs *reg = &set->regs[REGNO (loc)];
tree decl = REG_EXPR (loc);
HOST_WIDE_INT offset = REG_OFFSET (loc);
- attrs node, prev, next;
+ attrs node;
- prev = NULL;
- for (node = *reg; node; node = next)
+ decl = var_debug_decl (decl);
+
+ for (node = set->regs[REGNO (loc)]; node; node = node->next)
+ if (node->decl == decl && node->offset == offset)
+ break;
+ if (!node)
+ attrs_list_insert (&set->regs[REGNO (loc)], decl, offset, loc);
+ 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
+ the register to contain REG_EXPR (LOC), REG_OFFSET (LOC). If
+ MODIFY is true, any other live copies of the same variable part are
+ also deleted from the dataflow set, otherwise the variable part is
+ assumed to be copied from another location holding the same
+ part. */
+
+static void
+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);
+ attrs node, next;
+ attrs *nextp;
+
+ 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)
{
next = node->next;
if (node->decl != decl || node->offset != offset)
{
delete_variable_part (set, node->loc, node->decl, node->offset);
-
- if (prev)
- prev->next = next;
- else
- *reg = next;
pool_free (attrs_pool, node);
+ *nextp = next;
}
else
{
node->loc = loc;
- prev = node;
+ nextp = &node->next;
}
}
- if (*reg == NULL)
- attrs_list_insert (reg, decl, offset, loc);
- set_variable_part (set, loc, decl, offset);
+ if (modify)
+ 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. */
+/* Delete current content of register LOC in dataflow set SET. If
+ CLOBBER is true, also delete any other live copies of the same
+ variable part. */
static void
-var_reg_delete (dataflow_set *set, rtx loc)
+var_reg_delete (dataflow_set *set, rtx loc, bool clobber)
{
attrs *reg = &set->regs[REGNO (loc)];
attrs node, next;
+ if (clobber)
+ {
+ tree decl = REG_EXPR (loc);
+ HOST_WIDE_INT offset = REG_OFFSET (loc);
+
+ decl = var_debug_decl (decl);
+
+ clobber_variable_part (set, NULL, decl, offset, NULL);
+ }
+
for (node = *reg; node; node = next)
{
next = node->next;
*reg = NULL;
}
-/* Delete and set the location part of variable MEM_EXPR (LOC)
- in dataflow set SET to LOC.
+/* Set the location part of variable MEM_EXPR (LOC) in dataflow set
+ SET to LOC.
Adjust the address first if it is stack pointer based. */
static void
-var_mem_delete_and_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;
- set_variable_part (set, loc, decl, offset);
+ decl = var_debug_decl (decl);
+
+ set_variable_part (set, loc, decl, offset, initialized, set_src);
}
-/* Delete the location part LOC from dataflow set SET.
+/* Delete and set the location part of variable MEM_EXPR (LOC) in
+ dataflow set SET to LOC. If MODIFY is true, any other live copies
+ of the same variable part are also deleted from the dataflow set,
+ otherwise the variable part is assumed to be copied from another
+ location holding the same part.
Adjust the address first if it is stack pointer based. */
static void
-var_mem_delete (dataflow_set *set, rtx loc)
+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;
+ 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, set_src);
+ var_mem_set (set, loc, initialized, set_src);
+}
+
+/* Delete the location part LOC from dataflow set SET. If CLOBBER is
+ true, also delete any other live copies of the same variable part.
+ Adjust the address first if it is stack pointer based. */
+
+static void
+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;
+
+ decl = var_debug_decl (decl);
+ if (clobber)
+ clobber_variable_part (set, NULL, decl, offset, NULL);
delete_variable_part (set, loc, decl, offset);
}
INSERT);
if (!*dstp)
{
- *dstp = dst = pool_alloc (var_pool);
- dst->decl = src->decl;
- dst->n_var_parts = 0;
+ src->refcount++;
+
+ /* If CUR_LOC of some variable part is not the first element of
+ the location chain we are going to change it so we have to make
+ a copy of the variable. */
+ for (k = 0; k < src->n_var_parts; k++)
+ {
+ gcc_assert (!src->var_part[k].loc_chain
+ == !src->var_part[k].cur_loc);
+ if (src->var_part[k].loc_chain)
+ {
+ gcc_assert (src->var_part[k].cur_loc);
+ if (src->var_part[k].cur_loc != src->var_part[k].loc_chain->loc)
+ break;
+ }
+ }
+ if (k < src->n_var_parts)
+ {
+ 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;
+
+ /* Continue traversing the hash table. */
+ return 1;
}
else
dst = *dstp;
-#ifdef ENABLE_CHECKING
- if (src->n_var_parts == 0)
- abort ();
-#endif
+ gcc_assert (src->n_var_parts);
/* Count the number of location parts, result is K. */
for (i = 0, j = 0, k = 0;
else
j++;
}
- if (i < src->n_var_parts)
- k += src->n_var_parts - i;
- if (j < dst->n_var_parts)
- k += dst->n_var_parts - j;
-#ifdef ENABLE_CHECKING
+ k += src->n_var_parts - i;
+ k += dst->n_var_parts - j;
+
/* We track only variables whose size is <= MAX_VAR_PARTS bytes
thus there are at most MAX_VAR_PARTS different offsets. */
- if (k > MAX_VAR_PARTS)
- abort ();
-#endif
+ gcc_assert (k <= MAX_VAR_PARTS);
+
+ if (dst->refcount > 1 && dst->n_var_parts != k)
+ {
+ 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;
for (k--; k >= 0; k--)
{
- location_chain node;
+ location_chain node, node2;
if (i >= 0 && j >= 0
&& src->var_part[i].offset == dst->var_part[j].offset)
int dst_l, src_l;
int ii, jj, n;
struct variable_union_info *vui;
-
+
+ /* If DST is shared compare the location chains.
+ If they are different we will modify the chain in DST with
+ high probability so make a copy of DST. */
+ if (dst->refcount > 1)
+ {
+ for (node = src->var_part[i].loc_chain,
+ node2 = dst->var_part[j].loc_chain; node && node2;
+ node = node->next, node2 = node2->next)
+ {
+ if (!((REG_P (node2->loc)
+ && REG_P (node->loc)
+ && REGNO (node2->loc) == REGNO (node->loc))
+ || rtx_equal_p (node2->loc, node->loc)))
+ if (node2->init < node->init)
+ node2->init = node->init;
+ break;
+ }
+ if (node || node2)
+ dst = unshare_variable (set, dst, VAR_INIT_STATUS_UNKNOWN);
+ }
+
src_l = 0;
for (node = src->var_part[i].loc_chain; node; node = node->next)
src_l++;
dst_l = 0;
for (node = dst->var_part[j].loc_chain; node; node = node->next)
dst_l++;
- vui = xcalloc (src_l + dst_l, sizeof (struct variable_union_info));
+ vui = XCNEWVEC (struct variable_union_info, src_l + dst_l);
/* Fill in the locations from DST. */
for (node = dst->var_part[j].loc_chain, jj = 0; node;
/* Find location from NODE. */
for (jj = 0; jj < dst_l; jj++)
{
- if ((GET_CODE (vui[jj].lc->loc) == REG
- && GET_CODE (node->loc) == REG
+ if ((REG_P (vui[jj].lc->loc)
+ && REG_P (node->loc)
&& REGNO (vui[jj].lc->loc) == REGNO (node->loc))
|| rtx_equal_p (vui[jj].lc->loc, node->loc))
{
/* 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;
&& src->var_part[i].offset > dst->var_part[j].offset)
|| j < 0)
{
- location_chain last = NULL;
+ 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;
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;
- if (last)
- last->next = new_lc;
- else
- dst->var_part[k].loc_chain = new_lc;
- last = new_lc;
+ *nextp = new_lc;
+ nextp = &new_lc->next;
}
dst->var_part[k].offset = src->var_part[i].offset;
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;
}
{
for (lc2 = vp2->loc_chain; lc2; lc2 = lc2->next)
{
- if (GET_CODE (lc1->loc) == REG && GET_CODE (lc2->loc) == REG)
+ if (REG_P (lc1->loc) && REG_P (lc2->loc))
{
if (REGNO (lc1->loc) == REGNO (lc2->loc))
break;
return false;
}
-/* Return true if variables VAR1 and VAR2 are different (only the first
- location in the list of locations is checked for each offset,
- i.e. when true is returned a note should be emitted). */
+/* Return true if variables VAR1 and VAR2 are different.
+ If COMPARE_CURRENT_LOCATION is true compare also the cur_loc of each
+ variable part. */
static bool
-variable_different_p (variable var1, variable var2)
+variable_different_p (variable var1, variable var2,
+ bool compare_current_location)
{
int i;
+ if (var1 == var2)
+ return false;
+
if (var1->n_var_parts != var2->n_var_parts)
return true;
{
if (var1->var_part[i].offset != var2->var_part[i].offset)
return true;
+ if (compare_current_location)
+ {
+ if (!((REG_P (var1->var_part[i].cur_loc)
+ && REG_P (var2->var_part[i].cur_loc)
+ && (REGNO (var1->var_part[i].cur_loc)
+ == REGNO (var2->var_part[i].cur_loc)))
+ || rtx_equal_p (var1->var_part[i].cur_loc,
+ var2->var_part[i].cur_loc)))
+ return true;
+ }
if (variable_part_different_p (&var1->var_part[i], &var2->var_part[i]))
return true;
if (variable_part_different_p (&var2->var_part[i], &var1->var_part[i]))
variable var1, var2;
var1 = *(variable *) slot;
- var2 = (variable) htab_find_with_hash (htab, var1->decl,
- VARIABLE_HASH_VAL (var1->decl));
+ var2 = htab_find_with_hash (htab, var1->decl,
+ VARIABLE_HASH_VAL (var1->decl));
if (!var2)
{
dataflow_set_different_value = true;
- /* Stop traversing the hash table. */
+ /* Stop traversing the hash table. */
return 0;
}
- if (variable_different_p (var1, var2))
+ if (variable_different_p (var1, var2, false))
{
dataflow_set_different_value = true;
- /* Stop traversing the hash table. */
+ /* Stop traversing the hash table. */
return 0;
}
variable var1, var2;
var1 = *(variable *) slot;
- var2 = (variable) htab_find_with_hash (htab, var1->decl,
- VARIABLE_HASH_VAL (var1->decl));
+ var2 = htab_find_with_hash (htab, var1->decl,
+ VARIABLE_HASH_VAL (var1->decl));
if (!var2)
{
dataflow_set_different_value = true;
- /* Stop traversing the hash table. */
+ /* Stop traversing the hash table. */
return 0;
}
-#ifdef ENABLE_CHECKING
/* If both variables are defined they have been already checked for
equivalence. */
- if (variable_different_p (var1, var2))
- abort ();
-#endif
+ gcc_assert (!variable_different_p (var1, var2, false));
/* Continue traversing the hash table. */
return 1;
track_expr_p (tree expr)
{
rtx decl_rtl;
+ tree realdecl;
/* If EXPR is not a parameter or a variable do not track it. */
if (TREE_CODE (expr) != VAR_DECL && TREE_CODE (expr) != PARM_DECL)
decl_rtl = DECL_RTL_IF_SET (expr);
if (!decl_rtl)
return 0;
+
+ /* If this expression is really a debug alias of some other declaration, we
+ don't need to track this expression if the ultimate declaration is
+ ignored. */
+ realdecl = expr;
+ if (DECL_DEBUG_EXPR_IS_FROM (realdecl) && DECL_DEBUG_EXPR (realdecl))
+ {
+ realdecl = DECL_DEBUG_EXPR (realdecl);
+ /* ??? We don't yet know how to emit DW_OP_piece for variable
+ that has been SRA'ed. */
+ if (!DECL_P (realdecl))
+ return 0;
+ }
+
+ /* Do not track EXPR if REALDECL it should be ignored for debugging
+ purposes. */
+ if (DECL_IGNORED_P (realdecl))
+ return 0;
/* Do not track global variables until we are able to emit correct location
list for them. */
- if (TREE_STATIC (expr))
+ if (TREE_STATIC (realdecl))
return 0;
/* When the EXPR is a DECL for alias of some variable (see example)
extern char **_dl_argv_internal __attribute__ ((alias ("_dl_argv")));
char **_dl_argv;
*/
- if (GET_CODE (decl_rtl) == MEM
+ if (MEM_P (decl_rtl)
&& contains_symbol_ref (XEXP (decl_rtl, 0)))
return 0;
/* If RTX is a memory it should not be very large (because it would be
an array or struct). */
- if (GET_CODE (decl_rtl) == MEM)
+ if (MEM_P (decl_rtl))
{
/* Do not track structures and arrays. */
- if (GET_MODE (decl_rtl) == BLKmode)
+ if (GET_MODE (decl_rtl) == BLKmode
+ || AGGREGATE_TYPE_P (TREE_TYPE (realdecl)))
return 0;
if (MEM_SIZE (decl_rtl)
&& INTVAL (MEM_SIZE (decl_rtl)) > MAX_VAR_PARTS)
return 1;
}
+/* Determine whether a given LOC refers to the same variable part as
+ EXPR+OFFSET. */
+
+static bool
+same_variable_part_p (rtx loc, tree expr, HOST_WIDE_INT offset)
+{
+ tree expr2;
+ HOST_WIDE_INT offset2;
+
+ if (! DECL_P (expr))
+ return false;
+
+ if (REG_P (loc))
+ {
+ expr2 = REG_EXPR (loc);
+ offset2 = REG_OFFSET (loc);
+ }
+ else if (MEM_P (loc))
+ {
+ expr2 = MEM_EXPR (loc);
+ offset2 = MEM_OFFSET (loc) ? INTVAL (MEM_OFFSET (loc)) : 0;
+ }
+ else
+ return false;
+
+ if (! expr2 || ! DECL_P (expr2))
+ return false;
+
+ expr = var_debug_decl (expr);
+ expr2 = var_debug_decl (expr2);
+
+ return (expr == expr2 && offset == offset2);
+}
+
+
/* Count uses (register and memory references) LOC which will be tracked.
INSN is instruction which the LOC is part of. */
{
basic_block bb = BLOCK_FOR_INSN ((rtx) insn);
- if (GET_CODE (*loc) == REG)
+ if (REG_P (*loc))
{
-#ifdef ENABLE_CHECKING
- if (REGNO (*loc) >= FIRST_PSEUDO_REGISTER)
- abort ();
-#endif
- VTI (bb)->n_mos++;
+ gcc_assert (REGNO (*loc) < FIRST_PSEUDO_REGISTER);
+ VTI (bb)->n_mos++;
}
- else if (GET_CODE (*loc) == MEM
+ else if (MEM_P (*loc)
&& MEM_EXPR (*loc)
&& track_expr_p (MEM_EXPR (*loc)))
{
- VTI (bb)->n_mos++;
+ VTI (bb)->n_mos++;
}
return 0;
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);
}
static int
add_uses (rtx *loc, void *insn)
{
- if (GET_CODE (*loc) == REG)
+ if (REG_P (*loc))
{
basic_block bb = BLOCK_FOR_INSN ((rtx) insn);
micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++;
mo->u.loc = *loc;
mo->insn = (rtx) insn;
}
- else if (GET_CODE (*loc) == MEM
+ else if (MEM_P (*loc)
&& MEM_EXPR (*loc)
&& track_expr_p (MEM_EXPR (*loc)))
{
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 (GET_CODE (loc) == REG)
+ if (REG_P (loc))
{
basic_block bb = BLOCK_FOR_INSN ((rtx) insn);
micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++;
- mo->type = ((GET_CODE (expr) != CLOBBER && REG_EXPR (loc)
- && track_expr_p (REG_EXPR (loc)))
- ? MO_SET : MO_CLOBBER);
+ 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;
+ else
+ mo->type = MO_SET;
mo->u.loc = loc;
mo->insn = (rtx) insn;
}
- else if (GET_CODE (loc) == MEM
+ else if (MEM_P (loc)
&& MEM_EXPR (loc)
&& track_expr_p (MEM_EXPR (loc)))
{
basic_block bb = BLOCK_FOR_INSN ((rtx) insn);
micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++;
- mo->type = GET_CODE (expr) == CLOBBER ? MO_CLOBBER : MO_SET;
+ 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;
+ else
+ mo->type = MO_SET;
mo->u.loc = loc;
mo->insn = (rtx) insn;
}
}
+static enum var_init_status
+find_src_status (dataflow_set *in, rtx loc, rtx insn)
+{
+ rtx src = NULL_RTX;
+ rtx pattern;
+ tree decl = NULL_TREE;
+ enum var_init_status status = VAR_INIT_STATUS_UNINITIALIZED;
+
+ if (! flag_var_tracking_uninit)
+ status = VAR_INIT_STATUS_INITIALIZED;
+
+ pattern = PATTERN (insn);
+
+ if (GET_CODE (pattern) == COND_EXEC)
+ pattern = COND_EXEC_CODE (pattern);
+
+ if (GET_CODE (pattern) == SET)
+ src = SET_SRC (pattern);
+ else if (GET_CODE (pattern) == PARALLEL
+ || GET_CODE (pattern) == SEQUENCE)
+ {
+ int i;
+ for (i = XVECLEN (pattern, 0) - 1; i >= 0; i--)
+ if (GET_CODE (XVECEXP (pattern, 0, i)) == SET
+ && SET_DEST (XVECEXP (pattern, 0, i)) == loc)
+ src = SET_SRC (XVECEXP (pattern, 0, i));
+ }
+
+ 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;
+}
+
+/* LOC is the destination the variable is being copied to. INSN
+ contains the copy instruction. SET is the dataflow set containing
+ the variable in LOC. */
+
+static rtx
+find_src_set_src (dataflow_set *set, rtx loc, rtx insn)
+{
+ tree decl = NULL_TREE; /* The variable being copied around. */
+ rtx src = NULL_RTX; /* The location "decl" is being copied from. */
+ rtx set_src = NULL_RTX; /* The value for "decl" stored in "src". */
+ rtx pattern;
+ void **slot;
+ variable var;
+ location_chain nextp;
+ int i;
+ bool found;
+
+
+ pattern = PATTERN (insn);
+ if (GET_CODE (pattern) == COND_EXEC)
+ pattern = COND_EXEC_CODE (pattern);
+
+ if (GET_CODE (pattern) == SET)
+ src = SET_SRC (pattern);
+ else if (GET_CODE (pattern) == PARALLEL
+ || GET_CODE (pattern) == SEQUENCE)
+ {
+ for (i = XVECLEN (pattern, 0) - 1; i >= 0; i--)
+ if (GET_CODE (XVECEXP (pattern, 0, i)) == SET
+ && SET_DEST (XVECEXP (pattern, 0, i)) == loc)
+ src = SET_SRC (XVECEXP (pattern, 0, i));
+ }
+
+ 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. */
static bool
break;
case MO_USE:
- case MO_SET:
{
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_delete_and_set (out, loc);
+ var_reg_set (out, loc, status, NULL);
else if (GET_CODE (loc) == MEM)
- var_mem_delete_and_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;
+ rtx insn = VTI (bb)->mos[i].insn;
+
+ if (GET_CODE (PATTERN (insn)) == SET)
+ set_src = SET_SRC (PATTERN (insn));
+ else if (GET_CODE (PATTERN (insn)) == PARALLEL
+ || GET_CODE (PATTERN (insn)) == SEQUENCE)
+ {
+ int j;
+ for (j = XVECLEN (PATTERN (insn), 0) - 1; j >= 0; j--)
+ if (GET_CODE (XVECEXP (PATTERN (insn), 0, j)) == SET
+ && SET_DEST (XVECEXP (PATTERN (insn), 0, j)) == loc)
+ set_src = SET_SRC (XVECEXP (PATTERN (insn), 0, j));
+ }
+
+ if (REG_P (loc))
+ 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_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;
+
+ if (! flag_var_tracking_uninit)
+ src_status = VAR_INIT_STATUS_INITIALIZED;
+ else
+ src_status = find_src_status (in, loc, VTI (bb)->mos[i].insn);
+
+ if (src_status == VAR_INIT_STATUS_UNKNOWN)
+ src_status = find_src_status (out, loc, VTI (bb)->mos[i].insn);
+
+ set_src = find_src_set_src (in, loc, VTI (bb)->mos[i].insn);
+
+ if (REG_P (loc))
+ 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, src_status, set_src);
}
break;
case MO_USE_NO_VAR:
- case MO_CLOBBER:
{
rtx loc = VTI (bb)->mos[i].u.loc;
- if (GET_CODE (loc) == REG)
- var_reg_delete (out, loc);
- else if (GET_CODE (loc) == MEM)
- var_mem_delete (out, loc);
+ if (REG_P (loc))
+ var_reg_delete (out, loc, false);
+ else if (MEM_P (loc))
+ var_mem_delete (out, loc, false);
}
break;
- case MO_ADJUST:
+ case MO_CLOBBER:
{
- rtx base;
+ rtx loc = VTI (bb)->mos[i].u.loc;
- out->stack_adjust += VTI (bb)->mos[i].u.adjust;
- base = gen_rtx_MEM (Pmode,
- gen_rtx_PLUS (Pmode, stack_pointer_rtx,
- GEN_INT (out->stack_adjust)));
- set_frame_base_location (out, base);
+ if (REG_P (loc))
+ var_reg_delete (out, loc, true);
+ else if (MEM_P (loc))
+ var_mem_delete (out, loc, true);
}
break;
+
+ case MO_ADJUST:
+ out->stack_adjust += VTI (bb)->mos[i].u.adjust;
+ break;
}
}
/* Compute reverse completion order of depth first search of the CFG
so that the data-flow runs faster. */
- rc_order = (int *) xmalloc (n_basic_blocks * sizeof (int));
- bb_order = (int *) xmalloc (last_basic_block * sizeof (int));
- flow_depth_first_order_compute (NULL, rc_order);
- for (i = 0; i < n_basic_blocks; i++)
+ rc_order = XNEWVEC (int, n_basic_blocks - NUM_FIXED_BLOCKS);
+ bb_order = XNEWVEC (int, last_basic_block);
+ pre_and_rev_post_order_compute (NULL, rc_order, false);
+ for (i = 0; i < n_basic_blocks - NUM_FIXED_BLOCKS; i++)
bb_order[rc_order[i]] = i;
free (rc_order);
in_worklist = sbitmap_alloc (last_basic_block);
in_pending = sbitmap_alloc (last_basic_block);
sbitmap_zero (in_worklist);
- sbitmap_zero (in_pending);
FOR_EACH_BB (bb)
- {
- fibheap_insert (pending, bb_order[bb->index], bb);
- SET_BIT (in_pending, bb->index);
- }
+ fibheap_insert (pending, bb_order[bb->index], bb);
+ sbitmap_ones (in_pending);
while (!fibheap_empty (pending))
{
if (!TEST_BIT (visited, bb->index))
{
bool changed;
+ edge_iterator ei;
SET_BIT (visited, bb->index);
/* Calculate the IN set as union of predecessor OUT sets. */
dataflow_set_clear (&VTI (bb)->in);
- for (e = bb->pred; e; e = e->pred_next)
+ FOR_EACH_EDGE (e, ei, bb->preds)
{
dataflow_set_union (&VTI (bb)->in, &VTI (e->src)->out);
}
changed = compute_bb_dataflow (bb);
if (changed)
{
- for (e = bb->succ; e; e = e->succ_next)
+ FOR_EACH_EDGE (e, ei, bb->succs)
{
if (e->dest == EXIT_BLOCK_PTR)
continue;
{
for (; list; list = list->next)
{
- print_mem_expr (rtl_dump_file, list->decl);
- fprintf (rtl_dump_file, "+");
- fprintf (rtl_dump_file, HOST_WIDE_INT_PRINT_DEC, list->offset);
+ print_mem_expr (dump_file, list->decl);
+ fprintf (dump_file, "+" HOST_WIDE_INT_PRINT_DEC, list->offset);
}
- fprintf (rtl_dump_file, "\n");
+ fprintf (dump_file, "\n");
}
/* Print the information about variable *SLOT to dump file. */
int i;
location_chain node;
- fprintf (rtl_dump_file, " name: %s\n",
+ fprintf (dump_file, " name: %s\n",
IDENTIFIER_POINTER (DECL_NAME (var->decl)));
for (i = 0; i < var->n_var_parts; i++)
{
- fprintf (rtl_dump_file, " offset %ld\n",
+ fprintf (dump_file, " offset %ld\n",
(long) var->var_part[i].offset);
for (node = var->var_part[i].loc_chain; node; node = node->next)
{
- fprintf (rtl_dump_file, " ");
- print_rtl_single (rtl_dump_file, node->loc);
+ fprintf (dump_file, " ");
+ if (node->init == VAR_INIT_STATUS_UNINITIALIZED)
+ fprintf (dump_file, "[uninit]");
+ print_rtl_single (dump_file, node->loc);
}
}
{
if (htab_elements (vars) > 0)
{
- fprintf (rtl_dump_file, "Variables:\n");
+ fprintf (dump_file, "Variables:\n");
htab_traverse (vars, dump_variable, NULL);
}
}
{
int i;
- fprintf (rtl_dump_file, "Stack adjustment: ");
- fprintf (rtl_dump_file, HOST_WIDE_INT_PRINT_DEC, set->stack_adjust);
- fprintf (rtl_dump_file, "\n");
- for (i = 1; i < FIRST_PSEUDO_REGISTER; i++)
+ fprintf (dump_file, "Stack adjustment: " HOST_WIDE_INT_PRINT_DEC "\n",
+ set->stack_adjust);
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
{
if (set->regs[i])
{
- fprintf (rtl_dump_file, "Reg %d:", i);
+ fprintf (dump_file, "Reg %d:", i);
dump_attrs_list (set->regs[i]);
}
}
dump_vars (set->vars);
- fprintf (rtl_dump_file, "\n");
+ fprintf (dump_file, "\n");
}
/* Print the IN and OUT sets for each basic block to dump file. */
FOR_EACH_BB (bb)
{
- fprintf (rtl_dump_file, "\nBasic block %d:\n", bb->index);
- fprintf (rtl_dump_file, "IN:\n");
+ fprintf (dump_file, "\nBasic block %d:\n", bb->index);
+ fprintf (dump_file, "IN:\n");
dump_dataflow_set (&VTI (bb)->in);
- fprintf (rtl_dump_file, "OUT:\n");
+ fprintf (dump_file, "OUT:\n");
dump_dataflow_set (&VTI (bb)->out);
}
}
empty_var = pool_alloc (var_pool);
empty_var->decl = var->decl;
+ empty_var->refcount = 1;
empty_var->n_var_parts = 0;
*slot = empty_var;
}
else
{
-#ifdef ENABLE_CHECKING
- if (!htab)
- abort ();
-#endif
+ gcc_assert (htab);
if (var->n_var_parts == 0)
{
void **slot = htab_find_slot_with_hash (htab, var->decl, hash,
}
}
-/* Set the location of frame_base_decl to LOC in dataflow set SET. This
- function expects that
- frame_base_decl has already one location for offset 0 in the variable table.
- */
+/* Look for the index in VAR->var_part corresponding to OFFSET.
+ Return -1 if not found. If INSERTION_POINT is non-NULL, the
+ referenced int will be set to the index that the part has or should
+ have, if it should be inserted. */
-static void
-set_frame_base_location (dataflow_set *set, rtx loc)
+static inline int
+find_variable_location_part (variable var, HOST_WIDE_INT offset,
+ int *insertion_point)
{
- variable var;
-
- var = htab_find_with_hash (set->vars, frame_base_decl,
- VARIABLE_HASH_VAL (frame_base_decl));
-#ifdef ENABLE_CHECKING
- if (!var)
- abort ();
- if (var->n_var_parts != 1)
- abort ();
- if (var->var_part[0].offset != 0)
- abort ();
- if (!var->var_part[0].loc_chain)
- abort ();
-#endif
+ int pos, low, high;
+
+ /* Find the location part. */
+ low = 0;
+ high = var->n_var_parts;
+ while (low != high)
+ {
+ pos = (low + high) / 2;
+ if (var->var_part[pos].offset < offset)
+ low = pos + 1;
+ else
+ high = pos;
+ }
+ pos = low;
+
+ if (insertion_point)
+ *insertion_point = pos;
+
+ if (pos < var->n_var_parts && var->var_part[pos].offset == offset)
+ return pos;
- var->var_part[0].loc_chain->loc = loc;
- variable_was_changed (var, set->vars);
+ return -1;
}
/* Set the part of variable's location in the dataflow set SET. The variable
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, low, high;
- location_chain node, prev, next;
+ int pos;
+ location_chain node, next;
+ location_chain *nextp;
variable var;
void **slot;
/* Create new variable information. */
var = pool_alloc (var_pool);
var->decl = decl;
+ var->refcount = 1;
var->n_var_parts = 1;
var->var_part[0].offset = offset;
var->var_part[0].loc_chain = NULL;
}
else
{
+ int inspos = 0;
+
var = (variable) *slot;
- /* Find the location part. */
- low = 0;
- high = var->n_var_parts;
- while (low != high)
+ pos = find_variable_location_part (var, offset, &inspos);
+
+ if (pos >= 0)
{
- pos = (low + high) / 2;
- if (var->var_part[pos].offset < offset)
- low = pos + 1;
+ node = var->var_part[pos].loc_chain;
+
+ if (node
+ && ((REG_P (node->loc) && REG_P (loc)
+ && REGNO (node->loc) == REGNO (loc))
+ || rtx_equal_p (node->loc, loc)))
+ {
+ /* 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
- high = pos;
+ {
+ /* We have to make a copy of a shared variable. */
+ if (var->refcount > 1)
+ var = unshare_variable (set, var, initialized);
+ }
}
- pos = low;
-
- if (pos == var->n_var_parts || var->var_part[pos].offset != offset)
+ else
{
- /* We have not find the location part, new one will be created. */
+ /* We have not found the location part, new one will be created. */
+
+ /* We have to make a copy of the shared variable. */
+ if (var->refcount > 1)
+ var = unshare_variable (set, var, initialized);
-#ifdef ENABLE_CHECKING
/* We track only variables whose size is <= MAX_VAR_PARTS bytes
thus there are at most MAX_VAR_PARTS different offsets. */
- if (var->n_var_parts >= MAX_VAR_PARTS)
- abort ();
-#endif
+ gcc_assert (var->n_var_parts < MAX_VAR_PARTS);
- /* We have to move the elements of array starting at index low to the
- next position. */
- for (high = var->n_var_parts; high > low; high--)
- var->var_part[high] = var->var_part[high - 1];
+ /* We have to move the elements of array starting at index
+ inspos to the next position. */
+ for (pos = var->n_var_parts; pos > inspos; pos--)
+ var->var_part[pos] = var->var_part[pos - 1];
var->n_var_parts++;
var->var_part[pos].offset = offset;
}
}
- /* Delete the location from list. */
- prev = NULL;
+ /* Delete the location from the list. */
+ nextp = &var->var_part[pos].loc_chain;
for (node = var->var_part[pos].loc_chain; node; node = next)
{
next = node->next;
- if ((GET_CODE (node->loc) == REG && GET_CODE (loc) == REG
+ if ((REG_P (node->loc) && REG_P (loc)
&& REGNO (node->loc) == REGNO (loc))
|| rtx_equal_p (node->loc, loc))
{
- if (prev)
- prev->next = next;
- else
- var->var_part[pos].loc_chain = next;
+ /* 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;
}
else
- prev = node;
+ nextp = &node->next;
}
/* 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;
}
}
+/* Remove all recorded register locations for the given variable part
+ from dataflow set SET, except for those that are identical to loc.
+ The variable part is specified by variable's declaration DECL and
+ offset OFFSET. */
+
+static void
+clobber_variable_part (dataflow_set *set, rtx loc, tree decl,
+ HOST_WIDE_INT offset, rtx set_src)
+{
+ void **slot;
+
+ if (! decl || ! DECL_P (decl))
+ return;
+
+ slot = htab_find_slot_with_hash (set->vars, decl, VARIABLE_HASH_VAL (decl),
+ NO_INSERT);
+ if (slot)
+ {
+ variable var = (variable) *slot;
+ int pos = find_variable_location_part (var, offset, NULL);
+
+ if (pos >= 0)
+ {
+ location_chain node, next;
+
+ /* Remove the register locations from the dataflow set. */
+ next = var->var_part[pos].loc_chain;
+ for (node = next; node; node = next)
+ {
+ next = node->next;
+ 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))
+ {
+ attrs anode, anext;
+ attrs *anextp;
+
+ /* Remove the variable part from the register's
+ list, but preserve any other variable parts
+ that might be regarded as live in that same
+ register. */
+ anextp = &set->regs[REGNO (node->loc)];
+ for (anode = *anextp; anode; anode = anext)
+ {
+ anext = anode->next;
+ if (anode->decl == decl
+ && anode->offset == offset)
+ {
+ pool_free (attrs_pool, anode);
+ *anextp = anext;
+ }
+ }
+ }
+
+ delete_variable_part (set, node->loc, decl, offset);
+ }
+ }
+ }
+ }
+}
+
/* Delete the part of variable's location from dataflow set SET. The variable
part is specified by variable's declaration DECL and offset OFFSET and the
part's location by LOC. */
delete_variable_part (dataflow_set *set, rtx loc, tree decl,
HOST_WIDE_INT offset)
{
- int pos, low, high;
void **slot;
slot = htab_find_slot_with_hash (set->vars, decl, VARIABLE_HASH_VAL (decl),
if (slot)
{
variable var = (variable) *slot;
+ int pos = find_variable_location_part (var, offset, NULL);
- /* Find the location part. */
- low = 0;
- high = var->n_var_parts;
- while (low != high)
+ if (pos >= 0)
{
- pos = (low + high) / 2;
- if (var->var_part[pos].offset < offset)
- low = pos + 1;
- else
- high = pos;
- }
- pos = low;
-
- if (pos < var->n_var_parts && var->var_part[pos].offset == offset)
- {
- location_chain node, prev, next;
+ location_chain node, next;
+ location_chain *nextp;
bool changed;
+ if (var->refcount > 1)
+ {
+ /* If the variable contains the location part we have to
+ make a copy of the variable. */
+ for (node = var->var_part[pos].loc_chain; node;
+ node = node->next)
+ {
+ if ((REG_P (node->loc) && REG_P (loc)
+ && REGNO (node->loc) == REGNO (loc))
+ || rtx_equal_p (node->loc, loc))
+ {
+ 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;
+ }
+ }
+ }
+
/* Delete the location part. */
- prev = NULL;
- for (node = var->var_part[pos].loc_chain; node; node = next)
+ nextp = &var->var_part[pos].loc_chain;
+ for (node = *nextp; node; node = next)
{
next = node->next;
- if ((GET_CODE (node->loc) == REG && GET_CODE (loc) == REG
+ if ((REG_P (node->loc) && REG_P (loc)
&& REGNO (node->loc) == REGNO (loc))
|| rtx_equal_p (node->loc, loc))
{
- if (prev)
- prev->next = next;
- else
- var->var_part[pos].loc_chain = next;
pool_free (loc_chain_pool, node);
+ *nextp = next;
break;
}
else
- prev = node;
+ nextp = &node->next;
}
/* If we have deleted the location which was last emitted
we have to emit new location so add the variable to set
of changed variables. */
if (var->var_part[pos].cur_loc
- && ((GET_CODE (loc) == REG
- && GET_CODE (var->var_part[pos].cur_loc) == REG
+ && ((REG_P (loc)
+ && REG_P (var->var_part[pos].cur_loc)
&& REGNO (loc) == REGNO (var->var_part[pos].cur_loc))
|| rtx_equal_p (loc, var->var_part[pos].cur_loc)))
{
}
}
if (changed)
- variable_was_changed (var, set->vars);
+ variable_was_changed (var, set->vars);
}
}
}
rtx insn = ((emit_note_data *)data)->insn;
enum emit_note_where where = ((emit_note_data *)data)->where;
rtx note;
- int i;
+ 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];
+ rtx loc[MAX_VAR_PARTS];
-#ifdef ENABLE_CHECKING
- if (!var->decl)
- abort ();
-#endif
+ gcc_assert (var->decl);
+
+ if (! flag_var_tracking_uninit)
+ initialized = VAR_INIT_STATUS_INITIALIZED;
complete = true;
last_limit = 0;
+ n_var_parts = 0;
for (i = 0; i < var->n_var_parts; i++)
{
+ enum machine_mode mode, wider_mode;
+
if (last_limit < var->var_part[i].offset)
{
complete = false;
break;
}
- last_limit
- = (var->var_part[i].offset
- + GET_MODE_SIZE (GET_MODE (var->var_part[i].loc_chain->loc)));
+ else if (last_limit > var->var_part[i].offset)
+ continue;
+ 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. */
+ wider_mode = GET_MODE_WIDER_MODE (mode);
+ for (j = i + 1; j < var->n_var_parts; j++)
+ if (last_limit <= var->var_part[j].offset)
+ break;
+ if (j < var->n_var_parts
+ && wider_mode != VOIDmode
+ && GET_CODE (loc[n_var_parts])
+ == GET_CODE (var->var_part[j].loc_chain->loc)
+ && mode == GET_MODE (var->var_part[j].loc_chain->loc)
+ && last_limit == var->var_part[j].offset)
+ {
+ rtx new_loc = NULL;
+ rtx loc2 = var->var_part[j].loc_chain->loc;
+
+ if (REG_P (loc[n_var_parts])
+ && hard_regno_nregs[REGNO (loc[n_var_parts])][mode] * 2
+ == hard_regno_nregs[REGNO (loc[n_var_parts])][wider_mode]
+ && end_hard_regno (mode, REGNO (loc[n_var_parts]))
+ == REGNO (loc2))
+ {
+ if (! WORDS_BIG_ENDIAN && ! BYTES_BIG_ENDIAN)
+ new_loc = simplify_subreg (wider_mode, loc[n_var_parts],
+ mode, 0);
+ else if (WORDS_BIG_ENDIAN && BYTES_BIG_ENDIAN)
+ new_loc = simplify_subreg (wider_mode, loc2, mode, 0);
+ if (new_loc)
+ {
+ if (!REG_P (new_loc)
+ || REGNO (new_loc) != REGNO (loc[n_var_parts]))
+ new_loc = NULL;
+ else
+ REG_ATTRS (new_loc) = REG_ATTRS (loc[n_var_parts]);
+ }
+ }
+ else if (MEM_P (loc[n_var_parts])
+ && GET_CODE (XEXP (loc2, 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (loc2, 0), 0)) == REG
+ && GET_CODE (XEXP (XEXP (loc2, 0), 1)) == CONST_INT)
+ {
+ if ((GET_CODE (XEXP (loc[n_var_parts], 0)) == REG
+ && rtx_equal_p (XEXP (loc[n_var_parts], 0),
+ XEXP (XEXP (loc2, 0), 0))
+ && INTVAL (XEXP (XEXP (loc2, 0), 1))
+ == GET_MODE_SIZE (mode))
+ || (GET_CODE (XEXP (loc[n_var_parts], 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (loc[n_var_parts], 0), 1))
+ == CONST_INT
+ && rtx_equal_p (XEXP (XEXP (loc[n_var_parts], 0), 0),
+ XEXP (XEXP (loc2, 0), 0))
+ && INTVAL (XEXP (XEXP (loc[n_var_parts], 0), 1))
+ + GET_MODE_SIZE (mode)
+ == INTVAL (XEXP (XEXP (loc2, 0), 1))))
+ new_loc = adjust_address_nv (loc[n_var_parts],
+ wider_mode, 0);
+ }
+
+ if (new_loc)
+ {
+ loc[n_var_parts] = new_loc;
+ mode = wider_mode;
+ last_limit = offsets[n_var_parts] + GET_MODE_SIZE (mode);
+ i = j;
+ }
+ }
+ ++n_var_parts;
}
type_size_unit = TYPE_SIZE_UNIT (TREE_TYPE (var->decl));
if ((unsigned HOST_WIDE_INT) last_limit < TREE_INT_CST_LOW (type_size_unit))
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 (var->n_var_parts == 1)
+ else if (n_var_parts == 1)
{
rtx expr_list
- = gen_rtx_EXPR_LIST (VOIDmode,
- var->var_part[0].loc_chain->loc,
- GEN_INT (var->var_part[0].offset));
+ = 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 (var->n_var_parts)
+ else if (n_var_parts)
{
- rtx argp[MAX_VAR_PARTS];
rtx parallel;
- for (i = 0; i < var->n_var_parts; i++)
- argp[i] = gen_rtx_EXPR_LIST (VOIDmode, var->var_part[i].loc_chain->loc,
- GEN_INT (var->var_part[i].offset));
+ for (i = 0; i < n_var_parts; i++)
+ loc[i]
+ = gen_rtx_EXPR_LIST (VOIDmode, loc[i], GEN_INT (offsets[i]));
+
parallel = gen_rtx_PARALLEL (VOIDmode,
- gen_rtvec_v (var->n_var_parts, argp));
+ 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);
variable old_var, new_var;
old_var = *(variable *) slot;
- new_var = (variable) htab_find_with_hash (new_vars, old_var->decl,
- VARIABLE_HASH_VAL (old_var->decl));
+ new_var = htab_find_with_hash (new_vars, old_var->decl,
+ VARIABLE_HASH_VAL (old_var->decl));
if (!new_var)
{
empty_var = pool_alloc (var_pool);
empty_var->decl = old_var->decl;
+ empty_var->refcount = 1;
empty_var->n_var_parts = 0;
variable_was_changed (empty_var, NULL);
}
- else if (variable_different_p (old_var, new_var))
+ else if (variable_different_p (old_var, new_var, true))
{
variable_was_changed (new_var, NULL);
}
variable old_var, new_var;
new_var = *(variable *) slot;
- old_var = (variable) htab_find_with_hash (old_vars, new_var->decl,
- VARIABLE_HASH_VAL (new_var->decl));
+ old_var = htab_find_with_hash (old_vars, new_var->decl,
+ VARIABLE_HASH_VAL (new_var->decl));
if (!old_var)
{
/* Variable has appeared. */
break;
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, status, NULL);
+ else
+ var_mem_set (&set, loc, status, NULL);
+
+ emit_notes_for_changes (insn, EMIT_NOTE_AFTER_INSN);
+ }
+ break;
+
case MO_SET:
{
rtx loc = VTI (bb)->mos[i].u.loc;
+ rtx set_src = NULL;
- if (GET_CODE (loc) == REG)
- var_reg_delete_and_set (&set, loc);
+ if (GET_CODE (PATTERN (insn)) == SET)
+ set_src = SET_SRC (PATTERN (insn));
+ else if (GET_CODE (PATTERN (insn)) == PARALLEL
+ || GET_CODE (PATTERN (insn)) == SEQUENCE)
+ {
+ int j;
+ for (j = XVECLEN (PATTERN (insn), 0) - 1; j >= 0; j--)
+ if (GET_CODE (XVECEXP (PATTERN (insn), 0, j)) == SET
+ && SET_DEST (XVECEXP (PATTERN (insn), 0, j)) == loc)
+ set_src = SET_SRC (XVECEXP (PATTERN (insn), 0, j));
+ }
+
+ if (REG_P (loc))
+ var_reg_delete_and_set (&set, loc, true, VAR_INIT_STATUS_INITIALIZED,
+ set_src);
else
- var_mem_delete_and_set (&set, loc);
+ var_mem_delete_and_set (&set, loc, true, VAR_INIT_STATUS_INITIALIZED,
+ set_src);
+
+ 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;
- if (VTI (bb)->mos[i].type == MO_USE)
- emit_notes_for_changes (insn, EMIT_NOTE_BEFORE_INSN);
+ src_status = find_src_status (&set, loc, VTI (bb)->mos[i].insn);
+ set_src = find_src_set_src (&set, loc, VTI (bb)->mos[i].insn);
+
+ if (REG_P (loc))
+ var_reg_delete_and_set (&set, loc, false, src_status, set_src);
else
- emit_notes_for_changes (insn, EMIT_NOTE_AFTER_INSN);
+ var_mem_delete_and_set (&set, loc, false, src_status, set_src);
+
+ emit_notes_for_changes (NEXT_INSN (insn), EMIT_NOTE_BEFORE_INSN);
}
break;
case MO_USE_NO_VAR:
- case MO_CLOBBER:
{
rtx loc = VTI (bb)->mos[i].u.loc;
- if (GET_CODE (loc) == REG)
- var_reg_delete (&set, loc);
+ if (REG_P (loc))
+ var_reg_delete (&set, loc, false);
else
- var_mem_delete (&set, loc);
+ var_mem_delete (&set, loc, false);
- if (VTI (bb)->mos[i].type == MO_USE_NO_VAR)
- emit_notes_for_changes (insn, EMIT_NOTE_BEFORE_INSN);
- else
- emit_notes_for_changes (insn, EMIT_NOTE_AFTER_INSN);
+ emit_notes_for_changes (insn, EMIT_NOTE_AFTER_INSN);
}
break;
- case MO_ADJUST:
+ case MO_CLOBBER:
{
- rtx base;
+ rtx loc = VTI (bb)->mos[i].u.loc;
- set.stack_adjust += VTI (bb)->mos[i].u.adjust;
- base = gen_rtx_MEM (Pmode,
- gen_rtx_PLUS (Pmode, stack_pointer_rtx,
- GEN_INT (set.stack_adjust)));
- set_frame_base_location (&set, base);
- emit_notes_for_changes (insn, EMIT_NOTE_AFTER_INSN);
+ if (REG_P (loc))
+ var_reg_delete (&set, loc, true);
+ else
+ var_mem_delete (&set, loc, true);
+
+ emit_notes_for_changes (NEXT_INSN (insn), EMIT_NOTE_BEFORE_INSN);
}
break;
+
+ case MO_ADJUST:
+ set.stack_adjust += VTI (bb)->mos[i].u.adjust;
+ break;
}
}
dataflow_set_destroy (&set);
dataflow_set *last_out;
dataflow_set empty;
-#ifdef ENABLE_CHECKING
- if (htab_elements (changed_variables))
- abort ();
-#endif
+ gcc_assert (!htab_elements (changed_variables));
/* Enable emitting notes by functions (mainly by set_variable_part and
delete_variable_part). */
static bool
vt_get_decl_and_offset (rtx rtl, tree *declp, HOST_WIDE_INT *offsetp)
{
- if (GET_CODE (rtl) == REG)
+ if (REG_P (rtl))
{
if (REG_ATTRS (rtl))
{
return true;
}
}
- else if (GET_CODE (rtl) == MEM)
+ else if (MEM_P (rtl))
{
if (MEM_ATTRS (rtl))
{
vt_add_function_parameters (void)
{
tree parm;
- HOST_WIDE_INT stack_adjust = 0;
- if (!frame_pointer_needed)
- stack_adjust = prologue_stack_adjust ();
-
for (parm = DECL_ARGUMENTS (current_function_decl);
parm; parm = TREE_CHAIN (parm))
{
rtx incoming = DECL_INCOMING_RTL (parm);
tree decl;
HOST_WIDE_INT offset;
- dataflow_set *in, *out;
+ dataflow_set *out;
if (TREE_CODE (parm) != PARM_DECL)
continue;
if (!decl)
continue;
- if (parm != decl)
- abort ();
+ gcc_assert (parm == decl);
- incoming = eliminate_regs (incoming, 0, NULL_RTX);
- if (!frame_pointer_needed && GET_CODE (incoming) == MEM)
- incoming = adjust_stack_reference (incoming, -stack_adjust);
- in = &VTI (ENTRY_BLOCK_PTR)->in;
out = &VTI (ENTRY_BLOCK_PTR)->out;
- if (GET_CODE (incoming) == REG)
+ if (REG_P (incoming))
{
- if (REGNO (incoming) >= FIRST_PSEUDO_REGISTER)
- abort ();
- attrs_list_insert (&in->regs[REGNO (incoming)],
- parm, offset, incoming);
+ gcc_assert (REGNO (incoming) < FIRST_PSEUDO_REGISTER);
attrs_list_insert (&out->regs[REGNO (incoming)],
parm, offset, incoming);
- set_variable_part (in, incoming, parm, offset);
- set_variable_part (out, incoming, parm, offset);
- }
- else if (GET_CODE (incoming) == MEM)
- {
- set_variable_part (in, incoming, parm, offset);
- 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, VAR_INIT_STATUS_INITIALIZED,
+ NULL);
}
}
FOR_EACH_BB (bb)
{
rtx insn;
- HOST_WIDE_INT pre, post;
+ HOST_WIDE_INT pre, post = 0;
/* Count the number of micro operations. */
VTI (bb)->n_mos = 0;
}
note_uses (&PATTERN (insn), count_uses_1, insn);
note_stores (PATTERN (insn), count_stores, insn);
- if (GET_CODE (insn) == CALL_INSN)
+ if (CALL_P (insn))
VTI (bb)->n_mos++;
}
}
- /* Add the nicro-operations to the array. */
- VTI (bb)->mos = xmalloc (VTI (bb)->n_mos
- * sizeof (struct micro_operation_def));
+ /* Add the micro-operations to the array. */
+ VTI (bb)->mos = XNEWVEC (micro_operation, VTI (bb)->n_mos);
VTI (bb)->n_mos = 0;
for (insn = BB_HEAD (bb); insn != NEXT_INSN (BB_END (bb));
insn = NEXT_INSN (insn))
}
}
- if (GET_CODE (insn) == CALL_INSN)
+ if (CALL_P (insn))
{
micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++;
}
n1 = VTI (bb)->n_mos;
+ /* This will record NEXT_INSN (insn), such that we can
+ insert notes before it without worrying about any
+ notes that MO_USEs might emit after the insn. */
note_stores (PATTERN (insn), add_stores, insn);
n2 = VTI (bb)->n_mos - 1;
- /* Order the MO_SETs to be before MO_CLOBBERs. */
+ /* Order the MO_CLOBBERs to be before MO_SETs. */
while (n1 < n2)
{
- while (n1 < n2 && VTI (bb)->mos[n1].type == MO_SET)
+ while (n1 < n2 && VTI (bb)->mos[n1].type == MO_CLOBBER)
n1++;
- while (n1 < n2 && VTI (bb)->mos[n2].type == MO_CLOBBER)
+ while (n1 < n2 && (VTI (bb)->mos[n2].type == MO_SET
+ || VTI (bb)->mos[n2].type == MO_COPY))
n2--;
if (n1 < n2)
{
changed_variables = htab_create (10, variable_htab_hash, variable_htab_eq,
NULL);
vt_add_function_parameters ();
-
- if (!frame_pointer_needed)
- {
- rtx base;
-
- /* Create fake variable for tracking stack pointer changes. */
- frame_base_decl = make_node (VAR_DECL);
- DECL_NAME (frame_base_decl) = get_identifier ("___frame_base_decl");
- TREE_TYPE (frame_base_decl) = char_type_node;
- DECL_ARTIFICIAL (frame_base_decl) = 1;
-
- /* Set its initial "location". */
- base = gen_rtx_MEM (Pmode, stack_pointer_rtx);
- set_variable_part (&VTI (ENTRY_BLOCK_PTR)->in, base, frame_base_decl, 0);
- set_variable_part (&VTI (ENTRY_BLOCK_PTR)->out, base, frame_base_decl, 0);
- }
- else
- {
- frame_base_decl = NULL;
- }
}
/* Free the data structures needed for variable tracking. */
/* The entry point to variable tracking pass. */
-void
+unsigned int
variable_tracking_main (void)
{
if (n_basic_blocks > 500 && n_edges / n_basic_blocks >= 20)
- return;
+ return 0;
mark_dfs_back_edges ();
vt_initialize ();
if (!vt_stack_adjustments ())
{
vt_finalize ();
- return;
+ return 0;
}
}
vt_find_locations ();
vt_emit_notes ();
- if (rtl_dump_file)
+ if (dump_file && (dump_flags & TDF_DETAILS))
{
dump_dataflow_sets ();
- dump_flow_info (rtl_dump_file);
+ dump_flow_info (dump_file, dump_flags);
}
vt_finalize ();
+ return 0;
+}
+\f
+static bool
+gate_handle_var_tracking (void)
+{
+ return (flag_var_tracking);
}
+
+
+
+struct tree_opt_pass pass_variable_tracking =
+{
+ "vartrack", /* name */
+ gate_handle_var_tracking, /* gate */
+ variable_tracking_main, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ TV_VAR_TRACKING, /* tv_id */
+ 0, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ TODO_dump_func | TODO_verify_rtl_sharing,/* todo_flags_finish */
+ 'V' /* letter */
+};
+