aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Guenther <rguenther@suse.de>2005-07-15 09:31:39 +0000
committerRichard Biener <rguenth@gcc.gnu.org>2005-07-15 09:31:39 +0000
commit0691d1d4a31ff0a426d2ba07c64acbac5df6b8ae (patch)
tree2e0dd485a84563f4c7093a4d5ed09ecd19507784
parent7c22afcba12417a2dcb10ceb358966447f07f5ef (diff)
downloadgcc-0691d1d4a31ff0a426d2ba07c64acbac5df6b8ae.zip
gcc-0691d1d4a31ff0a426d2ba07c64acbac5df6b8ae.tar.gz
gcc-0691d1d4a31ff0a426d2ba07c64acbac5df6b8ae.tar.bz2
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
-rw-r--r--gcc/ChangeLog11
-rw-r--r--gcc/Makefile.in2
-rw-r--r--gcc/c-common.c25
-rw-r--r--gcc/doc/extend.texi10
-rw-r--r--gcc/ipa-inline.c78
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/flatten-1.c57
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/flatten-2.c76
8 files changed, 262 insertions, 2 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 68dec8a..317e2d7 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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,
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 2bc1092..3d8b8bc 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -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 \
diff --git a/gcc/c-common.c b/gcc/c-common.c
index f3d4a28..f7463e1 100644
--- a/gcc/c-common.c
+++ b/gcc/c-common.c
@@ -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. */
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index cc6ea2d..f71c520 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -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
diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c
index cb71047..df57ccc 100644
--- a/gcc/ipa-inline.c
+++ b/gcc/ipa-inline.c
@@ -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)
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 2e5eee9..6bef685 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/flatten-1.c b/gcc/testsuite/gcc.dg/tree-ssa/flatten-1.c
new file mode 100644
index 0000000..4561f75
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/flatten-1.c
@@ -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:" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/flatten-2.c b/gcc/testsuite/gcc.dg/tree-ssa/flatten-2.c
new file mode 100644
index 0000000..56e8083
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/flatten-2.c
@@ -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.:" } } */