c-common.c (handle_flatten_attribute): New function.

2005-07-15  Richard Guenther  <rguenther@suse.de>

	* c-common.c (handle_flatten_attribute): New function.
	Add flatten function attribute.
	* doc/extend.texi: Document flatten function attribute.
	* Makefile.in (ipa-inline.o): Depend on hashtab.h.
	* ipa-inline.c (cgraph_find_cycles, cgraph_flatten_node):
	New functions.
	(cgraph_decide_inlining): Handle functions with flatten
	attribute.

	* gcc.dg/tree-ssa/flatten-1.c: New testcase.
	* gcc.dg/tree-ssa/flatten-2.c: Likewise.

From-SVN: r102051
This commit is contained in:
Richard Guenther 2005-07-15 09:31:39 +00:00 committed by Richard Biener
parent 7c22afcba1
commit 0691d1d4a3
8 changed files with 262 additions and 2 deletions

View File

@ -1,3 +1,14 @@
2005-07-15 Richard Guenther <rguenther@suse.de>
* c-common.c (handle_flatten_attribute): New function.
Add flatten function attribute.
* doc/extend.texi: Document flatten function attribute.
* Makefile.in (ipa-inline.o): Depend on hashtab.h.
* ipa-inline.c (cgraph_find_cycles, cgraph_flatten_node):
New functions.
(cgraph_decide_inlining): Handle functions with flatten
attribute.
2005-07-14 David Edelsohn <edelsohn@gnu.org>
* config/rs6000/rs6000.md (UNSPEC_SYNC, UNSPEC_LWSYNC,

View File

@ -2141,7 +2141,7 @@ ipa.o : ipa.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(CGRAPH_H)
ipa-inline.o : ipa-inline.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(TREE_H) langhooks.h tree-inline.h $(FLAGS_H) $(CGRAPH_H) intl.h \
$(DIAGNOSTIC_H) $(FIBHEAP_H) $(PARAMS_H) $(TIMEVAR_H) tree-pass.h \
$(COVERAGE_H)
$(COVERAGE_H) $(HASHTAB_H)
coverage.o : coverage.c $(GCOV_IO_H) $(CONFIG_H) $(SYSTEM_H) coretypes.h \
$(TM_H) $(RTL_H) $(TREE_H) $(FLAGS_H) output.h $(REGS_H) $(EXPR_H) \
function.h toplev.h $(GGC_H) langhooks.h $(COVERAGE_H) gt-coverage.h \

View File

@ -505,6 +505,7 @@ static tree handle_noreturn_attribute (tree *, tree, tree, int, bool *);
static tree handle_noinline_attribute (tree *, tree, tree, int, bool *);
static tree handle_always_inline_attribute (tree *, tree, tree, int,
bool *);
static tree handle_flatten_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_externally_visible_attribute (tree *, tree, tree, int,
@ -571,6 +572,8 @@ const struct attribute_spec c_common_attribute_table[] =
handle_noinline_attribute },
{ "always_inline", 0, 0, true, false, false,
handle_always_inline_attribute },
{ "flatten", 0, 0, true, false, false,
handle_flatten_attribute },
{ "used", 0, 0, true, false, false,
handle_used_attribute },
{ "unused", 0, 0, false, false, false,
@ -4151,6 +4154,28 @@ handle_always_inline_attribute (tree *node, tree name,
return NULL_TREE;
}
/* Handle a "flatten" attribute; arguments as in
struct attribute_spec.handler. */
static tree
handle_flatten_attribute (tree *node, tree name,
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 (OPT_Wattributes, "%qE attribute ignored", name);
*no_add_attrs = true;
}
return NULL_TREE;
}
/* Handle a "used" attribute; arguments as in
struct attribute_spec.handler. */

View File

@ -1523,7 +1523,7 @@ 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{returns_twice}, @code{noinline}, @code{always_inline},
@code{pure}, @code{const}, @code{nothrow}, @code{sentinel},
@code{flatten}, @code{pure}, @code{const}, @code{nothrow}, @code{sentinel},
@code{format}, @code{format_arg}, @code{no_instrument_function},
@code{section}, @code{constructor}, @code{destructor}, @code{used},
@code{unused}, @code{deprecated}, @code{weak}, @code{malloc},
@ -1566,6 +1566,14 @@ 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{flatten} function attribute
@item flatten
Generally, inlining into a function is limited. For a function marked with
this attribute, every call inside this function will be inlined, if possible.
Whether the function itself is considered for inlining depends on its size and
the current inlining parameters. The @code{flatten} attribute only works
reliably in unit-at-a-time mode.
@item cdecl
@cindex functions that do pop the argument stack on the 386
@opindex mrtd

View File

@ -78,6 +78,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
#include "fibheap.h"
#include "intl.h"
#include "tree-pass.h"
#include "hashtab.h"
#include "coverage.h"
#include "ggc.h"
@ -438,6 +439,65 @@ lookup_recursive_calls (struct cgraph_node *node, struct cgraph_node *where,
lookup_recursive_calls (node, e->callee, heap);
}
/* Find callgraph nodes closing a circle in the graph. The
resulting hashtab can be used to avoid walking the circles.
Uses the cgraph nodes ->aux field which needs to be zero
before and will be zero after operation. */
static void
cgraph_find_cycles (struct cgraph_node *node, htab_t cycles)
{
struct cgraph_edge *e;
if (node->aux)
{
void **slot;
slot = htab_find_slot (cycles, node, INSERT);
if (!*slot)
{
if (dump_file)
fprintf (dump_file, "Cycle contains %s\n", cgraph_node_name (node));
*slot = node;
}
return;
}
node->aux = node;
for (e = node->callees; e; e = e->next_callee)
cgraph_find_cycles (e->callee, cycles);
node->aux = 0;
}
/* Leafify the cgraph node. We have to be careful in recursing
as to not run endlessly in circles of the callgraph.
We do so by using a hashtab of cycle entering nodes as generated
by cgraph_find_cycles. */
static void
cgraph_flatten_node (struct cgraph_node *node, htab_t cycles)
{
struct cgraph_edge *e;
for (e = node->callees; e; e = e->next_callee)
{
/* Inline call, if possible, and recurse. Be sure we are not
entering callgraph circles here. */
if (e->inline_failed
&& e->callee->local.inlinable
&& !cgraph_recursive_inlining_p (node, e->callee,
&e->inline_failed)
&& !htab_find (cycles, e->callee))
{
if (dump_file)
fprintf (dump_file, " inlining %s", cgraph_node_name (e->callee));
cgraph_mark_inline_edge (e);
cgraph_flatten_node (e->callee, cycles);
}
else if (dump_file)
fprintf (dump_file, " !inlining %s", cgraph_node_name (e->callee));
}
}
/* Decide on recursive inlining: in the case function has recursive calls,
inline until body size reaches given argument. */
@ -769,6 +829,24 @@ cgraph_decide_inlining (void)
node = order[i];
/* Handle nodes to be flattened, but don't update overall unit size. */
if (lookup_attribute ("flatten", DECL_ATTRIBUTES (node->decl)) != NULL)
{
int old_overall_insns = overall_insns;
htab_t cycles;
if (dump_file)
fprintf (dump_file,
"Leafifying %s\n", cgraph_node_name (node));
cycles = htab_create (7, htab_hash_pointer, htab_eq_pointer, NULL);
cgraph_find_cycles (node, cycles);
cgraph_flatten_node (node, cycles);
htab_delete (cycles);
overall_insns = old_overall_insns;
/* We don't need to consider always_inline functions inside the flattened
function anymore. */
continue;
}
if (!node->local.disregard_inline_limits)
continue;
if (dump_file)

View File

@ -1,3 +1,8 @@
2005-07-15 Richard Guenther <rguenther@suse.de>
* gcc.dg/tree-ssa/flatten-1.c: New testcase.
* gcc.dg/tree-ssa/flatten-2.c: Likewise.
2005-07-15 Steven Bosscher <stevenb@suse.de>
PR tree-optimization/22230

View File

@ -0,0 +1,57 @@
/* { dg-do compile } */
/* { dg-options -O2 } */
/* Basic tests for flatten attribute, check we end up
with only the flattened function bodies. */
static int foobar(int i);
static int bar(int i);
int __attribute__((flatten)) leaf0a(int i)
{
return bar(i);
}
int __attribute__((flatten)) leaf0b(int i)
{
return foobar(i);
}
int __attribute__((flatten)) leaf1(int i)
{
return bar(foobar(i));
}
int __attribute__((flatten)) leaf2(int i)
{
int j;
j = foobar(i);
return bar(j);
}
static int foobar(int i)
{
return i-1;
}
static int bar(int i)
{
return i + foobar(i);
}
static int g(int i)
{
return i*5+1;
}
static int f(int i)
{
return g(i);
}
int __attribute__((flatten)) leaf3(int i)
{
int j;
j = f(i);
j += f(i);
return j;
}
/* { dg-final { scan-assembler-not "g:" } } */
/* { dg-final { scan-assembler-not "f:" } } */
/* { dg-final { scan-assembler-not "bar:" } } */

View File

@ -0,0 +1,76 @@
/* { dg-do compile } */
/* { dg-options -O2 } */
/* Check that we finish compiling even if instructed to
flatten a cyclic callgraph. Verify we correctly
flatten with another function marked flatten in the
callgraph. */
void __attribute__((flatten)) direct(void)
{
direct();
}
void __attribute__((flatten)) indirect(void);
static void indirect1(void)
{
indirect();
}
void __attribute__((flatten)) indirect(void)
{
indirect1();
}
void __attribute__((flatten)) doubleindirect(void);
static void doubleindirect2(void)
{
doubleindirect();
}
static void doubleindirect1(void)
{
doubleindirect2();
}
void __attribute__((flatten)) doubleindirect(void)
{
doubleindirect1();
}
static void subcycle1(void);
static void subcycle2(void)
{
subcycle1();
}
static void subcycle1(void)
{
subcycle2();
}
void __attribute__((flatten)) subcycle(void)
{
subcycle1();
}
static void doublesubcycle1(void);
static void doublesubcycle2(void);
static void doublesubcycle3(void)
{
doublesubcycle1();
}
static void doublesubcycle2(void)
{
doublesubcycle3();
}
static void doublesubcycle1(void)
{
doublesubcycle2();
}
void __attribute__((flatten)) doublesubcycle(void)
{
doublesubcycle1();
}
/* { dg-final { scan-assembler "cycle.:" } } */
/* { dg-final { scan-assembler-not "indirect.:" } } */