Makefile.in (cgraph.o, [...]): Add intl.h dependency.
authorJan Hubicka <jh@suse.cz>
Sun, 4 Jan 2004 14:39:13 +0000 (15:39 +0100)
committerJan Hubicka <hubicka@gcc.gnu.org>
Sun, 4 Jan 2004 14:39:13 +0000 (14:39 +0000)
* Makefile.in (cgraph.o, cgraphunit.o): Add intl.h dependency.
* cgraph.c (create_edge, dump_cgraph): Update to use inline_failed
* cgraph.h (cgraph_edge): Replace inline_call by inline_failed
(cgraph_inline_p): Add extra argument reason.
* cgraphunit.c: Minor formating fixes.
cgraph_first_inlined_callee): New functions.
(record_call_1): Record builtins too.
(cgraph_analyze_function): Update inline_failed messages.
(cgraph_mark_functions_to_output, cgraph_expand_function, cgraph_inlined_into,
cgraph_inlined_callees, cgraph_estimate_growth): Update to use inline_failed.
(cgraph_check_inline_limits): Likewise; Add argument reason.
(cgraph_set_inline_failed): New static function.
(cgraph_decide_inlining_of_small_function, cgraph_decide_inlining): Set
reasons.
(cgraph_inline_p): Add new argument reason.
* tree-inline.c (expand_call_inline):  Update warning.

From-SVN: r75391

14 files changed:
gcc/ChangeLog
gcc/Makefile.in
gcc/cgraph.c
gcc/cgraph.h
gcc/cgraphunit.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/winline-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/winline-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/winline-3.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/winline-4.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/winline-5.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/winline-6.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/winline-7.c [new file with mode: 0644]
gcc/tree-inline.c

index 555a1e3..a1b09c0 100644 (file)
@@ -1,3 +1,22 @@
+2004-01-04  Jan Hubicka  <jh@suse.cz>
+
+       * Makefile.in (cgraph.o, cgraphunit.o): Add intl.h dependency.
+       * cgraph.c (create_edge, dump_cgraph): Update to use inline_failed
+       * cgraph.h (cgraph_edge): Replace inline_call by inline_failed
+       (cgraph_inline_p): Add extra argument reason.
+       * cgraphunit.c: Minor formating fixes.
+       cgraph_first_inlined_callee): New functions.
+       (record_call_1): Record builtins too.
+       (cgraph_analyze_function): Update inline_failed messages.
+       (cgraph_mark_functions_to_output, cgraph_expand_function, cgraph_inlined_into,
+       cgraph_inlined_callees, cgraph_estimate_growth): Update to use inline_failed.
+       (cgraph_check_inline_limits): Likewise; Add argument reason.
+       (cgraph_set_inline_failed): New static function.
+       (cgraph_decide_inlining_of_small_function, cgraph_decide_inlining): Set
+       reasons.
+       (cgraph_inline_p): Add new argument reason.
+       * tree-inline.c (expand_call_inline):  Update warning.
+
 2004-01-03  Nathanael Nerode  <neroden@gcc.gnu.org>
 
        * configure.ac: Replace AC_INIT, AC_OUTPUT, AC_CANONICAL_SYSTEM
index 1390141..592acd8 100644 (file)
@@ -1633,9 +1633,10 @@ simplify-rtx.o : simplify-rtx.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RT
    $(REGS_H) hard-reg-set.h flags.h real.h insn-config.h $(RECOG_H) $(EXPR_H) toplev.h \
    output.h function.h $(GGC_H) $(OBSTACK_H) $(TM_P_H) $(TREE_H) $(TARGET_H)
 cgraph.o : cgraph.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
-   langhooks.h toplev.h flags.h $(GGC_H)  $(TARGET_H) cgraph.h gt-cgraph.h output.h
+   langhooks.h toplev.h flags.h $(GGC_H)  $(TARGET_H) cgraph.h gt-cgraph.h \
+   output.h intl.h
 cgraphunit.o : cgraphunit.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
