#include "hashtab.h"
#include "regs.h"
#include "expr.h"
+#include "timevar.h"
+#include "tree-pass.h"
/* Type of micro operation. */
enum micro_operation_type
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;
/* Shall notes be emitted? */
static bool emit_notes;
-/* 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 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 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_set (dataflow_set *, rtx);
static void var_reg_delete_and_set (dataflow_set *, rtx);
static void var_reg_delete (dataflow_set *, rtx);
static void var_regno_delete (dataflow_set *, int);
+static void var_mem_set (dataflow_set *, rtx);
static void var_mem_delete_and_set (dataflow_set *, rtx);
static void var_mem_delete (dataflow_set *, rtx);
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 *);
VTI (bb)->out.stack_adjust = offset;
}
-/* Compute stack adjustment caused by function prologue. */
-
-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 (NOTE_P (insn)
- && 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)
/* Initialize entry block. */
VTI (ENTRY_BLOCK_PTR)->visited = true;
- VTI (ENTRY_BLOCK_PTR)->out.stack_adjust = frame_stack_adjust;
+ 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_iterator));
+ stack = XNEWVEC (edge_iterator, n_basic_blocks + 1);
sp = 0;
/* Push the first edge on to the stack. */
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;
- if (adjustment == 0)
- return mem;
+#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
- 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));
+ 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
htab_traverse (src, vars_copy_1, dst);
}
+/* Set the register to contain REG_EXPR (LOC), REG_OFFSET (LOC). */
+
+static void
+var_reg_set (dataflow_set *set, rtx loc)
+{
+ tree decl = REG_EXPR (loc);
+ HOST_WIDE_INT offset = REG_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);
+}
+
/* Delete current content of register LOC in dataflow set SET
and set the register to contain REG_EXPR (LOC), REG_OFFSET (LOC). */
nextp = &node->next;
}
}
- if (set->regs[REGNO (loc)] == NULL)
- attrs_list_insert (&set->regs[REGNO (loc)], decl, offset, loc);
- set_variable_part (set, loc, decl, offset);
+ var_reg_set (set, loc);
}
/* Delete current content of register LOC in dataflow set SET. */
*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)
{
tree decl = MEM_EXPR (loc);
HOST_WIDE_INT offset = MEM_OFFSET (loc) ? INTVAL (MEM_OFFSET (loc)) : 0;
set_variable_part (set, loc, decl, offset);
}
+/* Delete and 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 (set, loc);
+}
+
/* Delete the location part LOC from dataflow set SET.
Adjust the address first if it is stack pointer based. */
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;
&& track_expr_p (REG_EXPR (loc)))
? MO_SET : MO_CLOBBER);
mo->u.loc = loc;
- mo->insn = (rtx) insn;
+ mo->insn = NEXT_INSN ((rtx) insn);
}
else if (MEM_P (loc)
&& MEM_EXPR (loc)
mo->type = GET_CODE (expr) == CLOBBER ? MO_CLOBBER : MO_SET;
mo->u.loc = loc;
- mo->insn = (rtx) insn;
+ mo->insn = NEXT_INSN ((rtx) insn);
}
}
break;
case MO_USE:
+ {
+ rtx loc = VTI (bb)->mos[i].u.loc;
+
+ if (GET_CODE (loc) == REG)
+ var_reg_set (out, loc);
+ else if (GET_CODE (loc) == MEM)
+ var_mem_set (out, loc);
+ }
+ break;
+
case MO_SET:
{
rtx loc = VTI (bb)->mos[i].u.loc;
break;
case MO_ADJUST:
- {
- rtx base;
-
- out->stack_adjust += VTI (bb)->mos[i].u.adjust;
- base = gen_rtx_MEM (Pmode, plus_constant (stack_pointer_rtx,
- 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 = 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++)
+ 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);
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])
}
}
-/* 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));
- gcc_assert (var);
- gcc_assert (var->n_var_parts == 1);
- gcc_assert (!var->var_part[0].offset);
- gcc_assert (var->var_part[0].loc_chain);
-
- /* 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 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. */
break;
case MO_USE:
+ {
+ rtx loc = VTI (bb)->mos[i].u.loc;
+
+ if (GET_CODE (loc) == REG)
+ var_reg_set (&set, loc);
+ else
+ var_mem_set (&set, loc);
+
+ emit_notes_for_changes (insn, EMIT_NOTE_AFTER_INSN);
+ }
+ break;
+
case MO_SET:
{
rtx loc = VTI (bb)->mos[i].u.loc;
else
var_mem_delete_and_set (&set, loc);
- if (VTI (bb)->mos[i].type == MO_USE)
- 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_BEFORE_INSN);
}
break;
var_mem_delete (&set, loc);
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);
+ else
+ emit_notes_for_changes (insn, EMIT_NOTE_BEFORE_INSN);
}
break;
case MO_ADJUST:
- {
- rtx base;
-
- set.stack_adjust += VTI (bb)->mos[i].u.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);
- }
+ set.stack_adjust += VTI (bb)->mos[i].u.adjust;
break;
}
}
gcc_assert (parm == decl);
- incoming = eliminate_regs (incoming, 0, NULL_RTX);
out = &VTI (ENTRY_BLOCK_PTR)->out;
if (REG_P (incoming))
set_variable_part (out, incoming, parm, offset);
}
else if (MEM_P (incoming))
- {
- set_variable_part (out, incoming, parm, offset);
- }
+ 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;
}
/* 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))
}
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)
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;
- DECL_IGNORED_P (frame_base_decl) = 1;
-
- /* Set its initial "location". */
- 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
- {
- 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 (dump_file)
+ if (dump_file && (dump_flags & TDF_DETAILS))
{
dump_dataflow_sets ();
- dump_flow_info (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_flags_finish */
+ 'V' /* letter */
+};
+