/* Variable tracking routines for the GNU compiler.
- Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
This file is part of GCC.
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. */
+ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
/* 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
/* The declaration of the variable. */
tree decl;
+ /* Reference count. */
+ int refcount;
+
/* Number of variable parts. */
int n_var_parts;
} *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. */
-GTY(()) 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);
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 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 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 delete_variable_part (dataflow_set *, rtx, tree, HOST_WIDE_INT);
static int emit_note_insn_var_location (void **, void *);
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
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 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
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)
{
- 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->next = 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;
}
static void
var_reg_delete_and_set (dataflow_set *set, rtx loc)
{
- attrs *reg = &set->regs[REGNO (loc)];
tree decl = REG_EXPR (loc);
HOST_WIDE_INT offset = REG_OFFSET (loc);
- attrs node, prev, next;
+ attrs node, next;
+ attrs *nextp;
- prev = NULL;
- for (node = *reg; node; node = next)
+ 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);
+ if (set->regs[REGNO (loc)] == NULL)
+ attrs_list_insert (&set->regs[REGNO (loc)], decl, offset, loc);
set_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)
+ unshare_variable (set, src);
+ 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)
+ dst = unshare_variable (set, dst);
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)))
+ break;
+ }
+ if (node || node2)
+ dst = unshare_variable (set, dst);
+ }
+
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))
{
&& 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->next = NULL;
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;
{
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;
return 0;
}
- if (variable_different_p (var1, var2))
+ if (variable_different_p (var1, var2, false))
{
dataflow_set_different_value = true;
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;
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 it should be ignored for debugging purposes. */
- if (DECL_IGNORED_P (expr))
+ /* 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)
{
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;
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)))
{
static void
add_stores (rtx loc, 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->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)))
{
{
rtx loc = VTI (bb)->mos[i].u.loc;
- if (GET_CODE (loc) == REG)
+ if (REG_P (loc))
var_reg_delete_and_set (out, loc);
- else if (GET_CODE (loc) == MEM)
+ else if (MEM_P (loc))
var_mem_delete_and_set (out, loc);
}
break;
{
rtx loc = VTI (bb)->mos[i].u.loc;
- if (GET_CODE (loc) == REG)
+ if (REG_P (loc))
var_reg_delete (out, loc);
- else if (GET_CODE (loc) == MEM)
+ else if (MEM_P (loc))
var_mem_delete (out, loc);
}
break;
case MO_ADJUST:
- {
- rtx base;
-
- 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);
- }
+ 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 (dump_file, list->decl);
- fprintf (dump_file, "+");
- fprintf (dump_file, HOST_WIDE_INT_PRINT_DEC, list->offset);
+ fprintf (dump_file, "+" HOST_WIDE_INT_PRINT_DEC, list->offset);
}
fprintf (dump_file, "\n");
}
{
int i;
- fprintf (dump_file, "Stack adjustment: ");
- fprintf (dump_file, HOST_WIDE_INT_PRINT_DEC, set->stack_adjust);
- fprintf (dump_file, "\n");
+ fprintf (dump_file, "Stack adjustment: " HOST_WIDE_INT_PRINT_DEC "\n",
+ set->stack_adjust);
for (i = 1; i < FIRST_PSEUDO_REGISTER; i++)
{
if (set->regs[i])
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.
- */
-
-static void
-set_frame_base_location (dataflow_set *set, rtx loc)
-{
- 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
-
- var->var_part[0].loc_chain->loc = loc;
- variable_was_changed (var, set->vars);
-}
-
/* Set the part of variable's location in the dataflow set SET. The variable
part is specified by variable's declaration DECL and offset OFFSET and the
part's location by LOC. */
set_variable_part (dataflow_set *set, rtx loc, tree decl, HOST_WIDE_INT offset)
{
int pos, low, high;
- location_chain node, prev, next;
+ 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;
}
pos = low;
- if (pos == var->n_var_parts || var->var_part[pos].offset != offset)
+ if (pos < var->n_var_parts && var->var_part[pos].offset == offset)
{
- /* We have not find the location part, new one will be created. */
+ 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. */
+ return;
+ }
+ else
+ {
+ /* We have to make a copy of a shared variable. */
+ if (var->refcount > 1)
+ var = unshare_variable (set, var);
+ }
+ }
+ else
+ {
+ /* 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);
-#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. */
}
}
- /* 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;
pool_free (loc_chain_pool, node);
+ *nextp = next;
break;
}
else
- prev = node;
+ nextp = &node->next;
}
/* Add the location to the beginning. */
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))
+ {
+ var = unshare_variable (set, var);
+ 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)))
{
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;
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);
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]);
+ 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]
+ && REGNO (loc[n_var_parts])
+ + hard_regno_nregs[REGNO (loc[n_var_parts])][mode]
+ == 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))
NOTE_VAR_LOCATION (note) = gen_rtx_VAR_LOCATION (VOIDmode, var->decl,
NULL_RTX);
}
- 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);
}
- 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);
}
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. */
{
rtx loc = VTI (bb)->mos[i].u.loc;
- if (GET_CODE (loc) == REG)
+ if (REG_P (loc))
var_reg_delete_and_set (&set, loc);
else
var_mem_delete_and_set (&set, loc);
{
rtx loc = VTI (bb)->mos[i].u.loc;
- if (GET_CODE (loc) == REG)
+ if (REG_P (loc))
var_reg_delete (&set, loc);
else
var_mem_delete (&set, loc);
break;
case MO_ADJUST:
- {
- rtx base;
-
- 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);
- }
+ set.stack_adjust += VTI (bb)->mos[i].u.adjust;
break;
}
}
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;
-#ifdef ENABLE_CHECKING
- if (parm != decl)
- abort ();
-#endif
+ 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))
{
-#ifdef ENABLE_CHECKING
- if (REGNO (incoming) >= FIRST_PSEUDO_REGISTER)
- abort ();
-#endif
- 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);
}
+ else if (MEM_P (incoming))
+ set_variable_part (out, incoming, parm, offset);
}
}
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 micro-operations to the array. */
- VTI (bb)->mos = xmalloc (VTI (bb)->n_mos
- * sizeof (struct micro_operation_def));
+ 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++;
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. */
vt_finalize ();
}
+\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_flags_finish */
+ 'V' /* letter */
+};
+