-   langhooks.h tree-inline.h toplev.h flags.h $(GGC_H)  $(TARGET_H) cgraph.h
+   langhooks.h tree-inline.h toplev.h flags.h $(GGC_H)  $(TARGET_H) cgraph.h intl.h
 coverage.o : coverage.c gcov-io.c $(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) $(TARGET_H) langhooks.h $(COVERAGE_H) libfuncs.h \
index 26cbd27..73a420e 100644 (file)
@@ -34,6 +34,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "cgraph.h"
 #include "varray.h"
 #include "output.h"
+#include "intl.h"
 
 
 /* Hash table used to convert declarations into nodes.  */
@@ -156,7 +157,13 @@ create_edge (struct cgraph_node *caller, struct cgraph_node *callee)
   struct cgraph_edge *edge = ggc_alloc (sizeof (struct cgraph_edge));
   struct cgraph_edge *edge2;
 
-  edge->inline_call = false;
+  if (!DECL_SAVED_TREE (callee->decl))
+    edge->inline_failed = N_("function body not available");
+  else if (callee->local.inlinable)
+    edge->inline_failed = N_("function not considered for inlining");
+  else
+    edge->inline_failed = N_("function not inlinable");
+
   /* At the moment we don't associate calls with specific CALL_EXPRs
      as we probably ought to, so we must preserve inline_call flags to
      be the same in all copies of the same edge.  */
@@ -164,7 +171,7 @@ create_edge (struct cgraph_node *caller, struct cgraph_node *callee)
     for (edge2 = caller->callees; edge2; edge2 = edge2->next_callee)
       if (edge2->callee == callee)
        {
-         edge->inline_call = edge2->inline_call;
+         edge->inline_failed = edge2->inline_failed;
          break;
        }
 
@@ -381,7 +388,7 @@ dump_cgraph (FILE *f)
       for (edge = node->callers; edge; edge = edge->next_caller)
        {
          fprintf (f, "%s ", cgraph_node_name (edge->caller));
-         if (edge->inline_call)
+         if (!edge->inline_failed)
            fprintf(f, "(inlined) ");
        }
 
@@ -389,7 +396,7 @@ dump_cgraph (FILE *f)
       for (edge = node->callees; edge; edge = edge->next_callee)
        {
          fprintf (f, "%s ", cgraph_node_name (edge->callee));
-         if (edge->inline_call)
+         if (!edge->inline_failed)
            fprintf(f, "(inlined) ");
        }
       fprintf (f, "\n");
index 9540ecc..5cf31d7 100644 (file)
@@ -119,7 +119,9 @@ struct cgraph_edge GTY(())
   struct cgraph_node *callee;
   struct cgraph_edge *next_caller;
   struct cgraph_edge *next_callee;
-  bool inline_call;
+  /* When NULL, inline this call.  When non-NULL, points to the explanation
+     why function was not inlined.  */
+  const char *inline_failed;
 };
 
 /* The cgraph_varpool data structure.
@@ -181,6 +183,6 @@ void cgraph_create_edges (tree, tree);
 void cgraph_optimize (void);
 void cgraph_mark_needed_node (struct cgraph_node *);
 void cgraph_mark_reachable_node (struct cgraph_node *);
-bool cgraph_inline_p (tree, tree);
+bool cgraph_inline_p (tree, tree, const char **reason);
 
 #endif  /* GCC_CGRAPH_H  */
index 932c418..4b4aef0 100644 (file)
@@ -38,6 +38,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "params.h"
 #include "fibheap.h"
 #include "c-common.h"
+#include "intl.h"
 
 #define INSNS_PER_CALL 10
 
