diff options
author | rth <rth@138bc75d-0d04-0410-961f-82ee72b054a4> | 2009-09-16 16:26:55 +0000 |
---|---|---|
committer | rth <rth@138bc75d-0d04-0410-961f-82ee72b054a4> | 2009-09-16 16:26:55 +0000 |
commit | cfcaff92bf436affb2e7990cee9d754f96295f51 (patch) | |
tree | 9c8b5d51425dfcd062aa4b34755ad43e82f11eb8 /gcc/tree-nested.c | |
parent | 8bb76364adb500f539b7bbd329b83e4602bf839b (diff) | |
download | gcc-cfcaff92bf436affb2e7990cee9d754f96295f51.tar.gz |
PR target/41246
* tree-cfg.c (verify_gimple_call): Validate that
* gimple_call_chain
is set only if DECL_NO_STATIC_CHAIN is unset.
* tree-nested.c (iter_nestinfo_start, iter_nestinfo_next): New.
(FOR_EACH_NEST_INFO): New.
(walk_all_functions): Use it.
(finalize_nesting_tree): Likewise.
(unnest_nesting_tree): Likewise.
(free_nesting_tree): Use iter_nestinfo_start, iter_nestinfo_next.
(get_chain_decl, get_chain_field): Reset DECL_NO_STATIC_CHAIN.
(convert_gimple_call): Early out if gimple_call_chain already set.
(convert_all_function_calls): Iterate until no new functions
require a static chain.
(finalize_nesting_tree_1): Assert DECL_NO_STATIC_CHAIN is unset
when building a trampoline. Use dump_function_to_file instead
of dump_function.
(lower_nested_functions): Open dump_file. Validate that decls
that have DECL_NO_STATIC_CHAIN from the front end don't have that
bit reset by this pass.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@151762 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/tree-nested.c')
-rw-r--r-- | gcc/tree-nested.c | 212 |
1 files changed, 157 insertions, 55 deletions
diff --git a/gcc/tree-nested.c b/gcc/tree-nested.c index 7c55c8adc23..bcf971143cf 100644 --- a/gcc/tree-nested.c +++ b/gcc/tree-nested.c @@ -1,5 +1,6 @@ /* Nested function decomposition for GIMPLE. - Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 + Free Software Foundation, Inc. This file is part of GCC. @@ -102,6 +103,27 @@ struct nesting_info }; +/* Iterate over the nesting tree, starting with ROOT, depth first. */ + +static inline struct nesting_info * +iter_nestinfo_start (struct nesting_info *root) +{ + while (root->inner) + root = root->inner; + return root; +} + +static inline struct nesting_info * +iter_nestinfo_next (struct nesting_info *node) +{ + if (node->next) + return iter_nestinfo_start (node->next); + return node->outer; +} + +#define FOR_EACH_NEST_INFO(I, ROOT) \ + for ((I) = iter_nestinfo_start (ROOT); (I); (I) = iter_nestinfo_next (I)) + /* Obstack used for the bitmaps in the struct above. */ static struct bitmap_obstack nesting_info_bitmap_obstack; @@ -301,6 +323,7 @@ static tree get_chain_decl (struct nesting_info *info) { tree decl = info->chain_decl; + if (!decl) { tree type; @@ -327,6 +350,14 @@ get_chain_decl (struct nesting_info *info) TREE_READONLY (decl) = 1; info->chain_decl = decl; + + if (dump_file + && (dump_flags & TDF_DETAILS) + && DECL_NO_STATIC_CHAIN (info->context)) + fprintf (dump_file, "Resetting no-static-chain for %s\n", + lang_hooks.decl_printable_name (info->context, 2)); + + DECL_NO_STATIC_CHAIN (info->context) = 0; } return decl; } @@ -339,6 +370,7 @@ static tree get_chain_field (struct nesting_info *info) { tree field = info->chain_field; + if (!field) { tree type = build_pointer_type (get_frame_type (info->outer)); @@ -352,6 +384,14 @@ get_chain_field (struct nesting_info *info) insert_field_into_struct (get_frame_type (info), field); info->chain_field = field; + + if (dump_file + && (dump_flags & TDF_DETAILS) + && DECL_NO_STATIC_CHAIN (info->context)) + fprintf (dump_file, "Resetting no-static-chain for %s\n", + lang_hooks.decl_printable_name (info->context, 2)); + + DECL_NO_STATIC_CHAIN (info->context) = 0; } return field; } @@ -622,14 +662,9 @@ static void walk_all_functions (walk_stmt_fn callback_stmt, walk_tree_fn callback_op, struct nesting_info *root) { - do - { - if (root->inner) - walk_all_functions (callback_stmt, callback_op, root->inner); - walk_function (callback_stmt, callback_op, root); - root = root->next; - } - while (root); + struct nesting_info *n; + FOR_EACH_NEST_INFO (n, root) + walk_function (callback_stmt, callback_op, n); } @@ -1931,6 +1966,8 @@ convert_gimple_call (gimple_stmt_iterator *gsi, bool *handled_ops_p, switch (gimple_code (stmt)) { case GIMPLE_CALL: + if (gimple_call_chain (stmt)) + break; decl = gimple_call_fndecl (stmt); if (!decl) break; @@ -1998,32 +2035,71 @@ convert_gimple_call (gimple_stmt_iterator *gsi, bool *handled_ops_p, return NULL_TREE; } - -/* Walk the nesting tree starting with ROOT, depth first. Convert all - trampolines and call expressions. On the way back up, determine if - a nested function actually uses its static chain; if not, remember that. */ +/* Walk the nesting tree starting with ROOT. Convert all trampolines and + call expressions. At the same time, determine if a nested function + actually uses its static chain; if not, remember that. */ static void convert_all_function_calls (struct nesting_info *root) { + struct nesting_info *n; + int iter_count; + bool any_changed; + + /* First, optimistically set no_static_chain for all decls that haven't + used the static chain already for variable access. Notice that we + do this pre-order, because we want inner functions to be processed + first in the LIFO worklist. */ + FOR_EACH_NEST_INFO (n, root) + { + tree decl = n->context; + if (n->outer && !n->chain_decl && !n->chain_field) + { + DECL_NO_STATIC_CHAIN (decl) = 1; + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, "Guessing no-static-chain for %s\n", + lang_hooks.decl_printable_name (decl, 2)); + } + else + gcc_assert (!DECL_NO_STATIC_CHAIN (decl)); + } + + /* Walk the functions and perform transformations. Note that these + transformations can induce new uses of the static chain, which in turn + require re-examining all users of the decl. */ + /* ??? It would make sense to try to use the call graph to speed this up, + but the call graph hasn't really been built yet. Even if it did, we + would still need to iterate in this loop since address-of references + wouldn't show up in the callgraph anyway. */ + iter_count = 0; do { - if (root->inner) - convert_all_function_calls (root->inner); + any_changed = false; + iter_count++; - walk_function (convert_tramp_reference_stmt, convert_tramp_reference_op, - root); - walk_function (convert_gimple_call, NULL, root); + if (dump_file && (dump_flags & TDF_DETAILS)) + fputc ('\n', dump_file); - /* If the function does not use a static chain, then remember that. */ - if (root->outer && !root->chain_decl && !root->chain_field) - DECL_NO_STATIC_CHAIN (root->context) = 1; - else - gcc_assert (!DECL_NO_STATIC_CHAIN (root->context)); + FOR_EACH_NEST_INFO (n, root) + { + tree decl = n->context; + bool old_no_static_chain = DECL_NO_STATIC_CHAIN (decl); - root = root->next; + walk_function (convert_tramp_reference_stmt, + convert_tramp_reference_op, n); + walk_function (convert_gimple_call, NULL, n); + + /* If a call to another function created the use of a chain + within this function, we'll have to continue iteration. */ + if (old_no_static_chain && !DECL_NO_STATIC_CHAIN (decl)) + any_changed = true; + } } - while (root); + while (any_changed); + + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, "convert_all_function_calls iterations: %d\n\n", + iter_count); } struct nesting_copy_body_data @@ -2263,10 +2339,8 @@ finalize_nesting_tree_1 (struct nesting_info *root) if (!field) continue; - if (DECL_NO_STATIC_CHAIN (i->context)) - arg3 = null_pointer_node; - else - arg3 = build_addr (root->frame_decl, context); + gcc_assert (!DECL_NO_STATIC_CHAIN (i->context)); + arg3 = build_addr (root->frame_decl, context); arg2 = build_addr (i->context, context); @@ -2379,20 +2453,19 @@ finalize_nesting_tree_1 (struct nesting_info *root) } /* Dump the translated tree function. */ - dump_function (TDI_nested, root->context); + if (dump_file) + { + fputs ("\n\n", dump_file); + dump_function_to_file (root->context, dump_file, dump_flags); + } } static void finalize_nesting_tree (struct nesting_info *root) { - do - { - if (root->inner) - finalize_nesting_tree (root->inner); - finalize_nesting_tree_1 (root); - root = root->next; - } - while (root); + struct nesting_info *n; + FOR_EACH_NEST_INFO (n, root) + finalize_nesting_tree_1 (n); } /* Unnest the nodes and pass them to cgraph. */ @@ -2414,14 +2487,9 @@ unnest_nesting_tree_1 (struct nesting_info *root) static void unnest_nesting_tree (struct nesting_info *root) { - do - { - if (root->inner) - unnest_nesting_tree (root->inner); - unnest_nesting_tree_1 (root); - root = root->next; - } - while (root); + struct nesting_info *n; + FOR_EACH_NEST_INFO (n, root) + unnest_nesting_tree_1 (n); } /* Free the data structures allocated during this pass. */ @@ -2429,18 +2497,18 @@ unnest_nesting_tree (struct nesting_info *root) static void free_nesting_tree (struct nesting_info *root) { - struct nesting_info *next; + struct nesting_info *node, *next; + + node = iter_nestinfo_start (root); do { - if (root->inner) - free_nesting_tree (root->inner); - pointer_map_destroy (root->var_map); - pointer_map_destroy (root->field_map); - next = root->next; - free (root); - root = next; + next = iter_nestinfo_next (node); + pointer_map_destroy (node->var_map); + pointer_map_destroy (node->field_map); + free (node); + node = next; } - while (root); + while (node); } /* Gimplify a function and all its nested functions. */ @@ -2462,6 +2530,10 @@ lower_nested_functions (tree fndecl) { struct cgraph_node *cgn; struct nesting_info *root; +#ifdef ENABLE_CHECKING + struct nesting_info *n; + bitmap orig_decl_no_static_chain; +#endif /* If there are no nested functions, there's nothing to do. */ cgn = cgraph_node (fndecl); @@ -2470,8 +2542,23 @@ lower_nested_functions (tree fndecl) gimplify_all_functions (cgn); + dump_file = dump_begin (TDI_nested, &dump_flags); + if (dump_file) + fprintf (dump_file, "\n;; Function %s\n\n", + lang_hooks.decl_printable_name (fndecl, 2)); + bitmap_obstack_initialize (&nesting_info_bitmap_obstack); root = create_nesting_tree (cgn); + +#ifdef ENABLE_CHECKING + /* The C++ and Ada front ends set DECL_NO_STATIC_CHAIN in various + instances where they expect no static chain needed. */ + orig_decl_no_static_chain = BITMAP_ALLOC (&nesting_info_bitmap_obstack); + FOR_EACH_NEST_INFO (n, root) + if (DECL_NO_STATIC_CHAIN (n->context)) + bitmap_set_bit (orig_decl_no_static_chain, DECL_UID (n->context)); +#endif + walk_all_functions (convert_nonlocal_reference_stmt, convert_nonlocal_reference_op, root); @@ -2480,11 +2567,26 @@ lower_nested_functions (tree fndecl) root); walk_all_functions (convert_nl_goto_reference, NULL, root); walk_all_functions (convert_nl_goto_receiver, NULL, root); + convert_all_function_calls (root); finalize_nesting_tree (root); unnest_nesting_tree (root); + +#ifdef ENABLE_CHECKING + /* Validate the original settings of DECL_NO_STATIC_CHAIN. */ + FOR_EACH_NEST_INFO (n, root) + if (bitmap_bit_p (orig_decl_no_static_chain, DECL_UID (n->context))) + gcc_assert (DECL_NO_STATIC_CHAIN (n->context)); +#endif + free_nesting_tree (root); bitmap_obstack_release (&nesting_info_bitmap_obstack); + + if (dump_file) + { + dump_end (TDI_nested, dump_file); + dump_file = NULL; + } } #include "gt-tree-nested.h" |