c-objc-common.c (c_cannot_inline_tree_fn): Warn on why function is not inlinable...
authorJan Hubicka <jh@suse.cz>
Wed, 10 Sep 2003 23:45:05 +0000 (01:45 +0200)
committerJan Hubicka <hubicka@gcc.gnu.org>
Wed, 10 Sep 2003 23:45:05 +0000 (23:45 +0000)
* c-objc-common.c (c_cannot_inline_tree_fn): Warn
on why function is not inlinable; do not check
the body.
(inline_forbidden_p): Move to...
* tree-inline.c (inline_forbidden_p_1): ... here; Add warnings;
deal with alloca, longjmp.
(inline_forbidden_p): New static function.
(find_alloca_call_1, find_alloca_call, find_builtin_longjmp_call_1,
find_builtin_longjmp_call): Kill.

From-SVN: r71283

gcc/ChangeLog
gcc/c-objc-common.c
gcc/tree-inline.c

index 350d0e513e211e7d81d5db6f02aab1d181486a49..3a68a0515cd77fde09c506b8fedbefe4b2bb1423 100644 (file)
@@ -1,3 +1,15 @@
+Thu Sep 11 01:21:05 CEST 2003  Jan Hubicka  <jh@suse.cz>
+
+       * c-objc-common.c (c_cannot_inline_tree_fn): Warn
+       on why function is not inlinable; do not check
+       the body.
+       (inline_forbidden_p): Move to...
+       * tree-inline.c (inline_forbidden_p_1): ... here; Add warnings;
+       deal with alloca, longjmp.
+       (inline_forbidden_p): New static function.
+       (find_alloca_call_1, find_alloca_call, find_builtin_longjmp_call_1,
+       find_builtin_longjmp_call): Kill.
+
 2003-09-10  Richard Henderson  <rth@redhat.com>
 
        * cgraph.h (struct cgraph_node): Rename lowered to analyzed.
index 96d6855f303e884062989231fd9f20a2b7f5184a..172346b2aeca5c866c588c03dc585515deed4175 100644 (file)
@@ -40,7 +40,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "cgraph.h"
 
 static bool c_tree_printer (pretty_printer *, text_info *);
-static tree inline_forbidden_p (tree *, int *, void *);
 static tree start_cdtor (int);
 static void finish_cdtor (tree);
 
@@ -65,110 +64,45 @@ c_disregard_inline_limits (tree fn)
   return DECL_DECLARED_INLINE_P (fn) && DECL_EXTERNAL (fn);
 }
 
