X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=gcc%2Ftree-nested.c;h=7f60faa646b09535415418ddd7236c8cea2e818e;hp=e884260d2b3951c52bb66f9c7df7e45d34fa92b1;hb=40b19772a73e5f6a97472cfc8d818f880db20dfb;hpb=83e2a11b2613ddd8dfc024700b1c86729b058300 diff --git a/gcc/tree-nested.c b/gcc/tree-nested.c index e884260d2b3..7f60faa646b 100644 --- a/gcc/tree-nested.c +++ b/gcc/tree-nested.c @@ -1,5 +1,5 @@ /* Nested function decomposition for trees. - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2005 Free Software Foundation, Inc. This file is part of GCC. @@ -15,8 +15,8 @@ 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. */ + the Free Software Foundation, 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ #include "config.h" #include "system.h" @@ -55,7 +55,7 @@ The implementation here is much more direct. Everything that can be referenced by an inner function is a member of an explicitly created - structure herein called the "nonlocal frame struct". The incomming + structure herein called the "nonlocal frame struct". The incoming static chain for a nested function is a pointer to this struct in the parent. In this way, we settle on known offsets from a known base, and so are decoupled from the logic that places objects in the @@ -77,19 +77,19 @@ 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; @@ -132,15 +132,12 @@ create_tmp_var_for (struct nesting_info *info, tree type, const char *prefix) { tree tmp_var; -#if defined ENABLE_CHECKING /* If the type is of variable size or a type which must be created by the frontend, something is wrong. Note that we explicitly allow incomplete types here, since we create them ourselves here. */ - if (TREE_ADDRESSABLE (type) - || (TYPE_SIZE_UNIT (type) - && TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST)) - abort (); -#endif + gcc_assert (!TREE_ADDRESSABLE (type)); + gcc_assert (!TYPE_SIZE_UNIT (type) + || TREE_CODE (TYPE_SIZE_UNIT (type)) == INTEGER_CST); tmp_var = create_tmp_var_raw (type, prefix); DECL_CONTEXT (tmp_var) = info->context; @@ -151,21 +148,34 @@ create_tmp_var_for (struct nesting_info *info, tree type, const char *prefix) return tmp_var; } -/* Take the address of EXP. Mark it for addressability as necessary. */ +/* Take the address of EXP to be used within function CONTEXT. + Mark it for addressability as necessary. */ -static tree -build_addr (tree exp) +tree +build_addr (tree exp, tree context) { tree base = exp; + tree save_context; + tree retval; - while (TREE_CODE (base) == REALPART_EXPR || TREE_CODE (base) == IMAGPART_EXPR - || handled_component_p (base)) + while (handled_component_p (base)) base = TREE_OPERAND (base, 0); if (DECL_P (base)) TREE_ADDRESSABLE (base) = 1; - return build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (exp)), exp); + /* Building the ADDR_EXPR will compute a set of properties for + that ADDR_EXPR. Those properties are unfortunately context + specific. ie, they are dependent on CURRENT_FUNCTION_DECL. + + Temporarily set CURRENT_FUNCTION_DECL to the desired context, + build the ADDR_EXPR, then restore CURRENT_FUNCTION_DECL. That + way the properties are for the ADDR_EXPR are computed properly. */ + 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;; + return retval; } /* Insert FIELD into TYPE, sorted by alignment requirements. */ @@ -210,6 +220,14 @@ get_frame_type (struct nesting_info *info) 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; } @@ -249,8 +267,7 @@ lookup_field_for_decl (struct nesting_info *info, tree decl, slot = htab_find_slot (info->var_map, &dummy, insert); if (!slot) { - if (insert == INSERT) - abort (); + gcc_assert (insert != INSERT); return NULL; } elt = *slot; @@ -279,7 +296,7 @@ lookup_field_for_decl (struct nesting_info *info, tree decl, 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; @@ -363,7 +380,7 @@ init_tmp_var (struct nesting_info *info, tree exp, tree_stmt_iterator *tsi) tree t, stmt; t = create_tmp_var_for (info, TREE_TYPE (exp), NULL); - stmt = build (MODIFY_EXPR, TREE_TYPE (t), t, exp); + stmt = build2 (MODIFY_EXPR, TREE_TYPE (t), t, exp); SET_EXPR_LOCUS (stmt, EXPR_LOCUS (tsi_stmt (*tsi))); tsi_link_before (tsi, stmt, TSI_SAME_STMT); @@ -381,6 +398,23 @@ tsi_gimplify_val (struct nesting_info *info, tree exp, tree_stmt_iterator *tsi) return init_tmp_var (info, exp, tsi); } +/* Similarly, but copy from the temporary and insert the statement + after the iterator. */ + +static tree +save_tmp_var (struct nesting_info *info, tree exp, + tree_stmt_iterator *tsi) +{ + tree t, stmt; + + t = create_tmp_var_for (info, TREE_TYPE (exp), NULL); + stmt = build2 (MODIFY_EXPR, TREE_TYPE (t), exp, t); + SET_EXPR_LOCUS (stmt, EXPR_LOCUS (tsi_stmt (*tsi))); + tsi_link_after (tsi, stmt, TSI_SAME_STMT); + + return t; +} + /* Build or return the type used to represent a nested function trampoline. */ static GTY(()) tree trampoline_type; @@ -405,7 +439,7 @@ get_trampoline_type (void) align = STACK_BOUNDARY; } - t = build_index_type (build_int_2 (size - 1, 0)); + t = build_index_type (build_int_cst (NULL_TREE, size - 1)); t = build_array_type (char_type_node, t); t = build_decl (FIELD_DECL, get_identifier ("__data"), t); DECL_ALIGN (t) = align; @@ -434,8 +468,7 @@ lookup_tramp_for_decl (struct nesting_info *info, tree decl, slot = htab_find_slot (info->var_map, &dummy, insert); if (!slot) { - if (insert == INSERT) - abort (); + gcc_assert (insert != INSERT); return NULL; } elt = *slot; @@ -449,7 +482,7 @@ lookup_tramp_for_decl (struct nesting_info *info, tree decl, 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; @@ -488,7 +521,8 @@ get_nl_goto_field (struct nesting_info *info) size = size / GET_MODE_SIZE (Pmode); size = size + 1; - type = build_array_type (type, build_index_type (build_int_2 (size, 0))); + type = build_array_type + (type, build_index_type (build_int_cst (NULL_TREE, size))); field = make_node (FIELD_DECL); DECL_NAME (field) = get_identifier ("__nl_goto_buf"); @@ -522,6 +556,8 @@ struct walk_stmt_info tree_stmt_iterator tsi; struct nesting_info *info; bool val_only; + bool is_lhs; + bool changed; }; /* A subroutine of walk_function. Iterate over all sub-statements of *TP. */ @@ -571,12 +607,18 @@ walk_stmts (struct walk_stmt_info *wi, tree *tp) break; case MODIFY_EXPR: - /* The immediate arguments of a MODIFY_EXPR may use COMPONENT_REF. */ - wi->val_only = false; - walk_tree (&TREE_OPERAND (t, 0), wi->callback, wi, NULL); - wi->val_only = false; + /* 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); + + /* 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->is_lhs = true; + walk_tree (&TREE_OPERAND (t, 0), wi->callback, wi, NULL); + wi->val_only = true; + wi->is_lhs = false; break; default: @@ -615,16 +657,57 @@ walk_all_functions (walk_tree_fn callback, struct nesting_info *root) } while (root); } - +/* We have to check for a fairly pathological case. The operands of function + nested function are to be interpreted in the context of the enclosing + function. So if any are variably-sized, they will get remapped when the + enclosing function is inlined. But that remapping would also have to be + done in the types of the PARM_DECLs of the nested function, meaning the + argument types of that function will disagree with the arguments in the + calls to that function. So we'd either have to make a copy of the nested + function corresponding to each time the enclosing function was inlined or + add a VIEW_CONVERT_EXPR to each such operand for each call to the nested + function. The former is not practical. The latter would still require + detecting this case to know when to add the conversions. So, for now at + least, we don't inline such an enclosing function. + + We have to do that check recursively, so here return indicating whether + FNDECL has such a nested function. ORIG_FN is the function we were + trying to inline to use for checking whether any argument is variably + modified by anything in it. + + It would be better to do this in tree-inline.c so that we could give + the appropriate warning for why a function can't be inlined, but that's + too late since the nesting structure has already been flattened and + adding a flag just to record this fact seems a waste of a flag. */ + +static bool +check_for_nested_with_variably_modified (tree fndecl, tree orig_fndecl) +{ + struct cgraph_node *cgn = cgraph_node (fndecl); + tree arg; + + for (cgn = cgn->nested; cgn ; cgn = cgn->next_nested) + { + for (arg = DECL_ARGUMENTS (cgn->decl); arg; arg = TREE_CHAIN (arg)) + if (variably_modified_type_p (TREE_TYPE (arg), 0), orig_fndecl) + return true; + + if (check_for_nested_with_variably_modified (cgn->decl, orig_fndecl)) + return true; + } + + return false; +} + /* Construct our local datastructure describing the function nesting tree rooted by CGN. */ 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) @@ -635,6 +718,11 @@ create_nesting_tree (struct cgraph_node *cgn) info->inner = sub; } + /* See discussion at check_for_nested_with_variably_modified for a + discussion of why this has to be here. */ + if (check_for_nested_with_variably_modified (info->context, info->context)) + DECL_UNINLINABLE (info->context) = true; + return info; } @@ -650,7 +738,7 @@ get_static_chain (struct nesting_info *info, tree target_context, if (info->context == target_context) { - x = build_addr (info->frame_decl); + x = build_addr (info->frame_decl, target_context); } else { @@ -661,7 +749,7 @@ get_static_chain (struct nesting_info *info, tree target_context, tree field = get_chain_field (i); x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x); - x = build (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE); + x = build3 (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE); x = init_tmp_var (info, x, tsi); } } @@ -695,14 +783,14 @@ get_frame_field (struct nesting_info *info, tree target_context, tree field = get_chain_field (i); x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x); - x = build (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE); + x = build3 (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE); x = init_tmp_var (info, x, tsi); } x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x); } - x = build (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE); + x = build3 (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE); return x; } @@ -736,6 +824,7 @@ convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data) tree target_context = decl_function_context (t); struct nesting_info *i; tree x; + wi->changed = true; for (i = info->outer; i->context != target_context; i = i->outer) continue; @@ -746,8 +835,14 @@ convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data) x = init_tmp_var (info, x, &wi->tsi); x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x); } + if (wi->val_only) - x = init_tmp_var (info, x, &wi->tsi); + { + if (wi->is_lhs) + x = save_tmp_var (info, x, &wi->tsi); + else + x = init_tmp_var (info, x, &wi->tsi); + } *tp = x; } @@ -759,6 +854,7 @@ convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data) { *walk_subtrees = 1; wi->val_only = true; + wi->is_lhs = false; } break; @@ -774,17 +870,23 @@ convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data) case ADDR_EXPR: { bool save_val_only = wi->val_only; - tree save_sub = TREE_OPERAND (t, 0); wi->val_only = false; + wi->is_lhs = false; + wi->changed = false; walk_tree (&TREE_OPERAND (t, 0), convert_nonlocal_reference, wi, NULL); wi->val_only = true; - if (save_sub != TREE_OPERAND (t, 0)) + if (wi->changed) { + tree save_context; + /* If we changed anything, then TREE_INVARIANT is be wrong, since we're no longer directly referencing a decl. */ - TREE_INVARIANT (t) = 0; + save_context = current_function_decl; + current_function_decl = info->context; + recompute_tree_invarant_for_addr_expr (t); + current_function_decl = save_context; /* If the callback converted the address argument in a context where we only accept variables (and min_invariant, presumably), @@ -805,9 +907,8 @@ convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data) anything that describes the references. Otherwise, we lose track of whether a NOP_EXPR or VIEW_CONVERT_EXPR needs a simple value. */ wi->val_only = true; - for (; handled_component_p (t) - || TREE_CODE (t) == REALPART_EXPR || TREE_CODE (t) == IMAGPART_EXPR; - tp = &TREE_OPERAND (t, 0), t = *tp) + wi->is_lhs = false; + for (; handled_component_p (t); tp = &TREE_OPERAND (t, 0), t = *tp) { if (TREE_CODE (t) == COMPONENT_REF) walk_tree (&TREE_OPERAND (t, 2), convert_nonlocal_reference, wi, @@ -835,10 +936,11 @@ convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data) break; default: - if (!DECL_P (t) && !TYPE_P (t)) + if (!IS_TYPE_OR_DECL_P (t)) { *walk_subtrees = 1; wi->val_only = true; + wi->is_lhs = false; } break; } @@ -855,8 +957,10 @@ convert_local_reference (tree *tp, int *walk_subtrees, void *data) { struct walk_stmt_info *wi = data; struct nesting_info *info = wi->info; - tree t = *tp, field, x, y; + tree t = *tp, field, x; + bool save_val_only; + *walk_subtrees = 0; switch (TREE_CODE (t)) { case VAR_DECL: @@ -878,69 +982,48 @@ convert_local_reference (tree *tp, int *walk_subtrees, void *data) field = lookup_field_for_decl (info, t, NO_INSERT); if (!field) break; + wi->changed = true; x = get_frame_field (info, info->context, field, &wi->tsi); + if (wi->val_only) - x = init_tmp_var (info, x, &wi->tsi); + { + if (wi->is_lhs) + x = save_tmp_var (info, x, &wi->tsi); + else + x = init_tmp_var (info, x, &wi->tsi); + } + *tp = x; } break; case ADDR_EXPR: - { - bool save_val_only = wi->val_only; - tree save_sub = TREE_OPERAND (t, 0); - - wi->val_only = false; - walk_tree (&TREE_OPERAND (t, 0), convert_local_reference, wi, NULL); - wi->val_only = save_val_only; - - /* If we converted anything ... */ - if (TREE_OPERAND (t, 0) != save_sub) - { - /* Then the frame decl is now addressable. */ - TREE_ADDRESSABLE (info->frame_decl) = 1; - - /* 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 CALL_EXPR: - *walk_subtrees = 1; - - /* Ready for some fun? We need to recognize - __builtin_stack_alloc (&x, n) - and insert - FRAME.x = &x - after that. X should have use_pointer_in_frame set. We can't - do this any earlier, since we can't meaningfully evaluate &x. */ + 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; - x = get_callee_fndecl (t); - if (!x || DECL_BUILT_IN_CLASS (x) != BUILT_IN_NORMAL) - break; - if (DECL_FUNCTION_CODE (x) != BUILT_IN_STACK_ALLOC) - break; - t = TREE_VALUE (TREE_OPERAND (t, 1)); - if (TREE_CODE (t) != ADDR_EXPR) - abort (); - t = TREE_OPERAND (t, 0); - if (TREE_CODE (t) != VAR_DECL) - abort (); - field = lookup_field_for_decl (info, t, NO_INSERT); - if (!field) - break; - if (!use_pointer_in_frame (t)) - abort (); - - x = build_addr (t); - y = get_frame_field (info, info->context, field, &wi->tsi); - x = build (MODIFY_EXPR, void_type_node, y, x); - SET_EXPR_LOCUS (x, EXPR_LOCUS (tsi_stmt (wi->tsi))); - tsi_link_after (&wi->tsi, x, TSI_SAME_STMT); + /* If we converted anything ... */ + if (wi->changed) + { + tree save_context; + + /* 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); + } break; case REALPART_EXPR: @@ -952,10 +1035,10 @@ convert_local_reference (tree *tp, int *walk_subtrees, void *data) /* 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; - for (; handled_component_p (t) - || TREE_CODE (t) == REALPART_EXPR || TREE_CODE (t) == IMAGPART_EXPR; - tp = &TREE_OPERAND (t, 0), t = *tp) + wi->is_lhs = false; + for (; handled_component_p (t); tp = &TREE_OPERAND (t, 0), t = *tp) { if (TREE_CODE (t) == COMPONENT_REF) walk_tree (&TREE_OPERAND (t, 2), convert_local_reference, wi, @@ -980,13 +1063,15 @@ convert_local_reference (tree *tp, int *walk_subtrees, void *data) } wi->val_only = false; walk_tree (tp, convert_local_reference, wi, NULL); + wi->val_only = save_val_only; break; default: - if (!DECL_P (t) && !TYPE_P (t)) + if (!IS_TYPE_OR_DECL_P (t)) { *walk_subtrees = 1; wi->val_only = true; + wi->is_lhs = false; } break; } @@ -1004,7 +1089,7 @@ convert_nl_goto_reference (tree *tp, int *walk_subtrees, void *data) 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; @@ -1025,25 +1110,31 @@ convert_nl_goto_reference (tree *tp, int *walk_subtrees, void *data) 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); x = get_frame_field (info, target_context, field, &wi->tsi); - x = build_addr (x); + 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); + 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); @@ -1138,7 +1229,7 @@ convert_tramp_reference (tree *tp, int *walk_subtrees, void *data) /* Compute the address of the field holding the trampoline. */ x = get_frame_field (info, target_context, x, &wi->tsi); - x = build_addr (x); + x = build_addr (x, target_context); x = tsi_gimplify_val (info, x, &wi->tsi); arg = tree_cons (NULL, x, NULL); @@ -1162,7 +1253,7 @@ convert_tramp_reference (tree *tp, int *walk_subtrees, void *data) break; default: - if (!DECL_P (t) && !TYPE_P (t)) + if (!IS_TYPE_OR_DECL_P (t)) *walk_subtrees = 1; break; } @@ -1227,12 +1318,7 @@ convert_all_function_calls (struct nesting_info *root) if (root->outer && !root->chain_decl && !root->chain_field) DECL_NO_STATIC_CHAIN (root->context) = 1; else - { -#ifdef ENABLE_CHECKING - if (DECL_NO_STATIC_CHAIN (root->context)) - abort (); -#endif - } + gcc_assert (!DECL_NO_STATIC_CHAIN (root->context)); root = root->next; } @@ -1250,12 +1336,18 @@ finalize_nesting_tree_1 (struct nesting_info *root) tree stmt_list = NULL; tree context = root->context; struct function *sf; + struct cgraph_node *node; /* If we created a non-local frame type or decl, we need to lay them out at this time. */ if (root->frame_type) { + /* In some cases the frame type will trigger the -Wpadded warning. + This is not helpful; suppress it. */ + int save_warn_padded = warn_padded; + warn_padded = 0; layout_type (root->frame_type); + warn_padded = save_warn_padded; layout_decl (root->frame_decl, 0); } @@ -1274,13 +1366,13 @@ finalize_nesting_tree_1 (struct nesting_info *root) continue; if (use_pointer_in_frame (p)) - x = build_addr (p); + x = build_addr (p, context); else x = p; - y = build (COMPONENT_REF, TREE_TYPE (field), - root->frame_decl, field, NULL_TREE); - x = build (MODIFY_EXPR, TREE_TYPE (field), y, x); + y = build3 (COMPONENT_REF, TREE_TYPE (field), + root->frame_decl, field, NULL_TREE); + x = build2 (MODIFY_EXPR, TREE_TYPE (field), y, x); append_to_statement_list (x, &stmt_list); } } @@ -1289,9 +1381,9 @@ finalize_nesting_tree_1 (struct nesting_info *root) from chain_decl. */ if (root->chain_field) { - tree x = build (COMPONENT_REF, TREE_TYPE (root->chain_field), - root->frame_decl, root->chain_field, NULL_TREE); - x = build (MODIFY_EXPR, TREE_TYPE (x), x, get_chain_decl (root)); + 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)); append_to_statement_list (x, &stmt_list); } @@ -1310,15 +1402,15 @@ finalize_nesting_tree_1 (struct nesting_info *root) if (DECL_NO_STATIC_CHAIN (i->context)) x = null_pointer_node; else - x = build_addr (root->frame_decl); + x = build_addr (root->frame_decl, context); arg = tree_cons (NULL, x, NULL); - x = build_addr (i->context); + x = build_addr (i->context, context); arg = tree_cons (NULL, x, arg); - x = build (COMPONENT_REF, TREE_TYPE (field), - root->frame_decl, field, NULL_TREE); - x = build_addr (x); + x = build3 (COMPONENT_REF, TREE_TYPE (field), + root->frame_decl, field, NULL_TREE); + x = build_addr (x, context); arg = tree_cons (NULL, x, arg); x = implicit_built_in_decls[BUILT_IN_INIT_TRAMPOLINE]; @@ -1360,6 +1452,15 @@ finalize_nesting_tree_1 (struct nesting_info *root) /* Dump the translated tree function. */ dump_function (TDI_nested, root->context); + node = cgraph_node (root->context); + + /* For nested functions update the cgraph to reflect unnesting. + We also delay finalizing of these functions up to this point. */ + if (node->origin) + { + cgraph_unnest_node (cgraph_node (root->context)); + cgraph_finalize_function (root->context, true); + } } static void @@ -1387,19 +1488,20 @@ free_nesting_tree (struct nesting_info *root) 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. */ @@ -1415,6 +1517,7 @@ lower_nested_functions (tree fndecl) convert_all_function_calls (root); finalize_nesting_tree (root); free_nesting_tree (root); + root = NULL; } #include "gt-tree-nested.h"