OSDN Git Service

2005-07-15 Richard Guenther <rguenther@suse.de>
authorrguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 15 Jul 2005 09:31:39 +0000 (09:31 +0000)
committerrguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 15 Jul 2005 09:31:39 +0000 (09:31 +0000)
* 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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@102051 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/Makefile.in
gcc/c-common.c
gcc/doc/extend.texi
gcc/ipa-inline.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/tree-ssa/flatten-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/flatten-2.c [new file with mode: 0644]

index 68dec8a..317e2d7 100644 (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,
 2005-07-14  David Edelsohn  <edelsohn@gnu.org>
 
        * config/rs6000/rs6000.md (UNSPEC_SYNC, UNSPEC_LWSYNC,
index 2bc1092..3d8b8bc 100644 (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 \
 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 \
 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 \
index f3d4a28..f7463e1 100644 (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_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,
 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 },
                              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,
   { "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;
 }
 
   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.  */
 
 /* Handle a "used" attribute; arguments as in
    struct attribute_spec.handler.  */
 
index cc6ea2d..f71c520 100644 (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},
 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},
 @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.
 
 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
 @item cdecl
 @cindex functions that do pop the argument stack on the 386
 @opindex mrtd
index cb71047..df57ccc 100644 (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 "fibheap.h"
 #include "intl.h"
 #include "tree-pass.h"
+#include "hashtab.h"
 #include "coverage.h"
 #include "ggc.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);
 }
 
       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.  */
 
 /* 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];
 
 
       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)
       if (!node->local.disregard_inline_limits)
        continue;
       if (dump_file)
index 2e5eee9..6bef685 100644 (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
 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 (file)
index 0000000..4561f75
--- /dev/null
@@ -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 (file)
index 0000000..56e8083
--- /dev/null
@@ -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.:" } } */