-static tree
-inline_forbidden_p (tree *nodep, int *walk_subtrees ATTRIBUTE_UNUSED,
-                   void *fn)
-{
-  tree node = *nodep;
-  tree t;
-
-  switch (TREE_CODE (node))
-    {
-    case CALL_EXPR:
-      t = get_callee_fndecl (node);
-
-      if (! t)
-       break;
-
-      /* We cannot inline functions that call setjmp.  */
-      if (setjmp_call_p (t))
-       return node;
-
-      switch (DECL_FUNCTION_CODE (t))
-       {
-         /* We cannot inline functions that take a variable number of
-            arguments.  */
-       case BUILT_IN_VA_START:
-       case BUILT_IN_STDARG_START:
-#if 0
-         /* Functions that need information about the address of the
-             caller can't (shouldn't?) be inlined.  */
-       case BUILT_IN_RETURN_ADDRESS:
-#endif
-         return node;
-
-       default:
-         break;
-       }
-
-      break;
-
-    case DECL_STMT:
-      /* We cannot inline functions that contain other functions.  */
-      if (TREE_CODE (TREE_OPERAND (node, 0)) == FUNCTION_DECL
-         && DECL_INITIAL (TREE_OPERAND (node, 0)))
-       return node;
-      break;
-
-    case GOTO_STMT:
-    case GOTO_EXPR:
-      t = TREE_OPERAND (node, 0);
-
-      /* We will not inline a function which uses computed goto.  The
-        addresses of its local labels, which may be tucked into
-        global storage, are of course not constant across
-        instantiations, which causes unexpected behavior.  */
-      if (TREE_CODE (t) != LABEL_DECL)
-       return node;
-
-      /* We cannot inline a nested function that jumps to a nonlocal
-         label.  */
-      if (TREE_CODE (t) == LABEL_DECL
-         && !DECL_FILE_SCOPE_P (t) && DECL_CONTEXT (t) != fn)
-       return node;
-
-      break;
-
-    case RECORD_TYPE:
-    case UNION_TYPE:
-      /* We cannot inline a function of the form
-
-          void F (int i) { struct S { int ar[i]; } s; }
-
-        Attempting to do so produces a catch-22 in tree-inline.c.
-        If walk_tree examines the TYPE_FIELDS chain of RECORD_TYPE/
-        UNION_TYPE nodes, then it goes into infinite recursion on a
-        structure containing a pointer to its own type.  If it doesn't,
-        then the type node for S doesn't get adjusted properly when
-        F is inlined, and we abort in find_function_data.  */
-      for (t = TYPE_FIELDS (node); t; t = TREE_CHAIN (t))
-       if (variably_modified_type_p (TREE_TYPE (t)))
-         return node;
-
-    default:
-      break;
-    }
-
-  return NULL_TREE;
-}
-
 int
 c_cannot_inline_tree_fn (tree *fnp)
 {
   tree fn = *fnp;
   tree t;
+  bool do_warning = (warn_inline
+                    && DECL_INLINE (fn)
+                    && DECL_DECLARED_INLINE_P (fn)
+                    && !DECL_IN_SYSTEM_HEADER (fn));
 
   if (flag_really_no_inline
       && lookup_attribute ("always_inline", DECL_ATTRIBUTES (fn)) == NULL)
-    return 1;
+    {
+      if (do_warning)
+       warning ("%Hfunction '%F' can never be inlined because it "
+                "is supressed using -fno-inline",
+                &DECL_SOURCE_LOCATION (fn), fn);
+      goto cannot_inline;
+    }
 
   /* Don't auto-inline anything that might not be bound within
      this unit of translation.  */
   if (!DECL_DECLARED_INLINE_P (fn) && !(*targetm.binds_local_p) (fn))
-    goto cannot_inline;
+    {
+      if (do_warning)
+       warning ("%Hfunction '%F' can never be inlined because it might not "
+                "be bound within this unit of translation",
+                &DECL_SOURCE_LOCATION (fn), fn);
+      goto cannot_inline;
+    }
 
   if (! function_attribute_inlinable_p (fn))
-    goto cannot_inline;
+    {
+      if (do_warning)
+       warning ("%Hfunction '%F' can never be inlined because it uses "
+                "attributes conflicting with inlining",
+                &DECL_SOURCE_LOCATION (fn), fn);
+      goto cannot_inline;
+    }
 
   /* If a function has pending sizes, we must not defer its
      compilation, and we can't inline it as a tree.  */
@@ -178,7 +112,13 @@ c_cannot_inline_tree_fn (tree *fnp)
       put_pending_sizes (t);
 
       if (t)
-       goto cannot_inline;
+       {
+         if (do_warning)
+           warning ("%Hfunction '%F' can never be inlined because it has "
+                    "pending sizes",
+                    &DECL_SOURCE_LOCATION (fn), fn);
+         goto cannot_inline;
+       }
     }
 
   if (! DECL_FILE_SCOPE_P (fn))
@@ -186,31 +126,15 @@ c_cannot_inline_tree_fn (tree *fnp)
       /* If a nested function has pending sizes, we may have already
          saved them.  */
       if (DECL_LANG_SPECIFIC (fn)->pending_sizes)
-       goto cannot_inline;
-    }
-  else
-    {
-      /* We rely on the fact that this function is called upfront,
-        just before we start expanding a function.  If FN is active
-        (i.e., it's the current_function_decl or a parent thereof),
-        we have to walk FN's saved tree.  Otherwise, we can safely
-        assume we have done it before and, if we didn't mark it as
-        uninlinable (in which case we wouldn't have been called), it
-        is inlinable.  Unfortunately, this strategy doesn't work for
-        nested functions, because they're only expanded as part of
-        their enclosing functions, so the inlinability test comes in
-        late.  */
-      t = current_function_decl;
-
-      while (t && t != fn)
-       t = DECL_CONTEXT (t);
-      if (! t)
-       return 0;
+       {
+         if (do_warning)
+           warning ("%Hnested function '%F' can never be inlined because it "
+                    "has possibly saved pending sizes",
+                    &DECL_SOURCE_LOCATION (fn), fn);
+         goto cannot_inline;
+       }
     }
 
-  if (walk_tree (&DECL_SAVED_TREE (fn), inline_forbidden_p, fn, NULL))
-    goto cannot_inline;
-
   return 0;
 
  cannot_inline:
index 8893b26236ab24b39aece29db00d76a2938c7e88..43e98483089fe68d364d192623ef6bf0a9ede6cd 100644 (file)
@@ -128,10 +128,6 @@ static tree initialize_inlined_parameters (inline_data *, tree, tree, tree);
 static void remap_block (tree *, tree, inline_data *);
 static tree add_stmt_to_compound (tree, tree, tree);
 #endif /* INLINER_FOR_JAVA */
