/* Callgraph based analysis of static variables.
- Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2005, 2007 Free Software Foundation, Inc.
Contributed by Kenneth Zadeck <zadeck@naturalbridge.com>
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) any later
+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 ANY
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 gathers information about how variables whose scope is
confined to the compilation unit are used.
static inline ipa_reference_vars_info_t
get_reference_vars_info_from_cgraph (struct cgraph_node * node)
{
- return get_var_ann (node->decl)->reference_vars_info;
+ return get_function_ann (node->decl)->reference_vars_info;
}
/* Get a bitmap that contains all of the locally referenced static
static ipa_reference_local_vars_info_t
get_local_reference_vars_info (tree fn)
{
- ipa_reference_vars_info_t info = get_var_ann (fn)->reference_vars_info;
+ ipa_reference_vars_info_t info = get_function_ann (fn)->reference_vars_info;
if (info)
return info->local;
static ipa_reference_global_vars_info_t
get_global_reference_vars_info (tree fn)
{
- ipa_reference_vars_info_t info = get_var_ann (fn)->reference_vars_info;
+ ipa_reference_vars_info_t info = get_function_ann (fn)->reference_vars_info;
if (info)
return info->global;
if (DECL_EXTERNAL (t) || TREE_PUBLIC (t))
return false;
+ /* We cannot touch decls where the type needs constructing. */
+ if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (t)))
+ return false;
+
/* This is a variable we care about. Check if we have seen it
before, and if not add it the set of variables we care about. */
if (!bitmap_bit_p (all_module_statics, DECL_UID (t)))
{
if (!t) return;
- if ((TREE_CODE (t) == VAR_DECL)
+ if ((TREE_CODE (t) == VAR_DECL || TREE_CODE (t) == FUNCTION_DECL)
&& (has_proper_scope_for_analysis (t)))
{
if (checking_write)
if (TREE_CODE (t) == ADDR_EXPR)
{
tree x = get_base_var (t);
- if (TREE_CODE (x) == VAR_DECL)
+ if (TREE_CODE (x) == VAR_DECL || TREE_CODE (x) == FUNCTION_DECL)
if (has_proper_scope_for_analysis (x))
bitmap_set_bit (module_statics_escape, DECL_UID (x));
}
check_call (ipa_reference_local_vars_info_t local, tree call_expr)
{
int flags = call_expr_flags (call_expr);
- tree operand_list = TREE_OPERAND (call_expr, 1);
tree operand;
tree callee_t = get_callee_fndecl (call_expr);
enum availability avail = AVAIL_NOT_AVAILABLE;
+ call_expr_arg_iterator iter;
- for (operand = operand_list;
- operand != NULL_TREE;
- operand = TREE_CHAIN (operand))
- {
- tree argument = TREE_VALUE (operand);
- check_rhs_var (local, argument);
- }
+ FOR_EACH_CALL_EXPR_ARG (operand, iter, call_expr)
+ check_rhs_var (local, operand);
if (callee_t)
{
int *walk_subtrees,
void *data)
{
- struct cgraph_node *fn = data;
+ struct cgraph_node *fn = (struct cgraph_node *) data;
tree t = *tp;
ipa_reference_local_vars_info_t local = NULL;
if (fn)
*walk_subtrees = 0;
break;
- case MODIFY_EXPR:
+ case GIMPLE_MODIFY_STMT:
{
/* First look on the lhs and see what variable is stored to */
- tree lhs = TREE_OPERAND (t, 0);
- tree rhs = TREE_OPERAND (t, 1);
+ tree lhs = GIMPLE_STMT_OPERAND (t, 0);
+ tree rhs = GIMPLE_STMT_OPERAND (t, 1);
check_lhs_var (local, lhs);
/* For the purposes of figuring out what the cast affects */
switch (TREE_CODE_CLASS (TREE_CODE (rhs)))
{
case tcc_binary:
+ case tcc_comparison:
{
tree op0 = TREE_OPERAND (rhs, 0);
tree op1 = TREE_OPERAND (rhs, 1);
case ADDR_EXPR:
check_rhs_var (local, rhs);
break;
- case CALL_EXPR:
+ default:
+ break;
+ }
+ break;
+ case tcc_vl_exp:
+ switch (TREE_CODE (rhs))
+ {
+ case CALL_EXPR:
check_call (local, rhs);
break;
default:
}
/* Lookup the tree node for the static variable that has UID and
- conver the name to a string for debugging. */
+ convert the name to a string for debugging. */
static const char *
get_static_name (int index)
get_reference_vars_info_from_cgraph (target)->local;
/* Make the world safe for tail recursion. */
- struct ipa_dfs_info *node_info = x->aux;
+ struct ipa_dfs_info *node_info = (struct ipa_dfs_info *) x->aux;
if (node_info->aux)
return;
static void
ipa_init (void)
{
+ struct cgraph_node *node;
memory_identifier_string = build_string(7, "memory");
reference_vars_to_consider =
module_statics_written = BITMAP_ALLOC (&ipa_obstack);
all_module_statics = BITMAP_ALLOC (&ipa_obstack);
+ /* This will add NODE->DECL to the splay trees. */
+ for (node = cgraph_nodes; node; node = node->next)
+ has_proper_scope_for_analysis (node->decl);
+
/* There are some shared nodes, in particular the initializers on
static declarations. We do not need to scan them more than once
since all we would be interested in are the addressof
to variables defined within this unit. */
static void
-analyze_variable (struct cgraph_varpool_node *vnode)
+analyze_variable (struct varpool_node *vnode)
{
tree global = vnode->decl;
- if (TREE_CODE (global) == VAR_DECL)
- {
- if (DECL_INITIAL (global))
- walk_tree (&DECL_INITIAL (global), scan_for_static_refs,
- NULL, visited_nodes);
- }
- else gcc_unreachable ();
+ walk_tree (&DECL_INITIAL (global), scan_for_static_refs,
+ NULL, visited_nodes);
}
/* This is the main routine for finding the reference patterns for
analyze_function (struct cgraph_node *fn)
{
ipa_reference_vars_info_t info
- = xcalloc (1, sizeof (struct ipa_reference_vars_info_d));
+ = XCNEW (struct ipa_reference_vars_info_d);
ipa_reference_local_vars_info_t l
- = xcalloc (1, sizeof (struct ipa_reference_local_vars_info_d));
+ = XCNEW (struct ipa_reference_local_vars_info_d);
tree decl = fn->decl;
/* Add the info to the tree's annotation. */
- get_var_ann (fn->decl)->reference_vars_info = info;
+ get_function_ann (fn->decl)->reference_vars_info = info;
info->local = l;
l->statics_read = BITMAP_ALLOC (&ipa_obstack);
FOR_EACH_BB_FN (this_block, this_cfun)
{
block_stmt_iterator bsi;
+ tree phi, op;
+ use_operand_p use;
+ ssa_op_iter iter;
+
+ /* Find the addresses taken in phi node arguments. */
+ for (phi = phi_nodes (this_block); phi; phi = PHI_CHAIN (phi))
+ {
+ FOR_EACH_PHI_ARG (use, phi, iter, SSA_OP_USE)
+ {
+ op = USE_FROM_PTR (use);
+ if (TREE_CODE (op) == ADDR_EXPR)
+ check_rhs_var (l, op);
+ }
+ }
+
for (bsi = bsi_start (this_block); !bsi_end_p (bsi); bsi_next (&bsi))
walk_tree (bsi_stmt_ptr (bsi), scan_for_static_refs,
fn, visited_nodes);
if (DECL_STRUCT_FUNCTION (decl))
{
tree step;
- for (step = DECL_STRUCT_FUNCTION (decl)->unexpanded_var_list;
+ for (step = DECL_STRUCT_FUNCTION (decl)->local_decls;
step;
step = TREE_CHAIN (step))
{
}
- free (get_var_ann (fn->decl)->reference_vars_info);
- get_var_ann (fn->decl)->reference_vars_info = NULL;
+ free (get_function_ann (fn->decl)->reference_vars_info);
+ get_function_ann (fn->decl)->reference_vars_info = NULL;
}
\f
on the local information that was produced by ipa_analyze_function
and ipa_analyze_variable. */
-static void
+static unsigned int
static_execute (void)
{
struct cgraph_node *node;
- struct cgraph_varpool_node *vnode;
+ struct varpool_node *vnode;
struct cgraph_node *w;
struct cgraph_node **order =
- xcalloc (cgraph_n_nodes, sizeof (struct cgraph_node *));
- int order_pos = order_pos = ipa_utils_reduced_inorder (order, false, true);
+ XCNEWVEC (struct cgraph_node *, cgraph_n_nodes);
+ int order_pos = ipa_utils_reduced_inorder (order, false, true);
int i;
ipa_init ();
/* Process all of the variables first. */
- for (vnode = cgraph_varpool_nodes_queue; vnode; vnode = vnode->next_needed)
+ FOR_EACH_STATIC_INITIALIZER (vnode)
analyze_variable (vnode);
/* Process all of the functions next.
unsigned int index;
bitmap_iterator bi;
bitmap module_statics_readonly = BITMAP_ALLOC (&ipa_obstack);
- bitmap module_statics_const = BITMAP_ALLOC (&ipa_obstack);
bitmap bm_temp = BITMAP_ALLOC (&ipa_obstack);
EXECUTE_IF_SET_IN_BITMAP (module_statics_escape, 0, index, bi)
EXECUTE_IF_SET_IN_BITMAP (module_statics_readonly, 0, index, bi)
{
tree var = get_static_decl (index);
- TREE_READONLY (var) = 1;
- if (dump_file)
- fprintf (dump_file, "read-only var %s\n",
- get_static_name (index));
- if (DECL_INITIAL (var)
- && is_gimple_min_invariant (DECL_INITIAL (var)))
+
+ /* Readonly on a function decl is very different from the
+ variable. */
+ if (TREE_CODE (var) == FUNCTION_DECL)
+ continue;
+
+ /* Ignore variables in named sections - changing TREE_READONLY
+ changes the section flags, potentially causing conflicts with
+ other variables in the same named section. */
+ if (DECL_SECTION_NAME (var) == NULL_TREE)
{
- bitmap_set_bit (module_statics_const, index);
+ TREE_READONLY (var) = 1;
if (dump_file)
- fprintf (dump_file, "read-only constant %s\n",
+ fprintf (dump_file, "read-only var %s\n",
get_static_name (index));
}
}
}
BITMAP_FREE(module_statics_readonly);
- BITMAP_FREE(module_statics_const);
BITMAP_FREE(bm_temp);
}
{
ipa_reference_vars_info_t node_info;
ipa_reference_global_vars_info_t node_g =
- xcalloc (1, sizeof (struct ipa_reference_global_vars_info_d));
+ XCNEW (struct ipa_reference_global_vars_info_d);
ipa_reference_local_vars_info_t node_l;
bool read_all;
/* If any node in a cycle is calls_read_all or calls_write_all
they all are. */
- w_info = node->aux;
+ w_info = (struct ipa_dfs_info *) node->aux;
w = w_info->next_cycle;
while (w)
{
read_all |= w_l->calls_read_all;
write_all |= w_l->calls_write_all;
- w_info = w->aux;
+ w_info = (struct ipa_dfs_info *) w->aux;
w = w_info->next_cycle;
}
node_l->statics_written);
}
- w_info = node->aux;
+ w_info = (struct ipa_dfs_info *) node->aux;
w = w_info->next_cycle;
while (w)
{
if (!write_all)
bitmap_ior_into (node_g->statics_written,
w_l->statics_written);
- w_info = w->aux;
+ w_info = (struct ipa_dfs_info *) w->aux;
w = w_info->next_cycle;
}
while (w)
{
propagate_bits (w);
- w_info = w->aux;
+ w_info = (struct ipa_dfs_info *) w->aux;
w = w_info->next_cycle;
}
}
node = order[i];
merge_callee_local_info (node, node);
- w_info = node->aux;
+ w_info = (struct ipa_dfs_info *) node->aux;
w = w_info->next_cycle;
while (w)
{
merge_callee_local_info (w, w);
- w_info = w->aux;
+ w_info = (struct ipa_dfs_info *) w->aux;
w = w_info->next_cycle;
}
}
get_static_name (index));
}
- w_info = node->aux;
+ w_info = (struct ipa_dfs_info *) node->aux;
w = w_info->next_cycle;
while (w)
{
}
- w_info = w->aux;
+ w_info = (struct ipa_dfs_info *) w->aux;
w = w_info->next_cycle;
}
fprintf (dump_file, "\n globals read: ");
&& (cgraph_function_body_availability (node) == AVAIL_OVERWRITABLE))
clean_function (node);
}
+ return 0;
}
&& !(errorcount || sorrycount));
}
-struct tree_opt_pass pass_ipa_reference =
+struct simple_ipa_opt_pass pass_ipa_reference =
{
+ {
+ SIMPLE_IPA_PASS,
"static-var", /* name */
gate_reference, /* gate */
static_execute, /* execute */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- 0, /* todo_flags_finish */
- 0 /* letter */
+ 0 /* todo_flags_finish */
+ }
};
#include "gt-ipa-reference.h"