#include "coretypes.h"
#include "tm.h"
#include "hashtab.h"
+#include "pointer-set.h"
#include "tree.h"
#include "rtl.h"
#include "tm_p.h"
#include "tree-gimple.h"
#include "tree-flow.h"
#include "tree-inline.h"
-#include "tree-alias-common.h"
#include "tree-pass.h"
#include "convert.h"
#include "params.h"
+#include "cgraph.h"
/* Build and maintain data flow information for trees. */
NULL, /* sub */
NULL, /* next */
0, /* static_pass_number */
- 0, /* tv_id */
+ TV_FIND_REFERENCED_VARS, /* tv_id */
PROP_gimple_leh | PROP_cfg, /* properties_required */
PROP_referenced_vars, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- 0, /* todo_flags_finish */
+ 0, /* todo_flags_finish */
+ 0 /* letter */
};
/* Invalidates dataflow information for a statement STMT. */
-static void
+void
free_df_for_stmt (tree stmt)
{
- stmt_ann_t ann = stmt_ann (stmt);
+ dataflow_t *df;
- if (ann && ann->df)
+ if (TREE_CODE (stmt) == PHI_NODE)
+ df = &PHI_DF (stmt);
+ else
{
- /* If we have a varray of immediate uses, then go ahead and release
- it for re-use. */
- if (ann->df->immediate_uses)
- ggc_free (ann->df->immediate_uses);
-
- /* Similarly for the main dataflow structure. */
- ggc_free (ann->df);
- ann->df = NULL;
+ stmt_ann_t ann = stmt_ann (stmt);
+
+ if (!ann)
+ return;
+
+ df = &ann->df;
}
+
+ if (!*df)
+ return;
+
+ /* If we have a varray of immediate uses, then go ahead and release
+ it for re-use. */
+ if ((*df)->immediate_uses)
+ ggc_free ((*df)->immediate_uses);
+
+ /* Similarly for the main dataflow structure. */
+ ggc_free (*df);
+ *df = NULL;
}
-/* Invalidate dataflow information for the whole function. */
+/* Invalidate dataflow information for the whole function.
+
+ Note this only invalidates dataflow information on statements and
+ PHI nodes which are reachable.
+
+ A deleted statement may still have attached dataflow information
+ on it. */
void
free_df (void)
{
int i;
-#ifdef ENABLE_CHECKING
- if (TREE_CODE (phi) != PHI_NODE)
- abort ();
-#endif
+ gcc_assert (TREE_CODE (phi) == PHI_NODE);
for (i = 0; i < PHI_NUM_ARGS (phi); i++)
{
tree use;
ssa_op_iter iter;
-#ifdef ENABLE_CHECKING
/* PHI nodes are handled elsewhere. */
- if (TREE_CODE (stmt) == PHI_NODE)
- abort ();
-#endif
+ gcc_assert (TREE_CODE (stmt) != PHI_NODE);
/* Look at USE_OPS or VUSE_OPS according to FLAGS. */
if (flags & TDFA_USE_OPS)
if (!IS_EMPTY_STMT (imm_rdef_stmt) && (!calc_for || calc_for (use)))
add_immediate_use (imm_rdef_stmt, stmt);
}
- }
+
+ FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_ALL_KILLS)
+ {
+ tree imm_rdef_stmt = SSA_NAME_DEF_STMT (use);
+ if (!IS_EMPTY_STMT (imm_rdef_stmt) && (!calc_for || calc_for (use)))
+ add_immediate_use (imm_rdef_stmt, stmt);
+ }
+ }
}
static void
add_immediate_use (tree stmt, tree use_stmt)
{
- stmt_ann_t ann = get_stmt_ann (stmt);
- struct dataflow_d *df;
+ struct dataflow_d **df;
+
+ if (TREE_CODE (stmt) == PHI_NODE)
+ df = &PHI_DF (stmt);
+ else
+ {
+ stmt_ann_t ann = get_stmt_ann (stmt);
+ df = &ann->df;
+ }
- df = ann->df;
- if (df == NULL)
+ if (*df == NULL)
{
- df = ann->df = ggc_alloc (sizeof (struct dataflow_d));
- memset ((void *) df, 0, sizeof (struct dataflow_d));
- df->uses[0] = use_stmt;
+ *df = ggc_alloc (sizeof (struct dataflow_d));
+ memset ((void *) *df, 0, sizeof (struct dataflow_d));
+ (*df)->uses[0] = use_stmt;
return;
}
- if (!df->uses[1])
+ if (!(*df)->uses[1])
{
- df->uses[1] = use_stmt;
+ (*df)->uses[1] = use_stmt;
return;
}
- if (ann->df->immediate_uses == NULL)
- VARRAY_TREE_INIT (ann->df->immediate_uses, 4, "immediate_uses");
+ if ((*df)->immediate_uses == NULL)
+ VARRAY_TREE_INIT ((*df)->immediate_uses, 4, "immediate_uses");
- VARRAY_PUSH_TREE (ann->df->immediate_uses, use_stmt);
+ VARRAY_PUSH_TREE ((*df)->immediate_uses, use_stmt);
}
redirect_immediate_use (tree use, tree old, tree new)
{
tree imm_stmt = SSA_NAME_DEF_STMT (use);
- struct dataflow_d *df = get_stmt_ann (imm_stmt)->df;
+ struct dataflow_d *df = get_immediate_uses (imm_stmt);
unsigned int num_uses = num_immediate_uses (df);
unsigned int i;
{
var_ann_t ann;
-#if defined ENABLE_CHECKING
- if (t == NULL_TREE
- || !DECL_P (t)
- || (t->common.ann
- && t->common.ann->common.type != VAR_ANN))
- abort ();
-#endif
+ gcc_assert (t);
+ gcc_assert (DECL_P (t));
+ gcc_assert (!t->common.ann || t->common.ann->common.type == VAR_ANN);
ann = ggc_alloc (sizeof (*ann));
memset ((void *) ann, 0, sizeof (*ann));
{
stmt_ann_t ann;
-#if defined ENABLE_CHECKING
- if ((!is_gimple_stmt (t))
- || (t->common.ann
- && t->common.ann->common.type != STMT_ANN))
- abort ();
-#endif
+ gcc_assert (is_gimple_stmt (t));
+ gcc_assert (!t->common.ann || t->common.ann->common.type == STMT_ANN);
ann = ggc_alloc (sizeof (*ann));
memset ((void *) ann, 0, sizeof (*ann));
{
tree_ann_t ann;
-#if defined ENABLE_CHECKING
- if (t == NULL_TREE
- || (t->common.ann
- && t->common.ann->common.type != TREE_ANN_COMMON))
- abort ();
-#endif
+ gcc_assert (t);
+ gcc_assert (!t->common.ann || t->common.ann->common.type == TREE_ANN_COMMON);
ann = ggc_alloc (sizeof (*ann));
memset ((void *) ann, 0, sizeof (*ann));
fprintf (file, ", UID %u", (unsigned) ann->uid);
+ fprintf (file, ", ");
+ print_generic_expr (file, TREE_TYPE (var), dump_flags);
+
if (ann->type_mem_tag)
{
fprintf (file, ", type memory tag: ");
if (is_global_var (var))
fprintf (file, ", is global");
+ if (TREE_THIS_VOLATILE (var))
+ fprintf (file, ", is volatile");
+
if (is_call_clobbered (var))
fprintf (file, ", call clobbered");
size = num_referenced_vars * sizeof (tree);
total += size;
- fprintf (file, fmt_str_1, "Referenced variables", num_referenced_vars,
+ fprintf (file, fmt_str_1, "Referenced variables", (unsigned long)num_referenced_vars,
SCALE (size), LABEL (size));
size = dfa_stats.num_stmt_anns * sizeof (struct stmt_ann_d);
static void
collect_dfa_stats (struct dfa_stats_d *dfa_stats_p)
{
- htab_t htab;
+ struct pointer_set_t *pset;
basic_block bb;
block_stmt_iterator i;
- if (dfa_stats_p == NULL)
- abort ();
+ gcc_assert (dfa_stats_p);
memset ((void *)dfa_stats_p, 0, sizeof (struct dfa_stats_d));
/* Walk all the trees in the function counting references. Start at
basic block 0, but don't stop at block boundaries. */
- htab = htab_create (30, htab_hash_pointer, htab_eq_pointer, NULL);
+ pset = pointer_set_create ();
for (i = bsi_start (BASIC_BLOCK (0)); !bsi_end_p (i); bsi_next (&i))
walk_tree (bsi_stmt_ptr (i), collect_dfa_stats_r, (void *) dfa_stats_p,
- (void *) htab);
+ pset);
- htab_delete (htab);
+ pointer_set_destroy (pset);
FOR_EACH_BB (bb)
{
/* Type, _DECL and constant nodes have no interesting children.
Ignore them. */
- else if (DECL_P (*tp)
- || TYPE_P (*tp)
- || TREE_CODE_CLASS (TREE_CODE (*tp)) == 'c')
+ else if (IS_TYPE_OR_DECL_P (*tp) || CONSTANT_CLASS_P (*tp))
*walk_subtrees = 0;
return NULL_TREE;
if (is_global_var (var))
mark_call_clobbered (var);
- /* If an initialized global variable then register the initializer
- as well. */
- if (POINTER_TYPE_P (TREE_TYPE (var))
- && TREE_READONLY (var)
- && DECL_INITIAL (var)
- && TREE_CODE (DECL_INITIAL (var)) == ADDR_EXPR)
+ /* Scan DECL_INITIAL for pointer variables as they may contain
+ address arithmetic referencing the address of other
+ variables. */
+ if (DECL_INITIAL (var)
+ && POINTER_TYPE_P (TREE_TYPE (var)))
walk_tree (&DECL_INITIAL (var), find_vars_r, walk_state, 0);
}
}
|| handled_component_p (var))
var = TREE_OPERAND (var, 0);
-#ifdef ENABLE_CHECKING
/* Treating GIMPLE registers as virtual variables makes no sense.
Also complain if we couldn't extract a _DECL out of the original
expression. */
- if (!SSA_VAR_P (var)
- || is_gimple_reg (var))
- abort ();
-#endif
+ gcc_assert (SSA_VAR_P (var));
+ gcc_assert (!is_gimple_reg (var));
return var;
}
v_may_defs_after = NUM_V_MAY_DEFS (STMT_V_MAY_DEF_OPS (stmt));
v_must_defs_after = NUM_V_MUST_DEFS (STMT_V_MUST_DEF_OPS (stmt));
- FOR_EACH_SSA_TREE_OPERAND (val, stmt, iter,
- SSA_OP_VMAYDEF | SSA_OP_VUSE | SSA_OP_VMUSTDEF)
-
+ FOR_EACH_SSA_TREE_OPERAND (val, stmt, iter, SSA_OP_ALL_OPERANDS)
{
if (DECL_P (val))
{
if (found_exposed_symbol
|| v_may_defs_before > v_may_defs_after
|| v_must_defs_before > v_must_defs_after)
- bitmap_a_or_b (vars_to_rename, vars_to_rename, vars_in_vops_to_rename);
+ bitmap_ior_into (vars_to_rename, vars_in_vops_to_rename);
BITMAP_XFREE (vars_in_vops_to_rename);
}
+
+/* Find all variables within the gimplified statement that were not previously
+ visible to the function and add them to the referenced variables list. */
+
+static tree
+find_new_referenced_vars_1 (tree *tp, int *walk_subtrees,
+ void *data ATTRIBUTE_UNUSED)
+{
+ tree t = *tp;
+
+ if (TREE_CODE (t) == VAR_DECL && !var_ann (t))
+ add_referenced_tmp_var (t);
+
+ if (IS_TYPE_OR_DECL_P (t))
+ *walk_subtrees = 0;
+
+ return NULL;
+}
+
+void
+find_new_referenced_vars (tree *stmt_p)
+{
+ walk_tree (stmt_p, find_new_referenced_vars_1, NULL, NULL);
+}