/* Nested function decomposition for trees.
- Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
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)
+ the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful,
GNU General Public License 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, 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA. */
+ along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#include "cgraph.h"
#include "expr.h"
#include "langhooks.h"
+#include "pointer-set.h"
#include "ggc.h"
been written as independent functions without change. */
-struct var_map_elt GTY(())
-{
- tree old;
- tree new;
-};
-
-struct nesting_info GTY ((chain_next ("%h.next")))
+struct nesting_info
{
struct nesting_info *outer;
struct nesting_info *inner;
struct nesting_info *next;
- htab_t GTY ((param_is (struct var_map_elt))) field_map;
- htab_t GTY ((param_is (struct var_map_elt))) var_map;
+ struct pointer_map_t *field_map;
+ struct pointer_map_t *var_map;
bitmap suppress_expansion;
tree context;
bool any_parm_remapped;
bool any_tramp_created;
+ char static_chain_added;
};
-/* Hashing and equality functions for nesting_info->var_map. */
+/* Obstack used for the bitmaps in the struct above. */
+static struct bitmap_obstack nesting_info_bitmap_obstack;
-static hashval_t
-var_map_hash (const void *x)
-{
- const struct var_map_elt *a = (const struct var_map_elt *) x;
- return htab_hash_pointer (a->old);
-}
-
-static int
-var_map_eq (const void *x, const void *y)
-{
- const struct var_map_elt *a = (const struct var_map_elt *) x;
- const struct var_map_elt *b = (const struct var_map_elt *) y;
- return a->old == b->old;
-}
/* We're working in so many different function contexts simultaneously,
that create_tmp_var is dangerous. Prevent mishap. */
DECL_CONTEXT (tmp_var) = info->context;
TREE_CHAIN (tmp_var) = info->new_local_var_chain;
DECL_SEEN_IN_BIND_EXPR_P (tmp_var) = 1;
+ if (TREE_CODE (type) == COMPLEX_TYPE
+ || TREE_CODE (type) == VECTOR_TYPE)
+ DECL_GIMPLE_REG_P (tmp_var) = 1;
+
info->new_local_var_chain = tmp_var;
return tmp_var;
save_context = current_function_decl;
current_function_decl = context;
retval = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (exp)), exp);
- current_function_decl = save_context;;
+ current_function_decl = save_context;
return retval;
}
TREE_CHAIN (field) = *p;
*p = field;
+
+ /* Set correct alignment for frame struct type. */
+ if (TYPE_ALIGN (type) < DECL_ALIGN (field))
+ TYPE_ALIGN (type) = DECL_ALIGN (field);
}
/* Build or return the RECORD_TYPE that describes the frame state that is
lookup_field_for_decl (struct nesting_info *info, tree decl,
enum insert_option insert)
{
- struct var_map_elt *elt, dummy;
void **slot;
- tree field;
- dummy.old = decl;
- slot = htab_find_slot (info->field_map, &dummy, insert);
- if (!slot)
+ if (insert == NO_INSERT)
{
- gcc_assert (insert != INSERT);
- return NULL;
+ slot = pointer_map_contains (info->field_map, decl);
+ return slot ? *slot : NULL;
}
- elt = (struct var_map_elt *) *slot;
- if (!elt && insert == INSERT)
+ slot = pointer_map_insert (info->field_map, decl);
+ if (!*slot)
{
- field = make_node (FIELD_DECL);
+ tree field = make_node (FIELD_DECL);
DECL_NAME (field) = DECL_NAME (decl);
if (use_pointer_in_frame (decl))
}
insert_field_into_struct (get_frame_type (info), field);
-
- elt = GGC_NEW (struct var_map_elt);
- elt->old = decl;
- elt->new = field;
- *slot = elt;
+ *slot = field;
if (TREE_CODE (decl) == PARM_DECL)
info->any_parm_remapped = true;
}
- else
- field = elt ? elt->new : NULL;
- return field;
+ return *slot;
}
/* Build or return the variable that holds the static chain within
tree t, stmt;
t = create_tmp_var_for (info, TREE_TYPE (exp), NULL);
- stmt = build2 (MODIFY_EXPR, TREE_TYPE (t), t, exp);
+ stmt = build_gimple_modify_stmt (t, exp);
SET_EXPR_LOCUS (stmt, EXPR_LOCUS (tsi_stmt (*tsi)));
tsi_link_before (tsi, stmt, TSI_SAME_STMT);
tree t, stmt;
t = create_tmp_var_for (info, TREE_TYPE (exp), NULL);
- stmt = build2 (MODIFY_EXPR, TREE_TYPE (t), exp, t);
+ stmt = build_gimple_modify_stmt (exp, t);
SET_EXPR_LOCUS (stmt, EXPR_LOCUS (tsi_stmt (*tsi)));
tsi_link_after (tsi, stmt, TSI_SAME_STMT);
static tree
get_trampoline_type (void)
{
- tree record, t;
unsigned align, size;
+ tree t;
if (trampoline_type)
return trampoline_type;
DECL_ALIGN (t) = align;
DECL_USER_ALIGN (t) = 1;
- record = make_node (RECORD_TYPE);
- TYPE_NAME (record) = get_identifier ("__builtin_trampoline");
- TYPE_FIELDS (record) = t;
- layout_type (record);
+ trampoline_type = make_node (RECORD_TYPE);
+ TYPE_NAME (trampoline_type) = get_identifier ("__builtin_trampoline");
+ TYPE_FIELDS (trampoline_type) = t;
+ layout_type (trampoline_type);
- return record;
+ return trampoline_type;
}
/* Given DECL, a nested function, find or create a field in the non-local
lookup_tramp_for_decl (struct nesting_info *info, tree decl,
enum insert_option insert)
{
- struct var_map_elt *elt, dummy;
void **slot;
- tree field;
- dummy.old = decl;
- slot = htab_find_slot (info->var_map, &dummy, insert);
- if (!slot)
+ if (insert == NO_INSERT)
{
- gcc_assert (insert != INSERT);
- return NULL;
+ slot = pointer_map_contains (info->var_map, decl);
+ return slot ? *slot : NULL;
}
- elt = (struct var_map_elt *) *slot;
- if (!elt && insert == INSERT)
+ slot = pointer_map_insert (info->var_map, decl);
+ if (!*slot)
{
- field = make_node (FIELD_DECL);
+ tree field = make_node (FIELD_DECL);
DECL_NAME (field) = DECL_NAME (decl);
TREE_TYPE (field) = get_trampoline_type ();
TREE_ADDRESSABLE (field) = 1;
insert_field_into_struct (get_frame_type (info), field);
-
- elt = GGC_NEW (struct var_map_elt);
- elt->old = decl;
- elt->new = field;
- *slot = elt;
+ *slot = field;
info->any_tramp_created = true;
}
- else
- field = elt ? elt->new : NULL;
- return field;
+ return *slot;
}
/* Build or return the field within the non-local frame state that holds
return field;
}
\f
+/* Helper function for walk_stmts. Walk output operands of an ASM_EXPR. */
+
+static void
+walk_asm_expr (struct walk_stmt_info *wi, tree stmt)
+{
+ int noutputs = list_length (ASM_OUTPUTS (stmt));
+ const char **oconstraints
+ = (const char **) alloca ((noutputs) * sizeof (const char *));
+ int i;
+ tree link;
+ const char *constraint;
+ bool allows_mem, allows_reg, is_inout;
+
+ wi->is_lhs = true;
+ for (i=0, link = ASM_OUTPUTS (stmt); link; ++i, link = TREE_CHAIN (link))
+ {
+ constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link)));
+ oconstraints[i] = constraint;
+ parse_output_constraint (&constraint, i, 0, 0, &allows_mem,
+ &allows_reg, &is_inout);
+
+ wi->val_only = (allows_reg || !allows_mem);
+ walk_tree (&TREE_VALUE (link), wi->callback, wi, NULL);
+ }
+
+ for (link = ASM_INPUTS (stmt); link; link = TREE_CHAIN (link))
+ {
+ constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link)));
+ parse_input_constraint (&constraint, 0, 0, noutputs, 0,
+ oconstraints, &allows_mem, &allows_reg);
+
+ wi->val_only = (allows_reg || !allows_mem);
+ /* Although input "m" is not really a LHS, we need a lvalue. */
+ wi->is_lhs = !wi->val_only;
+ walk_tree (&TREE_VALUE (link), wi->callback, wi, NULL);
+ }
+
+ wi->is_lhs = false;
+ wi->val_only = true;
+}
+
/* Iterate over all sub-statements of *TP calling walk_tree with
WI->CALLBACK for every sub-expression in each statement found. */
walk_stmts (wi, &TREE_OPERAND (t, 0));
break;
- case MODIFY_EXPR:
+ case GIMPLE_MODIFY_STMT:
/* A formal temporary lhs may use a COMPONENT_REF rhs. */
- wi->val_only = !is_gimple_formal_tmp_var (TREE_OPERAND (t, 0));
- walk_tree (&TREE_OPERAND (t, 1), wi->callback, wi, NULL);
+ wi->val_only = !is_gimple_formal_tmp_var (GIMPLE_STMT_OPERAND (t, 0));
+ walk_tree (&GIMPLE_STMT_OPERAND (t, 1), wi->callback, wi, NULL);
/* If the rhs is appropriate for a memory, we may use a
COMPONENT_REF on the lhs. */
- wi->val_only = !is_gimple_mem_rhs (TREE_OPERAND (t, 1));
+ wi->val_only = !is_gimple_mem_rhs (GIMPLE_STMT_OPERAND (t, 1));
wi->is_lhs = true;
- walk_tree (&TREE_OPERAND (t, 0), wi->callback, wi, NULL);
+ walk_tree (&GIMPLE_STMT_OPERAND (t, 0), wi->callback, wi, NULL);
wi->val_only = true;
wi->is_lhs = false;
break;
+ case ASM_EXPR:
+ walk_asm_expr (wi, *tp);
+ break;
+
default:
wi->val_only = true;
walk_tree (tp, wi->callback, wi, NULL);
walk_body (callback, info, &DECL_SAVED_TREE (info->context));
}
+/* Invoke CALLBACK on OMP_FOR init, cond, incr and pre-body. */
+
+static void
+walk_omp_for (walk_tree_fn callback, struct nesting_info *info, tree for_stmt)
+{
+ struct walk_stmt_info wi;
+ tree t, list = NULL, empty;
+
+ walk_body (callback, info, &OMP_FOR_PRE_BODY (for_stmt));
+
+ empty = build_empty_stmt ();
+ append_to_statement_list_force (empty, &list);
+ memset (&wi, 0, sizeof (wi));
+ wi.callback = callback;
+ wi.info = info;
+ wi.tsi = tsi_last (list);
+
+ t = OMP_FOR_INIT (for_stmt);
+ gcc_assert (TREE_CODE (t) == GIMPLE_MODIFY_STMT);
+ SET_EXPR_LOCUS (empty, EXPR_LOCUS (t));
+ wi.val_only = false;
+ walk_tree (&GIMPLE_STMT_OPERAND (t, 0), callback, &wi, NULL);
+ wi.val_only = true;
+ wi.is_lhs = false;
+ walk_tree (&GIMPLE_STMT_OPERAND (t, 1), callback, &wi, NULL);
+
+ t = OMP_FOR_COND (for_stmt);
+ gcc_assert (COMPARISON_CLASS_P (t));
+ SET_EXPR_LOCUS (empty, EXPR_LOCUS (t));
+ wi.val_only = false;
+ walk_tree (&TREE_OPERAND (t, 0), callback, &wi, NULL);
+ wi.val_only = true;
+ wi.is_lhs = false;
+ walk_tree (&TREE_OPERAND (t, 1), callback, &wi, NULL);
+
+ t = OMP_FOR_INCR (for_stmt);
+ gcc_assert (TREE_CODE (t) == GIMPLE_MODIFY_STMT);
+ SET_EXPR_LOCUS (empty, EXPR_LOCUS (t));
+ wi.val_only = false;
+ walk_tree (&GIMPLE_STMT_OPERAND (t, 0), callback, &wi, NULL);
+ t = GIMPLE_STMT_OPERAND (t, 1);
+ gcc_assert (BINARY_CLASS_P (t));
+ wi.val_only = false;
+ walk_tree (&TREE_OPERAND (t, 0), callback, &wi, NULL);
+ wi.val_only = true;
+ wi.is_lhs = false;
+ walk_tree (&TREE_OPERAND (t, 1), callback, &wi, NULL);
+
+ /* Remove empty statement added above from the end of statement list. */
+ tsi_delink (&wi.tsi);
+ append_to_statement_list (list, &OMP_FOR_PRE_BODY (for_stmt));
+}
+
/* Similarly for ROOT and all functions nested underneath, depth first. */
static void
static struct nesting_info *
create_nesting_tree (struct cgraph_node *cgn)
{
- struct nesting_info *info = GGC_CNEW (struct nesting_info);
- info->field_map = htab_create_ggc (7, var_map_hash, var_map_eq, ggc_free);
- info->var_map = htab_create_ggc (7, var_map_hash, var_map_eq, ggc_free);
- info->suppress_expansion = BITMAP_GGC_ALLOC ();
+ struct nesting_info *info = XCNEW (struct nesting_info);
+ info->field_map = pointer_map_create ();
+ info->var_map = pointer_map_create ();
+ info->suppress_expansion = BITMAP_ALLOC (&nesting_info_bitmap_obstack);
info->context = cgn->decl;
for (cgn = cgn->nested; cgn ; cgn = cgn->next_nested)
static tree
get_nonlocal_debug_decl (struct nesting_info *info, tree decl)
{
- struct var_map_elt *elt, dummy;
tree target_context;
struct nesting_info *i;
tree x, field, new_decl;
void **slot;
- dummy.old = decl;
- slot = htab_find_slot (info->var_map, &dummy, INSERT);
- elt = *slot;
+ slot = pointer_map_insert (info->var_map, decl);
- if (elt)
- return elt->new;
+ if (*slot)
+ return *slot;
target_context = decl_function_context (decl);
SET_DECL_VALUE_EXPR (new_decl, x);
DECL_HAS_VALUE_EXPR_P (new_decl) = 1;
- elt = ggc_alloc (sizeof (*elt));
- elt->old = decl;
- elt->new = new_decl;
- *slot = elt;
-
+ *slot = new_decl;
TREE_CHAIN (new_decl) = info->debug_var_chain;
info->debug_var_chain = new_decl;
walk_tree (tp, convert_nonlocal_reference, wi, NULL);
break;
+ case VIEW_CONVERT_EXPR:
+ /* Just request to look at the subtrees, leaving val_only and lhs
+ untouched. This might actually be for !val_only + lhs, in which
+ case we don't want to force a replacement by a temporary. */
+ *walk_subtrees = 1;
+ break;
+
case OMP_PARALLEL:
save_suppress = info->suppress_expansion;
if (convert_nonlocal_omp_clauses (&OMP_PARALLEL_CLAUSES (t), wi))
break;
case OMP_FOR:
+ save_suppress = info->suppress_expansion;
+ convert_nonlocal_omp_clauses (&OMP_FOR_CLAUSES (t), wi);
+ walk_omp_for (convert_nonlocal_reference, info, t);
+ walk_body (convert_nonlocal_reference, info, &OMP_FOR_BODY (t));
+ info->suppress_expansion = save_suppress;
+ break;
+
case OMP_SECTIONS:
case OMP_SINGLE:
save_suppress = info->suppress_expansion;
static tree
get_local_debug_decl (struct nesting_info *info, tree decl, tree field)
{
- struct var_map_elt *elt, dummy;
tree x, new_decl;
void **slot;
- dummy.old = decl;
- slot = htab_find_slot (info->var_map, &dummy, INSERT);
- elt = *slot;
-
- if (elt)
- return elt->new;
+ slot = pointer_map_insert (info->var_map, decl);
+ if (*slot)
+ return *slot;
/* Make sure frame_decl gets created. */
(void) get_frame_type (info);
SET_DECL_VALUE_EXPR (new_decl, x);
DECL_HAS_VALUE_EXPR_P (new_decl) = 1;
-
- elt = ggc_alloc (sizeof (*elt));
- elt->old = decl;
- elt->new = new_decl;
- *slot = elt;
+ *slot = new_decl;
TREE_CHAIN (new_decl) = info->debug_var_chain;
info->debug_var_chain = new_decl;
wi->val_only = save_val_only;
break;
+ case VIEW_CONVERT_EXPR:
+ /* Just request to look at the subtrees, leaving val_only and lhs
+ untouched. This might actually be for !val_only + lhs, in which
+ case we don't want to force a replacement by a temporary. */
+ *walk_subtrees = 1;
+ break;
+
case OMP_PARALLEL:
save_suppress = info->suppress_expansion;
if (convert_local_omp_clauses (&OMP_PARALLEL_CLAUSES (t), wi))
break;
case OMP_FOR:
+ save_suppress = info->suppress_expansion;
+ convert_local_omp_clauses (&OMP_FOR_CLAUSES (t), wi);
+ walk_omp_for (convert_local_reference, info, t);
+ walk_body (convert_local_reference, info, &OMP_FOR_BODY (t));
+ info->suppress_expansion = save_suppress;
+ break;
+
case OMP_SECTIONS:
case OMP_SINGLE:
save_suppress = info->suppress_expansion;
{
struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
struct nesting_info *info = wi->info, *i;
- tree t = *tp, label, new_label, target_context, x, arg, field;
- struct var_map_elt *elt, dummy;
+ tree t = *tp, label, new_label, target_context, x, field;
void **slot;
*walk_subtrees = 0;
(hairy target-specific) non-local goto receiver code to be generated
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 = (struct var_map_elt *) *slot;
- if (elt == NULL)
+ slot = pointer_map_insert (i->var_map, label);
+ if (*slot == NULL)
{
new_label = create_artificial_label ();
DECL_NONLOCAL (new_label) = 1;
-
- elt = GGC_NEW (struct var_map_elt);
- elt->old = label;
- elt->new = new_label;
- *slot = elt;
+ *slot = new_label;
}
else
- new_label = elt->new;
+ new_label = *slot;
/* Build: __builtin_nl_goto(new_label, &chain->nl_goto_field). */
field = get_nl_goto_field (i);
x = get_frame_field (info, target_context, field, &wi->tsi);
x = build_addr (x, target_context);
x = tsi_gimplify_val (info, x, &wi->tsi);
- arg = tree_cons (NULL, x, NULL);
- x = build_addr (new_label, target_context);
- arg = tree_cons (NULL, x, arg);
- x = implicit_built_in_decls[BUILT_IN_NONLOCAL_GOTO];
- x = build_function_call_expr (x, arg);
+ x = build_call_expr (implicit_built_in_decls[BUILT_IN_NONLOCAL_GOTO], 2,
+ build_addr (new_label, target_context), x);
SET_EXPR_LOCUS (x, EXPR_LOCUS (tsi_stmt (wi->tsi)));
*tsi_stmt_ptr (wi->tsi) = x;
struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
struct nesting_info *info = wi->info;
tree t = *tp, label, new_label, x;
- struct var_map_elt *elt, dummy;
tree_stmt_iterator tmp_tsi;
+ void **slot;
*walk_subtrees = 0;
if (TREE_CODE (t) != LABEL_EXPR)
return NULL_TREE;
label = LABEL_EXPR_LABEL (t);
- dummy.old = label;
- elt = (struct var_map_elt *) htab_find (info->var_map, &dummy);
- if (!elt)
+ slot = pointer_map_contains (info->var_map, label);
+ if (!slot)
return NULL_TREE;
- new_label = elt->new;
/* If there's any possibility that the previous statement falls through,
then we must branch around the new non-local label. */
x = build1 (GOTO_EXPR, void_type_node, label);
tsi_link_before (&wi->tsi, x, TSI_SAME_STMT);
}
+
+ new_label = (tree) *slot;
x = build1 (LABEL_EXPR, void_type_node, new_label);
tsi_link_before (&wi->tsi, x, TSI_SAME_STMT);
{
struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
struct nesting_info *info = wi->info, *i;
- tree t = *tp, decl, target_context, x, arg;
+ tree t = *tp, decl, target_context, x;
*walk_subtrees = 0;
switch (TREE_CODE (t))
x = get_frame_field (info, target_context, x, &wi->tsi);
x = build_addr (x, target_context);
x = tsi_gimplify_val (info, x, &wi->tsi);
- arg = tree_cons (NULL, x, NULL);
/* Do machine-specific ugliness. Normally this will involve
computing extra alignment, but it can really be anything. */
- x = implicit_built_in_decls[BUILT_IN_ADJUST_TRAMPOLINE];
- x = build_function_call_expr (x, arg);
+ x = build_call_expr (implicit_built_in_decls[BUILT_IN_ADJUST_TRAMPOLINE],
+ 1, x);
x = init_tmp_var (info, x, &wi->tsi);
/* Cast back to the proper function type. */
case CALL_EXPR:
/* Only walk call arguments, lest we generate trampolines for
direct calls. */
- walk_tree (&TREE_OPERAND (t, 1), convert_tramp_reference, wi, NULL);
+ {
+ int nargs = call_expr_nargs (t);
+ int i;
+ for (i = 0; i < nargs; i++)
+ walk_tree (&CALL_EXPR_ARG (t, i), convert_tramp_reference, wi, NULL);
+ }
break;
default:
struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
struct nesting_info *info = wi->info;
tree t = *tp, decl, target_context;
+ char save_static_chain_added;
+ int i;
*walk_subtrees = 0;
switch (TREE_CODE (t))
break;
target_context = decl_function_context (decl);
if (target_context && !DECL_NO_STATIC_CHAIN (decl))
- TREE_OPERAND (t, 2)
- = get_static_chain (info, target_context, &wi->tsi);
+ {
+ CALL_EXPR_STATIC_CHAIN (t)
+ = get_static_chain (info, target_context, &wi->tsi);
+ info->static_chain_added
+ |= (1 << (info->context != target_context));
+ }
break;
case RETURN_EXPR:
- case MODIFY_EXPR:
+ case GIMPLE_MODIFY_STMT:
case WITH_SIZE_EXPR:
/* Only return modify and with_size_expr may contain calls. */
*walk_subtrees = 1;
break;
+ case OMP_PARALLEL:
+ save_static_chain_added = info->static_chain_added;
+ info->static_chain_added = 0;
+ walk_body (convert_call_expr, info, &OMP_PARALLEL_BODY (t));
+ for (i = 0; i < 2; i++)
+ {
+ tree c, decl;
+ if ((info->static_chain_added & (1 << i)) == 0)
+ continue;
+ decl = i ? get_chain_decl (info) : info->frame_decl;
+ /* Don't add CHAIN.* or FRAME.* twice. */
+ for (c = OMP_PARALLEL_CLAUSES (t); c; c = OMP_CLAUSE_CHAIN (c))
+ if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE
+ || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_SHARED)
+ && OMP_CLAUSE_DECL (c) == decl)
+ break;
+ if (c == NULL)
+ {
+ c = build_omp_clause (i ? OMP_CLAUSE_FIRSTPRIVATE
+ : OMP_CLAUSE_SHARED);
+ OMP_CLAUSE_DECL (c) = decl;
+ OMP_CLAUSE_CHAIN (c) = OMP_PARALLEL_CLAUSES (t);
+ OMP_PARALLEL_CLAUSES (t) = c;
+ }
+ }
+ info->static_chain_added |= save_static_chain_added;
+ break;
+
case OMP_FOR:
+ walk_body (convert_call_expr, info, &OMP_FOR_PRE_BODY (t));
+ /* FALLTHRU */
case OMP_SECTIONS:
+ case OMP_SECTION:
case OMP_SINGLE:
case OMP_MASTER:
case OMP_ORDERED:
y = build3 (COMPONENT_REF, TREE_TYPE (field),
root->frame_decl, field, NULL_TREE);
- x = build2 (MODIFY_EXPR, TREE_TYPE (field), y, x);
+ x = build_gimple_modify_stmt (y, x);
append_to_statement_list (x, &stmt_list);
}
}
{
tree x = build3 (COMPONENT_REF, TREE_TYPE (root->chain_field),
root->frame_decl, root->chain_field, NULL_TREE);
- x = build2 (MODIFY_EXPR, TREE_TYPE (x), x, get_chain_decl (root));
+ x = build_gimple_modify_stmt (x, get_chain_decl (root));
append_to_statement_list (x, &stmt_list);
}
struct nesting_info *i;
for (i = root->inner; i ; i = i->next)
{
- tree arg, x, field;
+ tree arg1, arg2, arg3, x, field;
field = lookup_tramp_for_decl (root, i->context, NO_INSERT);
if (!field)
continue;
if (DECL_NO_STATIC_CHAIN (i->context))
- x = null_pointer_node;
+ arg3 = null_pointer_node;
else
- x = build_addr (root->frame_decl, context);
- arg = tree_cons (NULL, x, NULL);
+ arg3 = build_addr (root->frame_decl, context);
- x = build_addr (i->context, context);
- arg = tree_cons (NULL, x, arg);
+ arg2 = build_addr (i->context, context);
x = build3 (COMPONENT_REF, TREE_TYPE (field),
root->frame_decl, field, NULL_TREE);
- x = build_addr (x, context);
- arg = tree_cons (NULL, x, arg);
+ arg1 = build_addr (x, context);
x = implicit_built_in_decls[BUILT_IN_INIT_TRAMPOLINE];
- x = build_function_call_expr (x, arg);
-
+ x = build_call_expr (x, 3, arg1, arg2, arg3);
append_to_statement_list (x, &stmt_list);
}
}
{
if (root->inner)
free_nesting_tree (root->inner);
- htab_delete (root->var_map);
+ pointer_map_destroy (root->var_map);
+ pointer_map_destroy (root->field_map);
next = root->next;
- ggc_free (root);
+ 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. */
lower_nested_functions (tree fndecl)
{
struct cgraph_node *cgn;
+ struct nesting_info *root;
/* If there are no nested functions, there's nothing to do. */
cgn = cgraph_node (fndecl);
if (!cgn->nested)
return;
+ bitmap_obstack_initialize (&nesting_info_bitmap_obstack);
root = create_nesting_tree (cgn);
walk_all_functions (convert_nonlocal_reference, root);
walk_all_functions (convert_local_reference, root);
finalize_nesting_tree (root);
unnest_nesting_tree (root);
free_nesting_tree (root);
- root = NULL;
+ bitmap_obstack_release (&nesting_info_bitmap_obstack);
}
#include "gt-tree-nested.h"