-static tree find_alloca_call_1 (tree *, int *, void *);
-static tree find_alloca_call (tree);
-static tree find_builtin_longjmp_call_1 (tree *, int *, void *);
-static tree find_builtin_longjmp_call (tree);
 
 /* Remap DECL during the copying of the BLOCK tree for the function.  */
 
@@ -880,50 +876,148 @@ tree_inlinable_function_p (tree fn)
   return inlinable_function_p (fn);
 }
 
-/* If *TP is possibly call to alloca, return nonzero.  */
-static tree
-find_alloca_call_1 (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
-                   void *data ATTRIBUTE_UNUSED)
-{
-  if (alloca_call_p (*tp))
-    return *tp;
-  return NULL;
-}
+static const char *inline_forbidden_reason;
 
-/* Return subexpression representing possible alloca call, if any.  */
 static tree
-find_alloca_call (tree exp)
+inline_forbidden_p_1 (tree *nodep, int *walk_subtrees ATTRIBUTE_UNUSED,
+                   void *fn)
 {
-  location_t saved_loc = input_location;
-  tree ret = walk_tree_without_duplicates
-               (&exp, find_alloca_call_1, NULL);
-  input_location = saved_loc;
-  return ret;
-}
+  tree node = *nodep;
+  tree t;
 
-static tree
-find_builtin_longjmp_call_1 (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
-                            void *data ATTRIBUTE_UNUSED)
-{
-  tree exp = *tp, decl;
+  switch (TREE_CODE (node))
+    {
+    case CALL_EXPR:
+      /* Refuse to inline alloca call unless user explicitly forced so as this
+        may change program's memory overhead drastically when the function
+        using alloca is called in loop.  In GCC present in SPEC2000 inlining
+        into schedule_block cause it to require 2GB of ram instead of 256MB.  */
+      if (alloca_call_p (node)
+         && !lookup_attribute ("always_inline", DECL_ATTRIBUTES (fn)))
+       {
+         inline_forbidden_reason = "%Hfunction '%F' can never be inlined "
+                                   "because it uses alloca (override using "
+                                   "the always_inline attribute)";
+         return node;
+       }
+      t = get_callee_fndecl (node);
+      if (! t)
+       break;
+
+
+      /* We cannot inline functions that call setjmp.  */
+      if (setjmp_call_p (t))
+       {
+         inline_forbidden_reason = "%Hfunction '%F' can never be inlined"
+                                   " because it uses setjmp";
+         return node;
+       }
 
-  if (TREE_CODE (exp) == CALL_EXPR
-      && TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR
-      && (decl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
-         TREE_CODE (decl) == FUNCTION_DECL)
-      && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL
-      && DECL_FUNCTION_CODE (decl) == BUILT_IN_LONGJMP)
-    return decl;
+      switch (DECL_FUNCTION_CODE (t))
+       {
+         /* We cannot inline functions that take a variable number of
+            arguments.  */
+       case BUILT_IN_VA_START:
+       case BUILT_IN_STDARG_START:
+         {
+           inline_forbidden_reason = "%Hfunction '%F' can never be inlined "
+                                     "because it uses variable argument lists";
+           return node;
+         }
+       case BUILT_IN_LONGJMP:
+         {
+           /* We can't inline functions that call __builtin_longjmp at all.
+              The non-local goto machinery really requires the destination
+              be in a different function.  If we allow the function calling
+              __builtin_longjmp to be inlined into the function calling
+              __builtin_setjmp, Things will Go Awry.  */
+           /* ??? Need front end help to identify "regular" non-local goto.  */
+            if (DECL_BUILT_IN_CLASS (t) == BUILT_IN_NORMAL)
+             {
+               inline_forbidden_reason = "%Hfunction '%F' can never be inlined "
+                                         "because it uses setjmp-longjmp "
+                                         "exception handling";
+               return node;
+             }
+         }
+
+       default:
+         break;
+       }
+      break;
 
-  return NULL;
+#ifndef INLINER_FOR_JAVA
+    case DECL_STMT:
+      /* We cannot inline functions that contain other functions.  */
+      if (TREE_CODE (TREE_OPERAND (node, 0)) == FUNCTION_DECL
+         && DECL_INITIAL (TREE_OPERAND (node, 0)))
+       {
+         inline_forbidden_reason = "%Hfunction '%F' can never be inlined "
+                                   "because it contains a nested function";
+         return node;
+       }
+      break;
+
+    case GOTO_STMT:
+    case GOTO_EXPR:
+      t = TREE_OPERAND (node, 0);
+
+      /* We will not inline a function which uses computed goto.  The
+        addresses of its local labels, which may be tucked into
+        global storage, are of course not constant across
+        instantiations, which causes unexpected behavior.  */
+      if (TREE_CODE (t) != LABEL_DECL)
+       {
+         inline_forbidden_reason = "%Hfunction '%F' can never be inlined "
+                                   "because it contains a nonlocal label";
+         return node;
+       }
+
+      /* We cannot inline a nested function that jumps to a nonlocal
+         label.  */
+      if (TREE_CODE (t) == LABEL_DECL && DECL_CONTEXT (t) != fn)
+       {
+         inline_forbidden_reason = "%Hfunction '%F' can never be inlined "
+                                   "because it contains a nonlocal goto";
+         return node;
+       }
+
+      break;
+
+    case RECORD_TYPE:
+    case UNION_TYPE:
+      /* We cannot inline a function of the form
+
+          void F (int i) { struct S { int ar[i]; } s; }
+
+        Attempting to do so produces a catch-22.
+        If walk_tree examines the TYPE_FIELDS chain of RECORD_TYPE/
+        UNION_TYPE nodes, then it goes into infinite recursion on a
+        structure containing a pointer to its own type.  If it doesn't,
+        then the type node for S doesn't get adjusted properly when
+        F is inlined, and we abort in find_function_data.  */
+      for (t = TYPE_FIELDS (node); t; t = TREE_CHAIN (t))
+       if (variably_modified_type_p (TREE_TYPE (t)))
+         {
+           inline_forbidden_reason = "%Hfunction '%F' can never be inlined "
+                                     "because it uses variable sized variables";
+           return node;
+         }
+#endif
+    default:
+      break;
+    }
+
+  return NULL_TREE;
 }
 
