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:
parent
7c22afcba1
commit
0691d1d4a3
|
@ -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,
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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. */
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:" } } */
|
|
@ -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.:" } } */
|
Loading…
Reference in New Issue