#include "varray.h"
#include "ggc.h"
#include "tree-flow.h"
+#include "tree-pass.h"
/* Rewriting a function into SSA form can create a huge number of SSA_NAMEs,
many of which may be thrown away shortly after their creation if jumps
We could also use a zone allocator for these objects since they have
a very well defined lifetime. If someone wants to experiment with that
this is the place to try it. */
-
-/* Array of all SSA_NAMEs used in the function. */
-VEC(tree,gc) *ssa_names;
-
-/* Free list of SSA_NAMEs. This list is wiped at the end of each function
- after we leave SSA form. */
-static GTY (()) tree free_ssanames;
/* Version numbers with special meanings. We start allocating new version
numbers after the special ones. */
void
init_ssanames (void)
{
- ssa_names = VEC_alloc (tree, gc, 50);
+ SSANAMES (cfun) = VEC_alloc (tree, gc, 50);
/* Version 0 is special, so reserve the first slot in the table. Though
currently unused, we may use version 0 in alias analysis as part of
We use VEC_quick_push here because we know that SSA_NAMES has at
least 50 elements reserved in it. */
- VEC_quick_push (tree, ssa_names, NULL_TREE);
- free_ssanames = NULL;
+ VEC_quick_push (tree, SSANAMES (cfun), NULL_TREE);
+ FREE_SSANAMES (cfun) = NULL;
}
/* Finalize management of SSA_NAMEs. */
void
fini_ssanames (void)
{
- VEC_free (tree, gc, ssa_names);
- free_ssanames = NULL;
+ VEC_free (tree, gc, SSANAMES (cfun));
+ FREE_SSANAMES (cfun) = NULL;
}
/* Dump some simple statistics regarding the re-use of SSA_NAME nodes. */
gcc_assert (DECL_P (var)
|| TREE_CODE (var) == INDIRECT_REF);
- gcc_assert (!stmt || EXPR_P (stmt) || TREE_CODE (stmt) == PHI_NODE);
+ gcc_assert (!stmt
+ || EXPR_P (stmt) || GIMPLE_STMT_P (stmt)
+ || TREE_CODE (stmt) == PHI_NODE);
/* If our free list has an element, then use it. */
- if (free_ssanames)
+ if (FREE_SSANAMES (cfun))
{
- t = free_ssanames;
- free_ssanames = TREE_CHAIN (free_ssanames);
+ t = FREE_SSANAMES (cfun);
+ FREE_SSANAMES (cfun) = TREE_CHAIN (FREE_SSANAMES (cfun));
#ifdef GATHER_STATISTICS
ssa_name_nodes_reused++;
#endif
/* The node was cleared out when we put it on the free list, so
there is no need to do so again here. */
gcc_assert (ssa_name (SSA_NAME_VERSION (t)) == NULL);
- VEC_replace (tree, ssa_names, SSA_NAME_VERSION (t), t);
+ VEC_replace (tree, SSANAMES (cfun), SSA_NAME_VERSION (t), t);
}
else
{
t = make_node (SSA_NAME);
SSA_NAME_VERSION (t) = num_ssa_names;
- VEC_safe_push (tree, gc, ssa_names, t);
+ VEC_safe_push (tree, gc, SSANAMES (cfun), t);
#ifdef GATHER_STATISTICS
ssa_name_nodes_created++;
#endif
SSA_NAME_DEF_STMT (t) = stmt;
SSA_NAME_PTR_INFO (t) = NULL;
SSA_NAME_IN_FREE_LIST (t) = 0;
+ SSA_NAME_IS_DEFAULT_DEF (t) = 0;
imm = &(SSA_NAME_IMM_USE_NODE (t));
imm->use = NULL;
imm->prev = imm;
/* Never release the default definition for a symbol. It's a
special SSA name that should always exist once it's created. */
- if (var == default_def (SSA_NAME_VAR (var)))
+ if (SSA_NAME_IS_DEFAULT_DEF (var))
return;
/* If VAR has been registered for SSA updating, don't remove it.
while (imm->next != imm)
delink_imm_use (imm->next);
- VEC_replace (tree, ssa_names, SSA_NAME_VERSION (var), NULL_TREE);
+ VEC_replace (tree, SSANAMES (cfun),
+ SSA_NAME_VERSION (var), NULL_TREE);
memset (var, 0, tree_size (var));
imm->prev = imm;
SSA_NAME_IN_FREE_LIST (var) = 1;
/* And finally link it into the free list. */
- TREE_CHAIN (var) = free_ssanames;
- free_ssanames = var;
+ TREE_CHAIN (var) = FREE_SSANAMES (cfun);
+ FREE_SSANAMES (cfun) = var;
}
}
if (!ptr_info)
return;
- new_ptr_info = ggc_alloc (sizeof (struct ptr_info_def));
+ new_ptr_info = GGC_NEW (struct ptr_info_def);
*new_ptr_info = *ptr_info;
if (ptr_info->pt_vars)
/* Make sure that we are in SSA. Otherwise, operand cache may point
to garbage. */
- gcc_assert (in_ssa_p);
+ gcc_assert (gimple_in_ssa_p (cfun));
FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_ALL_DEFS)
if (TREE_CODE (def) == SSA_NAME)
TREE_TYPE (ssa_name) = TREE_TYPE (sym);
}
-#include "gt-tree-ssanames.h"
+/* Return SSA names that are unused to GGC memory. This is used to keep
+ footprint of compiler during interprocedural optimization.
+ As a side effect the SSA_NAME_VERSION number reuse is reduced
+ so this function should not be used too often. */
+static unsigned int
+release_dead_ssa_names (void)
+{
+ tree t, next;
+ int n = 0;
+ referenced_var_iterator rvi;
+
+ /* Current defs point to various dead SSA names that in turn points to dead
+ statements so bunch of dead memory is held from releasing. */
+ FOR_EACH_REFERENCED_VAR (t, rvi)
+ set_current_def (t, NULL);
+ /* Now release the freelist. */
+ for (t = FREE_SSANAMES (cfun); t; t = next)
+ {
+ next = TREE_CHAIN (t);
+ /* Dangling pointers might make GGC to still see dead SSA names, so it is
+ important to unlink the list and avoid GGC from seeing all subsequent
+ SSA names. In longer run we want to have all dangling pointers here
+ removed (since they usually go through dead statements that consume
+ considerable amounts of memory). */
+ TREE_CHAIN (t) = NULL_TREE;
+ n++;
+ }
+ FREE_SSANAMES (cfun) = NULL;
+
+ /* Cgraph edges has been invalidated and point to dead statement. We need to
+ remove them now and will rebuild it before next IPA pass. */
+ cgraph_node_remove_callees (cgraph_node (current_function_decl));
+
+ if (dump_file)
+ fprintf (dump_file, "Released %i names, %.2f%%\n", n, n * 100.0 / num_ssa_names);
+ return 0;
+}
+
+struct tree_opt_pass pass_release_ssa_names =
+{
+ "release_ssa", /* name */
+ NULL, /* gate */
+ release_dead_ssa_names, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ 0, /* tv_id */
+ PROP_ssa, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ 0, /* todo_flags_finish */
+ 0 /* letter */
+};