From f08545a8f225fe7adfbfab9a652bb8c325494d3c Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Thu, 11 Sep 2003 01:45:05 +0200 Subject: [PATCH] c-objc-common.c (c_cannot_inline_tree_fn): Warn on why function is not inlinable; do not check the body. * 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 | 12 +++ gcc/c-objc-common.c | 154 +++++++++------------------------- gcc/tree-inline.c | 196 ++++++++++++++++++++++++++++++-------------- 3 files changed, 184 insertions(+), 178 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 350d0e513e2..3a68a0515cd 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,15 @@ +Thu Sep 11 01:21:05 CEST 2003 Jan Hubicka + + * 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 * cgraph.h (struct cgraph_node): Rename lowered to analyzed. diff --git a/gcc/c-objc-common.c b/gcc/c-objc-common.c index 96d6855f303..172346b2aec 100644 --- a/gcc/c-objc-common.c +++ b/gcc/c-objc-common.c @@ -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: diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index 8893b26236a..43e98483089 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -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; -- 2.30.2