this patch moves nested function information out of symbol table (to a summary).
This saves memory (especially at WPA time) and also makes nested function
support more contained.
gcc/ChangeLog:
2020-10-22 Jan Hubicka <hubicka@ucw.cz>
* cgraph.c: Include tree-nested.h
(cgraph_node::create): Call maybe_record_nested_function.
(cgraph_node::remove): Do not remove function from nested function
infos.
(cgraph_node::dump): Update.
(cgraph_node::unnest): Move to tree-nested.c
(cgraph_node::verify_node): Update.
(cgraph_c_finalize): Call nested_function_info::release.
* cgraph.h (struct symtab_node): Remove nested function info.
* cgraphclones.c (cgraph_node::create_clone): Do not clone nested
function info.
* cgraphunit.c (cgraph_node::analyze): Update.
(cgraph_node::expand): Do not worry about nested functions; they are
lowered.
(symbol_table::finalize_compilation_unit): Call
nested_function_info::release.
* gimplify.c: Include tree-nested.h
(unshare_body): Update.
(unvisit_body): Update.
* omp-offload.c (omp_discover_implicit_declare_target): Update.
* tree-nested.c: Include alloc-pool.h, tree-nested.h, symbol-summary.h
(nested_function_sum): New static variable.
(nested_function_info::get): New member function.
(nested_function_info::get_create): New member function.
(unnest_function): New function.
(nested_function_info::~nested_function_info): New member function.
(nested_function_info::release): New function.
(maybe_record_nested_function): New function.
(lookup_element_for_decl): Update.
(check_for_nested_with_variably_modified): Update.
(create_nesting_tree): Update.
(unnest_nesting_tree_1): Update.
(gimplify_all_functions): Update.
(lower_nested_functions): Update.
* tree-nested.h (class nested_function_info): New class.
(maybe_record_nested_function): Declare.
(unnest_function): Declare.
(first_nested_function): New inline function.
(next_nested_function): New inline function.
(nested_function_origin): New inline function.
gcc/ada/ChangeLog:
2020-10-22 Jan Hubicka <hubicka@ucw.cz>
* gcc-interface/trans.c: Include tree-nested.h
(walk_nesting_tree): Update for new nested function info.
gcc/c-family/ChangeLog:
2020-10-22 Jan Hubicka <hubicka@ucw.cz>
* c-gimplify.c: Include tree-nested.h
(c_genericize): Update for new nested function info.
gcc/d/ChangeLog:
2020-10-22 Jan Hubicka <hubicka@ucw.cz>
* decl.cc: Include tree-nested.h
(get_symbol_decl): Update for new nested function info.
#include "gomp-constants.h"
#include "stringpool.h"
#include "attribs.h"
+#include "tree-nested.h"
#include "ada.h"
#include "adadecode.h"
static void
walk_nesting_tree (struct cgraph_node *node, walk_tree_fn func, void *data)
{
- for (node = node->nested; node; node = node->next_nested)
+ for (node = first_nested_function (node);
+ node; node = next_nested_function (node))
{
walk_tree_without_duplicates (&DECL_SAVED_TREE (node->decl), func, data);
walk_nesting_tree (node, func, data);
#include "langhooks.h"
#include "dumpfile.h"
#include "c-ubsan.h"
+#include "tree-nested.h"
/* The gimplification pass converts the language-dependent trees
(ld-trees) emitted by the parser into language-independent trees
/* Dump all nested functions now. */
cgn = cgraph_node::get_create (fndecl);
- for (cgn = cgn->nested; cgn ; cgn = cgn->next_nested)
+ for (cgn = first_nested_function (cgn);
+ cgn; cgn = next_nested_function (cgn))
c_genericize (cgn->decl);
}
#include "selftest.h"
#include "tree-into-ssa.h"
#include "ipa-inline.h"
+#include "tree-nested.h"
/* FIXME: Only for PROP_loops, but cgraph shouldn't have to know about this. */
#include "tree-pass.h"
node->ifunc_resolver = true;
node->register_symbol ();
+ maybe_record_nested_function (node);
- if (DECL_CONTEXT (decl) && TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL)
- {
- node->origin = cgraph_node::get_create (DECL_CONTEXT (decl));
- node->next_nested = node->origin->nested;
- node->origin->nested = node;
- }
return node;
}
*/
force_output = false;
forced_by_abi = false;
- cgraph_node *next;
- for (cgraph_node *n = nested; n; n = next)
- {
- next = n->next_nested;
- n->origin = NULL;
- n->next_nested = NULL;
- }
- nested = NULL;
- if (origin)
- {
- cgraph_node **node2 = &origin->nested;
- while (*node2 != this)
- node2 = &(*node2)->next_nested;
- *node2 = next_nested;
- }
unregister ();
if (prev_sibling_clone)
prev_sibling_clone->next_sibling_clone = next_sibling_clone;
}
if (tp_first_run > 0)
fprintf (f, " first_run:%" PRId64, (int64_t) tp_first_run);
- if (origin)
+ if (cgraph_node *origin = nested_function_origin (this))
fprintf (f, " nested in:%s", origin->dump_asm_name ());
if (gimple_has_body_p (decl))
fprintf (f, " body");
return DECL_POSSIBLY_INLINED (decl);
}
-/* cgraph_node is no longer nested function; update cgraph accordingly. */
-void
-cgraph_node::unnest (void)
-{
- cgraph_node **node2 = &origin->nested;
- gcc_assert (origin);
-
- while (*node2 != this)
- node2 = &(*node2)->next_nested;
- *node2 = next_nested;
- origin = NULL;
-}
-
/* Return function availability. See cgraph.h for description of individual
return values. */
enum availability
}
}
- if (nested != NULL)
+ if (nested_function_info *info = nested_function_info::get (this))
{
- for (cgraph_node *n = nested; n != NULL; n = n->next_nested)
+ if (info->nested != NULL)
{
- if (n->origin == NULL)
- {
- error ("missing origin for a node in a nested list");
- error_found = true;
- }
- else if (n->origin != this)
+ for (cgraph_node *n = info->nested; n != NULL;
+ n = next_nested_function (n))
{
- error ("origin points to a different parent");
- error_found = true;
- break;
+ nested_function_info *ninfo = nested_function_info::get (n);
+ if (ninfo->origin == NULL)
+ {
+ error ("missing origin for a node in a nested list");
+ error_found = true;
+ }
+ else if (ninfo->origin != this)
+ {
+ error ("origin points to a different parent");
+ error_found = true;
+ break;
+ }
}
}
- }
- if (next_nested != NULL && origin == NULL)
- {
- error ("missing origin for a node in a nested list");
- error_found = true;
+ if (info->next_nested != NULL && info->origin == NULL)
+ {
+ error ("missing origin for a node in a nested list");
+ error_found = true;
+ }
}
if (error_found)
void
cgraph_c_finalize (void)
{
+ nested_function_info::release ();
symtab = NULL;
x_cgraph_nodes_queue = NULL;
/* Constructor. */
explicit cgraph_node (int uid)
: symtab_node (SYMTAB_FUNCTION), callees (NULL), callers (NULL),
- indirect_calls (NULL), origin (NULL), nested (NULL), next_nested (NULL),
+ indirect_calls (NULL),
next_sibling_clone (NULL), prev_sibling_clone (NULL), clones (NULL),
clone_of (NULL), call_site_hash (NULL), former_clone_of (NULL),
simdclone (NULL), simd_clones (NULL), ipa_transforms_to_apply (vNULL),
/* Return the DECL_STRUCT_FUNCTION of the function. */
struct function *get_fun () const;
- /* cgraph_node is no longer nested function; update cgraph accordingly. */
- void unnest (void);
-
/* Bring cgraph node local. */
void make_local (void);
/* List of edges representing indirect calls with a yet undetermined
callee. */
cgraph_edge *indirect_calls;
- /* For nested functions points to function the node is nested in. */
- cgraph_node *origin;
- /* Points to first nested function, if any. */
- cgraph_node *nested;
- /* Pointer to the next function with same origin, if any. */
- cgraph_node *next_nested;
- /* Pointer to the next clone. */
cgraph_node *next_sibling_clone;
cgraph_node *prev_sibling_clone;
cgraph_node *clones;
}
new_node->decl = new_decl;
new_node->register_symbol ();
- new_node->origin = origin;
new_node->lto_file_data = lto_file_data;
- if (new_node->origin)
- {
- new_node->next_nested = new_node->origin->nested;
- new_node->origin->nested = new_node;
- }
new_node->analyzed = analyzed;
new_node->definition = definition;
new_node->versionable = versionable;
/* Lower the function. */
if (!lowered)
{
- if (nested)
+ if (first_nested_function (this))
lower_nested_functions (decl);
- gcc_assert (!nested);
gimple_register_cfg_hooks ();
bitmap_obstack_initialize (NULL);
}
gimple_set_body (decl, NULL);
- if (DECL_STRUCT_FUNCTION (decl) == 0
- && !cgraph_node::get (decl)->origin)
+ if (DECL_STRUCT_FUNCTION (decl) == 0)
{
/* Stop pointing to the local nodes about to be freed.
But DECL_INITIAL must remain nonzero so we know this
- was an actual function definition.
- For a nested function, this is done in c_pop_function_context.
- If rest_of_compilation set this to 0, leave it 0. */
+ was an actual function definition. */
if (DECL_INITIAL (decl) != 0)
DECL_INITIAL (decl) = error_mark_node;
}
/* Gimplify and lower thunks. */
analyze_functions (/*first_time=*/false);
+ /* All nested functions should be lowered now. */
+ nested_function_info::release ();
+
/* Offloading requires LTO infrastructure. */
if (!in_lto_p && g->have_offload)
flag_generate_offload = 1;
#include "function.h"
#include "debug.h"
#include "tree-pretty-print.h"
+#include "tree-nested.h"
#include "d-tree.h"
all static chain passing is handled by the front-end. Do this even
if we are not emitting the body. */
struct cgraph_node *node = cgraph_node::get_create (decl->csym);
- if (node->origin)
- node->unnest ();
+ if (nested_function_origin (node))
+ unnest_function (node);
}
/* Mark compiler generated temporaries as artificial. */
#include "dbgcnt.h"
#include "omp-offload.h"
#include "context.h"
+#include "tree-nested.h"
/* Hash set of poisoned variables in a bind expr. */
static hash_set<tree> *asan_poisoned_variables = NULL;
delete visited;
if (cgn)
- for (cgn = cgn->nested; cgn; cgn = cgn->next_nested)
+ for (cgn = first_nested_function (cgn); cgn;
+ cgn = next_nested_function (cgn))
unshare_body (cgn->decl);
}
unmark_visited (&DECL_SIZE_UNIT (DECL_RESULT (fndecl)));
if (cgn)
- for (cgn = cgn->nested; cgn; cgn = cgn->next_nested)
+ for (cgn = first_nested_function (cgn);
+ cgn; cgn = next_nested_function (cgn))
unvisit_body (cgn->decl);
}
else if (DECL_STRUCT_FUNCTION (node->decl)
&& DECL_STRUCT_FUNCTION (node->decl)->has_omp_target)
worklist.safe_push (node->decl);
- for (cgn = node->nested; cgn; cgn = cgn->next_nested)
+ for (cgn = first_nested_function (node);
+ cgn; cgn = next_nested_function (cgn))
if (omp_declare_target_fn_p (cgn->decl))
worklist.safe_push (cgn->decl);
else if (DECL_STRUCT_FUNCTION (cgn->decl)
#include "gimple-low.h"
#include "gomp-constants.h"
#include "diagnostic.h"
+#include "alloc-pool.h"
+#include "tree-nested.h"
+#include "symbol-summary.h"
+/* Summary of nested functions. */
+static function_summary <nested_function_info *>
+ *nested_function_sum = NULL;
+
+/* Return nested_function_info, if available. */
+nested_function_info *
+nested_function_info::get (cgraph_node *node)
+{
+ if (!nested_function_sum)
+ return NULL;
+ return nested_function_sum->get (node);
+}
+
+/* Return nested_function_info possibly creating new one. */
+nested_function_info *
+nested_function_info::get_create (cgraph_node *node)
+{
+ if (!nested_function_sum)
+ nested_function_sum = new function_summary <nested_function_info *>
+ (symtab);
+ return nested_function_sum->get_create (node);
+}
+
+/* cgraph_node is no longer nested function; update cgraph accordingly. */
+void
+unnest_function (cgraph_node *node)
+{
+ nested_function_info *info = nested_function_info::get (node);
+ cgraph_node **node2 = &nested_function_info::get
+ (nested_function_origin (node))->nested;
+
+ gcc_checking_assert (info->origin);
+ while (*node2 != node)
+ node2 = &nested_function_info::get (*node2)->next_nested;
+ *node2 = info->next_nested;
+ info->next_nested = NULL;
+ info->origin = NULL;
+ nested_function_sum->remove (node);
+}
+
+/* Destructor: unlink function from nested function lists. */
+nested_function_info::~nested_function_info ()
+{
+ cgraph_node *next;
+ for (cgraph_node *n = nested; n; n = next)
+ {
+ nested_function_info *info = nested_function_info::get (n);
+ next = info->next_nested;
+ info->origin = NULL;
+ info->next_nested = NULL;
+ }
+ nested = NULL;
+ if (origin)
+ {
+ cgraph_node **node2
+ = &nested_function_info::get (origin)->nested;
+
+ nested_function_info *info;
+ while ((info = nested_function_info::get (*node2)) != this && info)
+ node2 = &info->next_nested;
+ *node2 = next_nested;
+ }
+}
+
+/* Free nested function info summaries. */
+void
+nested_function_info::release ()
+{
+ if (nested_function_sum)
+ delete (nested_function_sum);
+ nested_function_sum = NULL;
+}
+
+/* If NODE is nested function, record it. */
+void
+maybe_record_nested_function (cgraph_node *node)
+{
+ if (DECL_CONTEXT (node->decl)
+ && TREE_CODE (DECL_CONTEXT (node->decl)) == FUNCTION_DECL)
+ {
+ cgraph_node *origin = cgraph_node::get_create (DECL_CONTEXT (node->decl));
+ nested_function_info *info = nested_function_info::get_create (node);
+ nested_function_info *origin_info
+ = nested_function_info::get_create (origin);
+
+ info->origin = origin;
+ info->next_nested = origin_info->nested;
+ origin_info->nested = node;
+ }
+}
/* The object of this pass is to lower the representation of a set of nested
functions in order to expose all of the gory details of the various
*slot = build_tree_list (NULL_TREE, NULL_TREE);
return (tree) *slot;
-}
+}
/* Given DECL, a nested function, create a field in the non-local
frame structure for this function. */
struct cgraph_node *cgn = cgraph_node::get (fndecl);
tree arg;
- for (cgn = cgn->nested; cgn ; cgn = cgn->next_nested)
+ for (cgn = first_nested_function (cgn); cgn;
+ cgn = next_nested_function (cgn))
{
for (arg = DECL_ARGUMENTS (cgn->decl); arg; arg = DECL_CHAIN (arg))
if (variably_modified_type_p (TREE_TYPE (arg), orig_fndecl))
info->context = cgn->decl;
info->thunk_p = cgn->thunk.thunk_p;
- for (cgn = cgn->nested; cgn ; cgn = cgn->next_nested)
+ for (cgn = first_nested_function (cgn); cgn;
+ cgn = next_nested_function (cgn))
{
struct nesting_info *sub = create_nesting_tree (cgn);
sub->outer = info;
/* For nested functions update the cgraph to reflect unnesting.
We also delay finalizing of these functions up to this point. */
- if (node->origin)
+ if (nested_function_info::get (node)->origin)
{
- node->unnest ();
+ unnest_function (node);
if (!root->thunk_p)
cgraph_node::finalize_function (root->context, true);
}
struct cgraph_node *iter;
if (!gimple_body (root->decl))
gimplify_function_tree (root->decl);
- for (iter = root->nested; iter; iter = iter->next_nested)
+ for (iter = first_nested_function (root); iter;
+ iter = next_nested_function (iter))
if (!iter->thunk.thunk_p)
gimplify_all_functions (iter);
}
/* If there are no nested functions, there's nothing to do. */
cgn = cgraph_node::get (fndecl);
- if (!cgn->nested)
+ if (!first_nested_function (cgn))
return;
gimplify_all_functions (cgn);
extern void insert_field_into_struct (tree, tree);
extern void lower_nested_functions (tree);
+class nested_function_info
+{
+public:
+ /* Constructor. */
+ nested_function_info ()
+ : origin (NULL),
+ nested (NULL),
+ next_nested (NULL)
+ {
+ }
+ /* Copy constructor. We can not simply copy the structure,
+ because the linked lists would go wrong. However we should never
+ need that. */
+ nested_function_info (const nested_function_info &)
+ {
+ gcc_unreachable ();
+ }
+ ~nested_function_info ();
+
+ /* Return nested_function_info, if available. */
+ static nested_function_info *get (cgraph_node *node);
+
+ /* Return nested_function_info possibly creating new one. */
+ static nested_function_info *get_create (cgraph_node *node);
+
+ /* Release all nested_function_infos. */
+ static void release (void);
+
+ /* For nested functions points to function the node is nested in. */
+ cgraph_node *origin;
+ /* Points to first nested function, if any. */
+ cgraph_node *nested;
+ /* Pointer to the next function with same origin, if any. */
+ cgraph_node *next_nested;
+};
+
+extern void maybe_record_nested_function (cgraph_node *node);
+extern void unnest_function (cgraph_node *node);
+
+/* If there are functions nested in NODE, return first one. */
+inline cgraph_node *
+first_nested_function (cgraph_node *node)
+{
+ nested_function_info *info = nested_function_info::get (node);
+ return info ? info->nested : NULL;
+}
+
+/* Return next nested function (used to iterate from first_nested_function). */
+inline cgraph_node *
+next_nested_function (cgraph_node *node)
+{
+ return nested_function_info::get (node)->next_nested;
+}
+
+/* Return origin of nested function (and NULL otherwise). */
+inline cgraph_node *
+nested_function_origin (cgraph_node *node)
+{
+ nested_function_info *info = nested_function_info::get (node);
+ return info ? info->origin : NULL;
+}
+
#endif /* GCC_TREE_NESTED_H */