@@ -257,8 +258,6 @@ record_call_1 (tree *tp, int *walk_subtrees, void *data)
        tree decl = get_callee_fndecl (*tp);
        if (decl && TREE_CODE (decl) == FUNCTION_DECL)
          {
-           if (DECL_BUILT_IN (decl))
-             return NULL;
            cgraph_record_call (data, decl);
 
            /* When we see a function call, we don't want to look at the
@@ -311,6 +310,7 @@ static void
 cgraph_analyze_function (struct cgraph_node *node)
 {
   tree decl = node->decl;
+  struct cgraph_edge *e;
 
   current_function_decl = decl;
 
@@ -325,6 +325,10 @@ cgraph_analyze_function (struct cgraph_node *node)
   if (node->local.inlinable)
     node->local.disregard_inline_limits
       = (*lang_hooks.tree_inlining.disregard_inline_limits) (decl);
+  for (e = node->callers; e; e = e->next_caller)
+    if (e->inline_failed)
+      e->inline_failed = (!node->local.inlinable ? N_("function not inlinable")
+                         : N_("function not considered for inlining"));
   if (flag_really_no_inline && !node->local.disregard_inline_limits)
     node->local.inlinable = 0;
   /* Inlining characteristics are maintained by the cgraph_mark_inline.  */
@@ -442,11 +446,12 @@ cgraph_mark_functions_to_output (void)
     {
       tree decl = node->decl;
       struct cgraph_edge *e;
+
       if (node->output)
        abort ();
 
       for (e = node->callers; e; e = e->next_caller)
-       if (!e->inline_call)
+       if (e->inline_failed)
          break;
 
       /* We need to output all local functions that are used and not
@@ -476,7 +481,7 @@ cgraph_optimize_function (struct cgraph_node *node)
       struct cgraph_edge *e;
 
       for (e = node->callees; e; e = e->next_callee)
-       if (e->inline_call || warn_inline)
+       if (!e->inline_failed || warn_inline)
          break;
       if (e)
         optimize_inline_calls (decl);
@@ -512,6 +517,7 @@ cgraph_expand_function (struct cgraph_node *node)
 
 /* Fill array order with all nodes with output flag set in the reverse
    topological order.  */
+
 static int
 cgraph_postorder (struct cgraph_node **order)
 {
@@ -594,7 +600,7 @@ cgraph_inlined_into (struct cgraph_node *node, struct cgraph_node **array)
   /* Fast path: since we traverse in mostly topological order, we will likely
      find no edges.  */
   for (e = node->callers; e; e = e->next_caller)
-    if (e->inline_call)
+    if (!e->inline_failed)
       break;
 
   if (!e)
@@ -626,8 +632,9 @@ cgraph_inlined_into (struct cgraph_node *node, struct cgraph_node **array)
       SET_INLINED_TIMES (caller, INLINED_TIMES (caller) + 1);
 
       for (e1 = caller->callers; e1; e1 = e1->next_caller)
-       if (e1->inline_call)
+       if (!e1->inline_failed)
          break;
+
       if (e1)
        stack[sp++] = e1;
       else
@@ -635,7 +642,7 @@ cgraph_inlined_into (struct cgraph_node *node, struct cgraph_node **array)
          while (true)
            {
              for (e1 = e->next_caller; e1; e1 = e1->next_caller)
-               if (e1->inline_call)
+               if (!e1->inline_failed)
                  break;
 
              if (e1)
@@ -692,7 +699,7 @@ cgraph_inlined_callees (struct cgraph_node *node, struct cgraph_node **array)
   /* Fast path: since we traverse in mostly topological order, we will likely
      find no edges.  */
   for (e = node->callees; e; e = e->next_callee)
-    if (e->inline_call)
+    if (!e->inline_failed)
       break;
 
   if (!e)
@@ -724,7 +731,7 @@ cgraph_inlined_callees (struct cgraph_node *node, struct cgraph_node **array)
       SET_INLINED_TIMES (callee, INLINED_TIMES (callee) + 1);
 
       for (e1 = callee->callees; e1; e1 = e1->next_callee)
-       if (e1->inline_call)
+       if (!e1->inline_failed)
          break;
       if (e1)
        stack[sp++] = e1;
@@ -733,7 +740,7 @@ cgraph_inlined_callees (struct cgraph_node *node, struct cgraph_node **array)
          while (true)
            {
              for (e1 = e->next_callee; e1; e1 = e1->next_callee)
-               if (e1->inline_call)
+               if (!e1->inline_failed)
                  break;
 
              if (e1)
@@ -791,7 +798,7 @@ cgraph_estimate_growth (struct cgraph_node *node)
   struct cgraph_edge *e;
 
   for (e = node->callers; e; e = e->next_caller)
-    if (!e->inline_call)
+    if (e->inline_failed)
       {
        growth += ((cgraph_estimate_size_after_inlining (1, e->caller, node)
                    -
@@ -833,13 +840,13 @@ cgraph_mark_inline (struct cgraph_node *to, struct cgraph_node *what,
     {
       if (e->caller == to)
        {
-         if (e->inline_call)
-           abort ();
-         e->inline_call = true;
+         if (!e->inline_failed)
+           continue;
+         e->inline_failed = NULL;
          times++;
          clones += e->caller->global.cloned_times;
        }
-      else if (!e->inline_call)
+      else if (e->inline_failed)
        called = true;
     }
   if (!times)
@@ -884,7 +891,8 @@ cgraph_mark_inline (struct cgraph_node *to, struct cgraph_node *what,
 
 static bool
 cgraph_check_inline_limits (struct cgraph_node *to, struct cgraph_node *what,
-                           struct cgraph_node **inlined, int ninlined)
+                           struct cgraph_node **inlined, int ninlined,
+                           const char **reason)
 {
   int i;
   int times = 0;
@@ -908,7 +916,10 @@ cgraph_check_inline_limits (struct cgraph_node *to, struct cgraph_node *what,
   newsize = cgraph_estimate_size_after_inlining (times, to, what);
   if (newsize > PARAM_VALUE (PARAM_LARGE_FUNCTION_INSNS)
       && newsize > limit)
-    return false;
+    {
+      *reason = N_("--param large-function-growth limit reached");
+      return false;
+    }
   for (i = 0; i < ninlined; i++)
     {
       newsize =
@@ -918,7 +929,10 @@ cgraph_check_inline_limits (struct cgraph_node *to, struct cgraph_node *what,
          && newsize >
          inlined[i]->local.self_insns *
          (100 + PARAM_VALUE (PARAM_LARGE_FUNCTION_GROWTH)) / 100)
-       return false;
+       {
+         *reason = N_("--param large-function-growth limit reached while inlining the caller");
+         return false;
+       }
     }
   return true;
 }
@@ -936,6 +950,20 @@ cgraph_default_inline_p (struct cgraph_node *n)
     return n->global.insns < MAX_INLINE_INSNS_AUTO;
 }
 
+/* Set inline_failed for all callers of given function to REASON.  */
+
+static void
+cgraph_set_inline_failed (struct cgraph_node *node, const char *reason)
+{
+  struct cgraph_edge *e;
+
+  if (cgraph_dump_file)
+    fprintf (cgraph_dump_file, "Inlining failed: %s\n", reason);
+  for (e = node->callers; e; e = e->next_caller)
+    if (e->inline_failed)
+      e->inline_failed = reason;
+}
+
 /* We use greedy algorithm for inlining of small functions:
    All inline candidates are put into prioritized heap based on estimated
    growth of the overall number of instructions and then update the estimates.
@@ -960,25 +988,23 @@ cgraph_decide_inlining_of_small_functions (struct cgraph_node **inlined,
 
   for (node = cgraph_nodes; node; node = node->next)
     {
-      struct cgraph_edge *e;
-
       if (!node->local.inlinable || !node->callers
-         || !cgraph_default_inline_p (node))
+         || node->local.disregard_inline_limits)
        continue;
 
-      /* Rule out always_inline functions we dealt with earlier.  */
-      for (e = node->callers; e; e = e->next_caller)
-       if (e->inline_call)
-         break;
-      if (e)
-       continue;
+      if (!cgraph_default_inline_p (node))
+       {
+         cgraph_set_inline_failed (node,
+           N_("--param max-inline-insns-single limit reached"));
+         continue;
+       }
       heap_node[node->uid] =
        fibheap_insert (heap, cgraph_estimate_growth (node), node);
     }
 
   if (cgraph_dump_file)
     fprintf (cgraph_dump_file, "\nDeciding on smaller functions:\n");
-  while ((node = fibheap_extract_min (heap)) && overall_insns <= max_insns)
+  while (overall_insns <= max_insns && (node = fibheap_extract_min (heap)))
     {
       struct cgraph_edge *e;
       int old_insns = overall_insns;
@@ -992,18 +1018,27 @@ cgraph_decide_inlining_of_small_functions (struct cgraph_node **inlined,
                 cgraph_estimate_growth (node));
       if (!cgraph_default_inline_p (node))
        {
-         if (cgraph_dump_file)
-           fprintf (cgraph_dump_file, " Function too large.\n");
+         cgraph_set_inline_failed (node,
+           N_("--param max-inline-insns-single limit reached after inlining into the callee"));
          continue;
        }
       ninlined_callees = cgraph_inlined_callees (node, inlined_callees);
       for (e = node->callers; e; e = e->next_caller)
-       if (!e->inline_call && e->caller != node)
+       if (e->inline_failed)
          {
+           /* Marking recursive function inlinine has sane semantic and
+              thus we should not warn on it.  */
+           if (e->caller == node)
+             {
+               e->inline_failed = "";
+               continue;
+             }
            ninlined = cgraph_inlined_into (e->caller, inlined);
+           if (e->callee->output)
+             e->inline_failed = "";
            if (e->callee->output
                || !cgraph_check_inline_limits (e->caller, node, inlined,
-                                               ninlined))
+                                               ninlined, &e->inline_failed))
              {
                for (i = 0; i < ninlined; i++)
                  inlined[i]->output = 0, node->aux = 0;
@@ -1039,7 +1074,7 @@ cgraph_decide_inlining_of_small_functions (struct cgraph_node **inlined,
          are now called more times; update keys.  */
 
       for (e = node->callees; e; e = e->next_callee)
-       if (!e->inline_call && heap_node[e->callee->uid])
+       if (e->inline_failed && heap_node[e->callee->uid])
          fibheap_replace_key (heap, heap_node[e->callee->uid],
                               cgraph_estimate_growth (e->callee));
 
@@ -1048,7 +1083,7 @@ cgraph_decide_inlining_of_small_functions (struct cgraph_node **inlined,
          struct cgraph_edge *e;
 
          for (e = inlined_callees[i]->callees; e; e = e->next_callee)
-           if (!e->inline_call && heap_node[e->callee->uid])
+           if (e->inline_failed && heap_node[e->callee->uid])
              fibheap_replace_key (heap, heap_node[e->callee->uid],
                                   cgraph_estimate_growth (e->callee));
 
@@ -1059,8 +1094,9 @@ cgraph_decide_inlining_of_small_functions (struct cgraph_node **inlined,
                 " Inlined %i times for a net change of %+i insns.\n",
                 node->global.cloned_times, overall_insns - old_insns);
     }
-  if (cgraph_dump_file && !fibheap_empty (heap))
-    fprintf (cgraph_dump_file, "\nReached the inline-unit-growth limit.\n");
+  while ((node = fibheap_extract_min (heap)) != NULL)
+    if (!node->local.disregard_inline_limits)
+      cgraph_set_inline_failed (node, N_("--param inline-unit-growth limit reached"));
   fibheap_delete (heap);
   free (heap_node);
 }
@@ -1122,10 +1158,14 @@ cgraph_decide_inlining (void)
       for (; e; e = e->next_callee)
        {
          old_insns = overall_insns;
-         if (e->inline_call || !e->callee->local.disregard_inline_limits)
-           continue;
-         if (e->callee->output || e->callee == node)
-           continue;
+         if (!e->inline_failed || !e->callee->local.inlinable
+             || !e->callee->local.disregard_inline_limits)
+           continue;
+         if (e->callee->output || e->callee == node)
+           {
+             e->inline_failed = N_("recursive inlining");
+             continue;
+           }
          ninlined_callees =
            cgraph_inlined_callees (e->callee, inlined_callees);
          cgraph_mark_inline (node, e->callee, inlined, ninlined,
@@ -1160,7 +1200,7 @@ cgraph_decide_inlining (void)
          node = order[i];
 
          if (node->callers && !node->callers->next_caller && !node->needed
-             && node->local.inlinable && !node->callers->inline_call
+             && node->local.inlinable && node->callers->inline_failed
              && !DECL_EXTERNAL (node->decl) && !DECL_COMDAT (node->decl))
            {
              bool ok = true;
@@ -1168,12 +1208,13 @@ cgraph_decide_inlining (void)
 
              /* Verify that we won't duplicate the caller.  */
              for (node1 = node->callers->caller;
-                  node1->callers && node1->callers->inline_call
+                  node1->callers && node1->callers->inline_failed
                   && ok; node1 = node1->callers->caller)
                if (node1->callers->next_caller || node1->needed)
                  ok = false;
              if (ok)
                {
+                 const char *dummy_reason;
                  if (cgraph_dump_file)
                    fprintf (cgraph_dump_file,
                             "\nConsidering %s %i insns.\n"
@@ -1184,8 +1225,11 @@ cgraph_decide_inlining (void)
                  ninlined = cgraph_inlined_into (node->callers->caller,
                                                  inlined);
                  old_insns = overall_insns;
+
+                 /* Inlining functions once would never cause inlining warnings.  */
                  if (cgraph_check_inline_limits
-                     (node->callers->caller, node, inlined, ninlined))
+                     (node->callers->caller, node, inlined, ninlined,
+                      &dummy_reason))
                    {
                      ninlined_callees =
                        cgraph_inlined_callees (node, inlined_callees);
@@ -1245,9 +1289,16 @@ cgraph_decide_inlining_incrementally (struct cgraph_node *node)
 
   /* First of all look for always inline functions.  */
   for (e = node->callees; e; e = e->next_callee)
-    if (e->callee->local.disregard_inline_limits && !e->callee->output
-       && e->callee != node && !e->inline_call)
+    if (e->callee->local.disregard_inline_limits && e->inline_failed
+       /* ??? It is possible that renaming variable removed the function body
+          in duplicate_decls. See gcc.c-torture/compile/20011119-2.c  */
+       && DECL_SAVED_TREE (e->callee->decl))
       {
+       if (e->callee->output || e->callee == node)
+         {
+           e->inline_failed = N_("recursive inlining");
+           continue;
+         }
        ninlined_callees = cgraph_inlined_callees (e->callee, inlined_callees);
        cgraph_mark_inline (node, e->callee, inlined, ninlined,
                            inlined_callees, ninlined_callees);
@@ -1259,12 +1310,19 @@ cgraph_decide_inlining_incrementally (struct cgraph_node *node)
     {
       /* Now do the automatic inlining.  */
       for (e = node->callees; e; e = e->next_callee)
-       if (e->callee->local.inlinable && !e->callee->output
-           && e->callee != node && !e->inline_call
+       if (e->callee->local.inlinable && e->inline_failed
            && cgraph_default_inline_p (e->callee)
            && cgraph_check_inline_limits (node, e->callee, inlined,
-                                          ninlined))
+                                          ninlined, &e->inline_failed)
+           && DECL_SAVED_TREE (e->callee->decl))
          {
+           /* Marking recursive function inlinine has sane semantic and thus
+              we should not warn on it.  */
+           if (e->callee->output || e->callee == node)
+             {
+               e->inline_failed = "";
+               continue;
+             }
            ninlined_callees = cgraph_inlined_callees (e->callee,
                                                       inlined_callees);
            cgraph_mark_inline (node, e->callee, inlined, ninlined,
@@ -1283,10 +1341,12 @@ cgraph_decide_inlining_incrementally (struct cgraph_node *node)
 }
 
 
-/* Return true when CALLER_DECL should be inlined into CALLEE_DECL.  */
+/* Return true when CALLER_DECL should be inlined into CALLEE_DECL.
+   When returned false and reason is non-NULL, set it to the reason
+   why the call was not inlined.  */
 
 bool
-cgraph_inline_p (tree caller_decl, tree callee_decl)
+cgraph_inline_p (tree caller_decl, tree callee_decl, const char **reason)
 {
   struct cgraph_node *caller = cgraph_node (caller_decl);
   struct cgraph_node *callee = cgraph_node (callee_decl);
@@ -1294,10 +1354,16 @@ cgraph_inline_p (tree caller_decl, tree callee_decl)
 
   for (e = caller->callees; e; e = e->next_callee)
     if (e->callee == callee)
-      return e->inline_call;
+      {
+       if (e->inline_failed && reason)
+         *reason = e->inline_failed;
+        return !e->inline_failed;
+      }
   /* We do not record builtins in the callgraph.  Perhaps it would make more
      sense to do so and then prune out those not overwritten by explicit
      function body.  */
+  if (reason)
+    *reason = "originally indirect function calls never inlined";
   return false;
 }
 /* Expand all functions that must be output.
@@ -1340,7 +1406,8 @@ cgraph_expand_all_functions (void)
 /* Mark all local functions.
 
    A local function is one whose calls can occur only in the
-   current compilation unit, so we change its calling convention.
+   current compilation unit and all it's calls are explicit,
+   so we can change its calling convention.
    We simply mark all static functions whose address is not taken
    as local.  */
 
index 55b8f03..0b82e58 100644 (file)
@@ -1,3 +1,7 @@
+2004-01-04  Jan Hubicka  <jh@suse.cz>
+
+       * gcc.dg/winline[1-7].c: New tests.
+
 2004-01-02  Kriang Lerdsuwanakij  <lerdsuwa@users.sourceforge.net>
 
        PR c++/13520
diff --git a/gcc/testsuite/gcc.dg/winline-1.c b/gcc/testsuite/gcc.dg/winline-1.c
new file mode 100644 (file)
index 0000000..ac2ae82
--- /dev/null
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-Winline -O2" } */
+
+void q(void);
+inline int t(void)
+{
+       int ret;
+       q();
+       ret = t();  /* We define sane semantics for inline keyword on recursive
+                      functions, so do not warn here.  */
+       q();
+       return ret;
+}
diff --git a/gcc/testsuite/gcc.dg/winline-2.c b/gcc/testsuite/gcc.dg/winline-2.c
new file mode 100644 (file)
index 0000000..584c68f
--- /dev/null
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-Winline -O2" } */
+
+inline int q(void);             /* { dg-warning "body not available" "" } */
+inline int t(void)
+{
+       return q();              /* { dg-warning "called from here" "" } */
+}
diff --git a/gcc/testsuite/gcc.dg/winline-3.c b/gcc/testsuite/gcc.dg/winline-3.c
new file mode 100644 (file)
index 0000000..ce9e080
--- /dev/null
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-Winline -O2 --param max-inline-insns-single=1" } */
+
+void big (void);
+inline int q(void)             
+{                              /* { dg-warning "max-inline-insns-single" "" } */
+       big();
+       big();
+       big();
+       big();
+       big();
+       big();
+       big();
+       big();
+       big();
+       big();
+}
+inline int t (void)
+{
+       return q ();             /* { dg-warning "called from here" "" } */
+}
diff --git a/gcc/testsuite/gcc.dg/winline-4.c b/gcc/testsuite/gcc.dg/winline-4.c
new file mode 100644 (file)
index 0000000..5ce0a02
--- /dev/null
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-Winline -O1 -fno-unit-at-a-time" } */
+
+inline int q(void);             /* { dg-warning "body not available" } */
+inline int t(void)
+{
+       return q();              /* { dg-warning "called from here" } */
+}
+int q(void)
+{
+}
diff --git a/gcc/testsuite/gcc.dg/winline-5.c b/gcc/testsuite/gcc.dg/winline-5.c
new file mode 100644 (file)
index 0000000..20df786
--- /dev/null
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+/* { dg-options "-Winline -O2 --param inline-unit-growth=0" } */
+
+void big (void);
+inline int q(void)              
+{                              /* { dg-warning "inline-unit-growth" } */
+       big();
+       big();
+       big();
+       big();
+       big();
+       big();
+       big();
+       big();
+       big();
+       big();
+}
+inline int q1(void)
+{
+       big();
+       big();
+       big();
+}
+int t (void)
+{
+ /* We allow one inlining over limit.  */
+       q1();
+       return q ();             /* { dg-warning "called from here" } */
+}
diff --git a/gcc/testsuite/gcc.dg/winline-6.c b/gcc/testsuite/gcc.dg/winline-6.c
new file mode 100644 (file)
index 0000000..7ce7481
--- /dev/null
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-Winline -O2 --param large-function-growth=0 --param large-function-insns=1" } */
+
+void big (void);
+inline int q(void)
+{                              /* { dg-warning "large-function-growth" } */
+       big();
+       big();
+       big();
+       big();
+       big();
+       big();
+       big();
+       big();
+       big();
+       big();
+}
+inline int t (void)
+{
+       return q ();             /* { dg-warning "called from here" } */
+}
diff --git a/gcc/testsuite/gcc.dg/winline-7.c b/gcc/testsuite/gcc.dg/winline-7.c
new file mode 100644 (file)
index 0000000..03b9517
--- /dev/null
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-Winline -O2" } */
+
+void big (void);
+inline int q(void)
+{                              /* { dg-warning "(function not inlinable|alloca)" } */
+       return (int)alloca(10);
+}
+inline int t (void)
+{
+       return q ();             /* { dg-warning "called from here" } */
+}
index 48b59a4..9d73be2 100644 (file)
@@ -1247,6 +1247,7 @@ expand_call_inline (tree *tp, int *walk_subtrees, void *data)
   splay_tree st;
   tree args;
   tree return_slot_addr;
+  const char *reason;
 
   /* See what we've got.  */
   id = (inline_data *) data;
@@ -1327,12 +1328,13 @@ expand_call_inline (tree *tp, int *walk_subtrees, void *data)
 
   /* Don't try to inline functions that are not well-suited to
      inlining.  */
-  if (!DECL_SAVED_TREE (fn) || !cgraph_inline_p (id->current_decl, fn))
+  if (!cgraph_inline_p (id->current_decl, fn, &reason))
     {
-      if (warn_inline && DECL_INLINE (fn) && DECL_DECLARED_INLINE_P (fn)
-         && !DECL_IN_SYSTEM_HEADER (fn))
+      if (warn_inline && DECL_DECLARED_INLINE_P (fn)
+         && !DECL_IN_SYSTEM_HEADER (fn)
+         && strlen (reason))
        {
-         warning ("%Jinlining failed in call to '%F'", fn, fn);
+         warning ("%Jinlining failed in call to '%F': %s", fn, fn, reason);
          warning ("called from here");
        }
       return NULL_TREE;