attribute((leafify)) for 3.4
Richard Guenther
rguenth@tat.physik.uni-tuebingen.de
Fri Oct 31 15:53:00 GMT 2003
On Fri, 31 Oct 2003, Jan Hubicka wrote:
> > On Thu, 30 Oct 2003, Richard Guenther wrote:
> > I missed to mark the cgraph edges created after inlining, with this chunk
> > added I get leafify behavior as wanted. But I still see these artificial
> > libstdc++ functions not inlined - they seem to be triggered by temporary
> > objects created inside the loop and never optimized away (as 3.3 did).
> > I'll try to dig further and come up with a testcase.
> >
> > (Final) patch is attached. It breaks debugging (-g3) with the following
> > ICE:
> >
> > /home/rguenth/ix86/pooma/tat-serial-gcc34/pooma/linux/src/Evaluator/InlineEvaluator.h:102:
> > internal compiler error: in gen_subprogram_die, at dwarf2out.c:10607
> > Please submit a full bug report,
> > with preprocessed source if appropriate.
> > See <URL:http://gcc.gnu.org/bugs.html> for instructions.
> > make: *** [tramp3d.o] Error 1
> >
> > It seems that unnecessary (inlined) function bodies are emit and
> > debugging is confused by this. But I really dont know how to prevent
> > this. Linking is fine. Any idea?
>
> Dwarf2out emits abstract debug infromation for functions that are
> inlined.
> This crash usually happens when function is inlined but the debug
> information is missing. You probably need to fix:
>
> /* Return true when the DECL can possibly be inlined. */
> bool
> cgraph_function_possibly_inlined_p (tree decl)
> {
> if (!cgraph_global_info_ready)
> return (DECL_INLINE (decl) && !flag_no_inline);
> return cgraph_node (decl)->global.inlined;
> }
>
> To return true for functions inlined by leafifying.
Ah, ok. I missed this, fixed by setting e->callee->global.inlined to 1 in
cgraph_decide_inlining_leafify().
> > +static void
> > +cgraph_decide_inlining_leafify(struct cgraph_node *node)
> > +{
> > + struct cgraph_edge *e;
> > + if (node->aux)
> > + return;
> > + for (e = node->callees; e; e = e->next_callee)
> > + {
> > + e->maybe_inline_call = 1;
> > + cgraph_decide_inlining_leafify(e->callee);
> > + }
>
> In general we are trying to avoid recursion over loop depth. You will
> also need to behave somewhat sanely in the case of recursion (either not
> inline the reucursive call or error out.
It's tail recursion, so it shouldn't be bad. Also I moved node->aux
initialization up to avoid going endlessly through callgraph loops.
Recursive inlining seems to be prevented somehow at least for not-direct
recursing, for direct recursing I added a check in the mark routine. So
cgraph_decide_inlining_leafify() looks now like
static void
cgraph_decide_inlining_leafify(struct cgraph_node *node)
{
struct cgraph_edge *e;
if (node->aux)
return;
node->aux = node;
for (e = node->callees; e; e = e->next_callee)
{
if (e->callee == node)
continue;
e->maybe_inline_call = 1;
e->callee->global.inlined = 1;
cgraph_decide_inlining_leafify(e->callee);
}
}
> In general the cgraph changes looks acceptable for me for 3.4 given that
> I will reorganize this somewhat in 3.5 anyway.
> However you will need to wait for global write maintainer to agree on the
> rest of patch and concept of leafify argument and decision whether such
> a change is acceptable in stage 3.
I won't submit this officially for 3.4, as I dont have a copyright
assignment yet and I suspect this would last too long to be accepted late
in stage 3 anyways. Also the concept of leafify needs some arguments.
Apart from this I think it is trivial for you to implement this
functionality after cleanup in 3.5, so I wont need to fiddle around with
copyright assignments.
> Please also use -c3p for diffing so the functio names appear in the
> diff. It would make it more readable. Also there seem to be some
> formating problems (perhaps just tabs replaced by spaces) in your patch.
Ah, never saw -p, this one is really useful.
Updated patch attached for those who are interested.
Thanks,
Richard.
--
Richard Guenther <richard dot guenther at uni-tuebingen dot de>
WWW: http://www.tat.physik.uni-tuebingen.de/~rguenth/
-------------- next part --------------
Index: c-common.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-common.c,v
retrieving revision 1.465
diff -u -c -3 -p -r1.465 c-common.c
*** c-common.c 20 Oct 2003 22:03:32 -0000 1.465
--- c-common.c 31 Oct 2003 12:42:53 -0000
*************** static tree handle_noreturn_attribute (t
*** 762,767 ****
--- 762,768 ----
static tree handle_noinline_attribute (tree *, tree, tree, int, bool *);
static tree handle_always_inline_attribute (tree *, tree, tree, int,
bool *);
+ static tree handle_leafify_attribute (tree *, tree, tree, int, bool *);
static tree handle_used_attribute (tree *, tree, tree, int, bool *);
static tree handle_unused_attribute (tree *, tree, tree, int, bool *);
static tree handle_const_attribute (tree *, tree, tree, int, bool *);
*************** const struct attribute_spec c_common_att
*** 824,829 ****
--- 825,832 ----
handle_noinline_attribute },
{ "always_inline", 0, 0, true, false, false,
handle_always_inline_attribute },
+ { "leafify", 0, 0, true, false, false,
+ handle_leafify_attribute },
{ "used", 0, 0, true, false, false,
handle_used_attribute },
{ "unused", 0, 0, false, false, false,
*************** handle_always_inline_attribute (tree *no
*** 4448,4453 ****
--- 4451,4478 ----
tree args ATTRIBUTE_UNUSED,
int flags ATTRIBUTE_UNUSED,
bool *no_add_attrs)
+ {
+ if (TREE_CODE (*node) == FUNCTION_DECL)
+ {
+ /* Do nothing else, just set the attribute. We'll get at
+ it later with lookup_attribute. */
+ }
+ else
+ {
+ warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+ }
+
+ /* Handle a "leafify" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+ static tree
+ handle_leafify_attribute (tree *node, tree name,
+ tree args ATTRIBUTE_UNUSED,
+ int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
{
if (TREE_CODE (*node) == FUNCTION_DECL)
{
Index: cgraph.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cgraph.c,v
retrieving revision 1.34
diff -u -c -3 -p -r1.34 cgraph.c
*** cgraph.c 22 Oct 2003 19:18:03 -0000 1.34
--- cgraph.c 31 Oct 2003 12:42:53 -0000
*************** create_edge (struct cgraph_node *caller,
*** 157,162 ****
--- 157,163 ----
struct cgraph_edge *edge2;
edge->inline_call = false;
+ edge->maybe_inline_call = false;
/* At the moment we don't associate calls with specific CALL_EXPRs
as we probably ought to, so we must preserve inline_call flags to
be the same in all copies of the same edge. */
*************** create_edge (struct cgraph_node *caller,
*** 165,170 ****
--- 166,172 ----
if (edge2->callee == callee)
{
edge->inline_call = edge2->inline_call;
+ edge->maybe_inline_call = edge2->maybe_inline_call;
break;
}
Index: cgraph.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cgraph.h,v
retrieving revision 1.23
diff -u -c -3 -p -r1.23 cgraph.h
*** cgraph.h 22 Oct 2003 11:58:09 -0000 1.23
--- cgraph.h 31 Oct 2003 12:42:53 -0000
*************** struct cgraph_edge GTY(())
*** 120,125 ****
--- 120,126 ----
struct cgraph_edge *next_caller;
struct cgraph_edge *next_callee;
bool inline_call;
+ bool maybe_inline_call;
};
/* The cgraph_varpool data strutcture.
Index: cgraphunit.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cgraphunit.c,v
retrieving revision 1.37
diff -u -c -3 -p -r1.37 cgraphunit.c
*** cgraphunit.c 22 Oct 2003 11:58:09 -0000 1.37
--- cgraphunit.c 31 Oct 2003 12:42:53 -0000
*************** static int nfunctions_inlined;
*** 57,62 ****
--- 57,65 ----
static int initial_insns;
static int overall_insns;
+ /* Flag if we expand a leafify function. */
+ static int leafify;
+
/* Records tree nodes seen in cgraph_create_edges. Simply using
walk_tree_without_duplicates doesn't guarantee each node is visited
once because it gets a new htab upon each recursive call from
*************** record_call_1 (tree *tp, int *walk_subtr
*** 257,265 ****
tree decl = get_callee_fndecl (*tp);
if (decl && TREE_CODE (decl) == FUNCTION_DECL)
{
if (DECL_BUILT_IN (decl))
return NULL;
! cgraph_record_call (data, decl);
/* When we see a function call, we don't want to look at the
function reference in the ADDR_EXPR that is hanging from
--- 260,272 ----
tree decl = get_callee_fndecl (*tp);
if (decl && TREE_CODE (decl) == FUNCTION_DECL)
{
+ struct cgraph_edge *e;
+
if (DECL_BUILT_IN (decl))
return NULL;
! e = cgraph_record_call (data, decl);
! if (leafify)
! e->maybe_inline_call = 1;
/* When we see a function call, we don't want to look at the
function reference in the ADDR_EXPR that is hanging from
*************** cgraph_optimize_function (struct cgraph_
*** 471,477 ****
/* optimize_inline_calls avoids inlining of current_function_decl. */
current_function_decl = decl;
if (flag_inline_trees)
! optimize_inline_calls (decl);
if (node->nested)
{
for (node = node->nested; node; node = node->next_nested)
--- 478,487 ----
/* optimize_inline_calls avoids inlining of current_function_decl. */
current_function_decl = decl;
if (flag_inline_trees)
! {
! leafify = (lookup_attribute ("leafify", DECL_ATTRIBUTES (node->decl)) != NULL);
! optimize_inline_calls (decl);
! }
if (node->nested)
{
for (node = node->nested; node; node = node->next_nested)
*************** cgraph_expand_function (struct cgraph_no
*** 507,513 ****
else
{
for (e = node->callers; e; e = e->next_caller)
! if (e->inline_call)
break;
if (!e)
DECL_SAVED_TREE (decl) = NULL;
--- 517,523 ----
else
{
for (e = node->callers; e; e = e->next_caller)
! if (e->inline_call || e->maybe_inline_call)
break;
if (!e)
DECL_SAVED_TREE (decl) = NULL;
*************** cgraph_decide_inlining_of_small_function
*** 1070,1075 ****
--- 1080,1106 ----
free (heap_node);
}
+ /* Go down the call tree marking nodes disregarding inlining limits. Called
+ * for function decls with attribute((leafify)) set. Avoid recursion and
+ * redundant work by using node->aux field. */
+
+ static void
+ cgraph_decide_inlining_leafify(struct cgraph_node *node)
+ {
+ struct cgraph_edge *e;
+ if (node->aux)
+ return;
+ node->aux = node;
+ for (e = node->callees; e; e = e->next_callee)
+ {
+ if (e->callee == node)
+ continue;
+ e->maybe_inline_call = 1;
+ e->callee->global.inlined = 1;
+ cgraph_decide_inlining_leafify(e->callee);
+ }
+ }
+
/* Decide on the inlining. We do so in the topological order to avoid
expenses on updating datastructures. */
*************** cgraph_decide_inlining (void)
*** 1216,1221 ****
--- 1247,1274 ----
}
}
+ /* For all nodes with their function decl having attribute((leafify)) set
+ * remove inline mark and set maybe_inline_call downward all callees.
+ * Use node->aux to avoid duplicate walking of callees. */
+
+ for (node = cgraph_nodes; node; node = node->next)
+ node->aux = 0;
+
+ for (i = nnodes - 1; i >= 0; i--)
+ {
+ struct cgraph_edge *e;
+
+ node = order[i];
+
+ if (lookup_attribute ("leafify", DECL_ATTRIBUTES (node->decl)) == NULL)
+ continue;
+
+ for (e = node->callers; e; e = e->next_caller)
+ e->inline_call = 0;
+
+ cgraph_decide_inlining_leafify(node);
+ }
+
if (cgraph_dump_file)
fprintf (cgraph_dump_file,
"\nInlined %i calls, eliminated %i functions, "
*************** cgraph_inline_p (tree caller_decl, tree
*** 1291,1297 ****
for (e = caller->callees; e; e = e->next_callee)
if (e->callee == callee)
! return e->inline_call;
/* We do not record builtins in the callgraph. Perhaps it would make more
sense to do so and then prune out those not overwritten by explicit
function body. */
--- 1344,1350 ----
for (e = caller->callees; e; e = e->next_callee)
if (e->callee == callee)
! return e->inline_call || (e->maybe_inline_call && leafify);
/* We do not record builtins in the callgraph. Perhaps it would make more
sense to do so and then prune out those not overwritten by explicit
function body. */
Index: doc/extend.texi
===================================================================
RCS file: /cvs/gcc/gcc/gcc/doc/extend.texi,v
retrieving revision 1.169
diff -u -c -3 -p -r1.169 extend.texi
*** doc/extend.texi 26 Oct 2003 19:03:42 -0000 1.169
--- doc/extend.texi 31 Oct 2003 12:42:57 -0000
*************** The keyword @code{__attribute__} allows
*** 1976,1982 ****
attributes when making a declaration. This keyword is followed by an
attribute specification inside double parentheses. The following
attributes are currently defined for functions on all targets:
! @code{noreturn}, @code{noinline}, @code{always_inline},
@code{pure}, @code{const}, @code{nothrow},
@code{format}, @code{format_arg}, @code{no_instrument_function},
@code{section}, @code{constructor}, @code{destructor}, @code{used},
--- 1976,1982 ----
attributes when making a declaration. This keyword is followed by an
attribute specification inside double parentheses. The following
attributes are currently defined for functions on all targets:
! @code{noreturn}, @code{noinline}, @code{always_inline}, @code{leafify},
@code{pure}, @code{const}, @code{nothrow},
@code{format}, @code{format_arg}, @code{no_instrument_function},
@code{section}, @code{constructor}, @code{destructor}, @code{used},
*************** inlining.
*** 2052,2057 ****
--- 2052,2066 ----
Generally, functions are not inlined unless optimization is specified.
For functions declared inline, this attribute inlines the function even
if no optimization level was specified.
+
+ @cindex @code{leafify} function attribute
+ @item leafify
+ Generally, inlining into a function is limited. For a function marked with
+ this attribute, every call inside this function will be inlined, if possible.
+ This attribute implies that the function itself is not considered for automatic
+ inlining, but into functions marked @code{leafify}. You need to mark the function
+ @code{noinline} if you want to prevent the latter. The @code{leafify} attribute
+ only works in unit-at-a-time mode.
@cindex @code{pure} function attribute
@item pure
More information about the Gcc
mailing list