/* 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.
MO_SET, /* Set location. */
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. */
/* 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)
/* Fake variable for stack pointer. */
tree frame_base_decl;
+/* Stack adjust caused by function prologue. */
+static HOST_WIDE_INT frame_stack_adjust;
+
/* Local function prototypes. */
static void stack_adjust_offset_pre_post (rtx, HOST_WIDE_INT *,
HOST_WIDE_INT *);
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 *);
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);
}
}
-/* 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. */
+/* Compute stack adjustment caused by function prologue. */
static HOST_WIDE_INT
prologue_stack_adjust (void)
end = NEXT_INSN (BB_END (bb));
for (insn = BB_HEAD (bb); insn != end; insn = NEXT_INSN (insn))
{
- if (GET_CODE (insn) == NOTE
+ if (NOTE_P (insn)
&& NOTE_LINE_NUMBER (insn) == NOTE_INSN_PROLOGUE_END)
break;
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 = frame_stack_adjust;
/* Allocate stack for back-tracking up CFG. */
- stack = xmalloc ((n_basic_blocks + 1) * sizeof (edge));
+ stack = xmalloc ((n_basic_blocks + 1) * sizeof (edge_iterator));
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--;
rtx adjusted_mem;
rtx tmp;
+ if (adjustment == 0)
+ return mem;
+
adjusted_mem = copy_rtx (mem);
XEXP (adjusted_mem, 0) = replace_rtx (XEXP (adjusted_mem, 0),
stack_pointer_rtx,
variable var = (variable) elem;
location_chain node, next;
+#ifdef ENABLE_CHECKING
+ if (var->refcount <= 0)
+ abort ();
+#endif
+
+ 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++)
+ {
+ if (src->var_part[k].loc_chain)
+ {
+#ifdef ENABLE_CHECKING
+ if (src->var_part[k].cur_loc == NULL)
+ abort ();
+#endif
+ if (src->var_part[k].cur_loc != src->var_part[k].loc_chain->loc)
+ break;
+ }
+#ifdef ENABLE_CHECKING
+ else
+ {
+ if (src->var_part[k].cur_loc != NULL)
+ abort ();
+ }
+#endif
+ }
+ if (k < src->n_var_parts)
+ unshare_variable (set, src);
+ else
+ *dstp = src;
+
+ /* Continue traversing the hash table. */
+ return 1;
}
else
dst = *dstp;
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;
+ k += src->n_var_parts - i;
+ k += dst->n_var_parts - j;
#ifdef ENABLE_CHECKING
/* We track only variables whose size is <= MAX_VAR_PARTS bytes
thus there are at most MAX_VAR_PARTS different offsets. */
abort ();
#endif
+ 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;
dst->n_var_parts = k;
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++;
/* 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;
- /* 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))
+ if (variable_different_p (var1, var2, false))
abort ();
#endif
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_ALIAS_OF (realdecl))
+ realdecl = DECL_DEBUG_ALIAS_OF (realdecl);
+
+ /* 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)
#endif
VTI (bb)->n_mos++;
}
- else if (GET_CODE (*loc) == MEM
+ else if (MEM_P (*loc)
&& MEM_EXPR (*loc)
&& track_expr_p (MEM_EXPR (*loc)))
{
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;
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)));
+ base = gen_rtx_MEM (Pmode, plus_constant (stack_pointer_rtx,
+ out->stack_adjust));
set_frame_base_location (out, base);
}
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));
+ rc_order = xmalloc (n_basic_blocks * sizeof (int));
+ bb_order = xmalloc (last_basic_block * sizeof (int));
flow_depth_first_order_compute (NULL, rc_order);
for (i = 0; i < n_basic_blocks; i++)
bb_order[rc_order[i]] = i;
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, "+");
+ 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, " ");
+ 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");
+ fprintf (dump_file, "Stack adjustment: ");
+ fprintf (dump_file, HOST_WIDE_INT_PRINT_DEC, set->stack_adjust);
+ fprintf (dump_file, "\n");
for (i = 1; 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;
}
/* 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.
- */
+ 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)
abort ();
#endif
+ /* If frame_base_decl is shared unshare it first. */
+ if (var->refcount > 1)
+ var = unshare_variable (set, var);
+
var->var_part[0].loc_chain->loc = loc;
+ var->var_part[0].cur_loc = loc;
variable_was_changed (var, set->vars);
}
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)
+ {
+ 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 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);
#ifdef ENABLE_CHECKING
/* We track only variables whose size is <= MAX_VAR_PARTS bytes
}
}
- /* 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)))
{
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);
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)));
+ base = gen_rtx_MEM (Pmode, plus_constant (stack_pointer_rtx,
+ set.stack_adjust));
set_frame_base_location (&set, base);
emit_notes_for_changes (insn, EMIT_NOTE_AFTER_INSN);
}
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
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 ();
- attrs_list_insert (&in->regs[REGNO (incoming)],
- parm, offset, incoming);
+#endif
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)
+ else if (MEM_P (incoming))
{
- set_variable_part (in, incoming, parm, offset);
set_variable_part (out, incoming, parm, offset);
}
}
}
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. */
+ /* Add the micro-operations to the array. */
VTI (bb)->mos = xmalloc (VTI (bb)->n_mos
* sizeof (struct micro_operation_def));
VTI (bb)->n_mos = 0;
}
}
- if (GET_CODE (insn) == CALL_INSN)
+ if (CALL_P (insn))
{
micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++;
DECL_NAME (frame_base_decl) = get_identifier ("___frame_base_decl");
TREE_TYPE (frame_base_decl) = char_type_node;
DECL_ARTIFICIAL (frame_base_decl) = 1;
+ DECL_IGNORED_P (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);
+ frame_stack_adjust = -prologue_stack_adjust ();
+ base = gen_rtx_MEM (Pmode, plus_constant (stack_pointer_rtx,
+ frame_stack_adjust));
set_variable_part (&VTI (ENTRY_BLOCK_PTR)->out, base, frame_base_decl, 0);
}
else
vt_find_locations ();
vt_emit_notes ();
- if (rtl_dump_file)
+ if (dump_file)
{
dump_dataflow_sets ();
- dump_flow_info (rtl_dump_file);
+ dump_flow_info (dump_file);
}
vt_finalize ();