been written as independent functions without change. */
-struct var_map_elt
+struct var_map_elt GTY(())
{
tree old;
tree new;
};
-struct nesting_info
+struct nesting_info GTY ((chain_next ("%h.next")))
{
struct nesting_info *outer;
struct nesting_info *inner;
struct nesting_info *next;
- htab_t var_map;
+ htab_t GTY ((param_is (struct var_map_elt))) var_map;
tree context;
tree new_local_var_chain;
tree frame_type;
info->frame_type = type;
info->frame_decl = create_tmp_var_for (info, type, "FRAME");
+
+ /* ??? Always make it addressable for now, since it is meant to
+ be pointed to by the static chain pointer. This pessimizes
+ when it turns out that no static chains are needed because
+ the nested functions referencing non-local variables are not
+ reachable, but the true pessimization is to create the non-
+ local frame structure in the first place. */
+ TREE_ADDRESSABLE (info->frame_decl) = 1;
}
return type;
}
insert_field_into_struct (get_frame_type (info), field);
- elt = xmalloc (sizeof (*elt));
+ elt = ggc_alloc (sizeof (*elt));
elt->old = decl;
elt->new = field;
*slot = elt;
insert_field_into_struct (get_frame_type (info), field);
- elt = xmalloc (sizeof (*elt));
+ elt = ggc_alloc (sizeof (*elt));
elt->old = decl;
elt->new = field;
*slot = elt;
static struct nesting_info *
create_nesting_tree (struct cgraph_node *cgn)
{
- struct nesting_info *info = xcalloc (1, sizeof (*info));
- info->var_map = htab_create (7, var_map_hash, var_map_eq, free);
+ struct nesting_info *info = ggc_calloc (1, sizeof (*info));
+ info->var_map = htab_create_ggc (7, var_map_hash, var_map_eq, ggc_free);
info->context = cgn->decl;
for (cgn = cgn->nested; cgn ; cgn = cgn->next_nested)
struct walk_stmt_info *wi = data;
struct nesting_info *info = wi->info;
tree t = *tp, field, x;
+ bool save_val_only;
+ *walk_subtrees = 0;
switch (TREE_CODE (t))
{
case VAR_DECL:
break;
case ADDR_EXPR:
- {
- bool save_val_only = wi->val_only;
-
- wi->val_only = false;
- wi->is_lhs = false;
- wi->changed = false;
- walk_tree (&TREE_OPERAND (t, 0), convert_local_reference, wi, NULL);
- wi->val_only = save_val_only;
+ save_val_only = wi->val_only;
+ wi->val_only = false;
+ wi->is_lhs = false;
+ wi->changed = false;
+ walk_tree (&TREE_OPERAND (t, 0), convert_local_reference, wi, NULL);
+ wi->val_only = save_val_only;
- /* If we converted anything ... */
- if (wi->changed)
- {
- tree save_context;
+ /* If we converted anything ... */
+ if (wi->changed)
+ {
+ tree save_context;
- /* Then the frame decl is now addressable. */
- TREE_ADDRESSABLE (info->frame_decl) = 1;
+ /* Then the frame decl is now addressable. */
+ TREE_ADDRESSABLE (info->frame_decl) = 1;
- save_context = current_function_decl;
- current_function_decl = info->context;
- recompute_tree_invarant_for_addr_expr (t);
- current_function_decl = save_context;
-
- /* If we are in a context where we only accept values, then
- compute the address into a temporary. */
- if (save_val_only)
- *tp = tsi_gimplify_val (wi->info, t, &wi->tsi);
- }
- }
+ save_context = current_function_decl;
+ current_function_decl = info->context;
+ recompute_tree_invarant_for_addr_expr (t);
+ current_function_decl = save_context;
+
+ /* If we are in a context where we only accept values, then
+ compute the address into a temporary. */
+ if (save_val_only)
+ *tp = tsi_gimplify_val (wi->info, t, &wi->tsi);
+ }
break;
case REALPART_EXPR:
/* Go down this entire nest and just look at the final prefix and
anything that describes the references. Otherwise, we lose track
of whether a NOP_EXPR or VIEW_CONVERT_EXPR needs a simple value. */
+ save_val_only = wi->val_only;
wi->val_only = true;
wi->is_lhs = false;
for (; handled_component_p (t); tp = &TREE_OPERAND (t, 0), t = *tp)
}
wi->val_only = false;
walk_tree (tp, convert_local_reference, wi, NULL);
+ wi->val_only = save_val_only;
break;
default:
struct walk_stmt_info *wi = data;
struct nesting_info *info = wi->info, *i;
tree t = *tp, label, new_label, target_context, x, arg, field;
- struct var_map_elt *elt;
+ struct var_map_elt *elt, dummy;
void **slot;
*walk_subtrees = 0;
control transfer. This new label will be marked LABEL_NONLOCAL; this
mark will trigger proper behavior in the cfg, as well as cause the
(hairy target-specific) non-local goto receiver code to be generated
- when we expand rtl. */
- new_label = create_artificial_label ();
- DECL_NONLOCAL (new_label) = 1;
-
- /* Enter this association into var_map so that we can insert the new
- label into the IL during a second pass. */
- elt = xmalloc (sizeof (*elt));
- elt->old = label;
- elt->new = new_label;
- slot = htab_find_slot (i->var_map, elt, INSERT);
- *slot = elt;
+ when we expand rtl. Enter this association into var_map so that we
+ can insert the new label into the IL during a second pass. */
+ dummy.old = label;
+ slot = htab_find_slot (i->var_map, &dummy, INSERT);
+ elt = *slot;
+ if (elt == NULL)
+ {
+ new_label = create_artificial_label ();
+ DECL_NONLOCAL (new_label) = 1;
+
+ elt = ggc_alloc (sizeof (*elt));
+ elt->old = label;
+ elt->new = new_label;
+ *slot = elt;
+ }
+ else
+ new_label = elt->new;
/* Build: __builtin_nl_goto(new_label, &chain->nl_goto_field). */
field = get_nl_goto_field (i);
free_nesting_tree (root->inner);
htab_delete (root->var_map);
next = root->next;
- free (root);
+ ggc_free (root);
root = next;
}
while (root);
}
+static GTY(()) struct nesting_info *root;
+
/* Main entry point for this pass. Process FNDECL and all of its nested
subroutines and turn them into something less tightly bound. */
void
lower_nested_functions (tree fndecl)
{
- struct nesting_info *root;
struct cgraph_node *cgn;
/* If there are no nested functions, there's nothing to do. */
convert_all_function_calls (root);
finalize_nesting_tree (root);
free_nesting_tree (root);
+ root = NULL;
}
#include "gt-tree-nested.h"