+/* Return subexpression representing possible alloca call, if any.  */
 static tree
-find_builtin_longjmp_call (tree exp)
+inline_forbidden_p (tree fndecl)
 {
   location_t saved_loc = input_location;
   tree ret = walk_tree_without_duplicates
-               (&exp, find_builtin_longjmp_call_1, NULL);
+               (&DECL_SAVED_TREE (fndecl), inline_forbidden_p_1, fndecl);
   input_location = saved_loc;
   return ret;
 }
@@ -935,8 +1029,6 @@ static bool
 inlinable_function_p (tree fn)
 {
   bool inlinable = true;
-  bool calls_builtin_longjmp = false;
-  bool calls_alloca = false;
 
   /* If we've already decided this function shouldn't be inlined,
      there's no need to check again.  */
@@ -980,24 +1072,7 @@ inlinable_function_p (tree fn)
     inlinable = false;
 #endif /* INLINER_FOR_JAVA */
 
-  /* We can't inline functions that call __builtin_longjmp at all.
-     The non-local goto machinery really requires the destination
-     be in a different function.  If we allow the function calling
-     __builtin_longjmp to be inlined into the function calling
-     __builtin_setjmp, Things will Go Awry.  */
-  /* ??? Need front end help to identify "regular" non-local goto.  */
-  else if (find_builtin_longjmp_call (DECL_SAVED_TREE (fn)))
-    calls_builtin_longjmp = true;
-
-  /* Refuse to inline alloca call unless user explicitly forced so as this
-     may change program's memory overhead drastically when the function
-     using alloca is called in loop.  In GCC present in SPEC2000 inlining
-     into schedule_block cause it to require 2GB of ram instead of 256MB.  */
-  else if (lookup_attribute ("always_inline", DECL_ATTRIBUTES (fn)) == NULL
-          && find_alloca_call (DECL_SAVED_TREE (fn)))
-    calls_alloca = true;
-
-  if (calls_builtin_longjmp || calls_alloca)
+  else if (inline_forbidden_p (fn))
     {
       /* See if we should warn about uninlinable functions.  Previously,
         some of these warnings would be issued while trying to expand
@@ -1012,13 +1087,8 @@ inlinable_function_p (tree fn)
                         && DECL_DECLARED_INLINE_P (fn)
                         && !DECL_IN_SYSTEM_HEADER (fn));
 
-      if (do_warning && calls_builtin_longjmp)
-       warning ("%Hfunction '%F' can never be inlined because it uses "
-                "setjmp-longjmp exception handling",
-                &DECL_SOURCE_LOCATION (fn), fn);
-      if (do_warning && calls_alloca)
-       warning ("%Hfunction '%F' can never be inlined because it uses "
-                "setjmp-longjmp exception handling",
+      if (do_warning)
+       warning (inline_forbidden_reason,
                 &DECL_SOURCE_LOCATION (fn), fn);
 
       inlinable = false;