+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,
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 \
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,
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,
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. */
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},
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
#include "fibheap.h"
#include "intl.h"
#include "tree-pass.h"
+#include "hashtab.h"
#include "coverage.h"
#include "ggc.h"
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. */
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)
+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
--- /dev/null
+/* { 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:" } } */
--- /dev/null
+/* { 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.:" } } */