Commit fe663f4e by Richard Henderson Committed by Richard Henderson

re PR target/41246 (should "sorry" when regparm=3 and nested functions are encountered)

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.

From-SVN: r151762
parent 9b87db3c
2009-09-16 Richard Henderson <rth@redhat.com>
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.
2009-09-16 Michael Matz <matz@suse.de>
PR fortran/41212
......
......@@ -3573,6 +3573,25 @@ verify_gimple_call (gimple stmt)
return true;
}
/* If there is a static chain argument, this should not be an indirect
call, and the decl should not have DECL_NO_STATIC_CHAIN set. */
if (gimple_call_chain (stmt))
{
if (TREE_CODE (fn) != ADDR_EXPR
|| TREE_CODE (TREE_OPERAND (fn, 0)) != FUNCTION_DECL)
{
error ("static chain in indirect gimple call");
return true;
}
fn = TREE_OPERAND (fn, 0);
if (DECL_NO_STATIC_CHAIN (fn))
{
error ("static chain with function that doesn't use one");
return true;
}
}
/* ??? The C frontend passes unpromoted arguments in case it
didn't see a function declaration before the call. So for now
leave the call arguments unverified. Once we gimplify
......
/* 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"
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment