This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] fix for PR 1687, plus a small cleanup
- From: Steven Bosscher <s dot bosscher at student dot tudelft dot nl>
- To: gcc-patches at gcc dot gnu dot org
- Date: 07 May 2003 22:36:48 +0200
- Subject: [PATCH] fix for PR 1687, plus a small cleanup
Hi,
This fixes PR c/1687 for mainline, and moves a check for setjmp that was
present in C and C++ front ends to tree-inline.c.
This patch for the PR is different from the fix that was applied to the
branch because that fix slowed down things just a very tiny little bit
because we were creating three hash tables, one for each call to
walk_tree_without_duplicates. Even that very small slowdown is too much
for mainline IMO, so here's a "bigger but better" (IMHO :-) fix.
With this patch, we walk the tree with walk_tree_without_duplicates
only twice (once in tree-inline and once in the front end). In the
process, it gets rid of one extra tree walk in the C++ front end by not
looking for setjmp there anymore. Both the C and the C++ front ends had
checks for setjmp, but a call to setjmp should be deadly for the
tree-inliner with any language, so I thought that this check should go
into tree-inline.c.
I would appreciate if somebody could see if the new longjmp check is
OK. We used to check for BUILT_IN_LONGJMP; with this patch we use
special_function_p.
Bootstrapped and regtested on i586-pc-linux-gnu. OK for mainline?
Greetz
Steven
2003-05-07 Steven Bosscher <steven@gcc.gnu.org>
* c-objc-common.c (inline_forbidden_p): Don' look for
setjmp calls here. Use walk_tree_without_duplicates.
* calls.c (setjmp_call_p): Replace with...
(setjmp_longjmp_call_p): New function.
* tree.h (setjmp_call_p): Remove prototype.
(setjmp_longjmp_call_p): Add prototype.
* tree-inline.c (find_alloca_call_1, find_alloca_call,
find_builtin_longjmp_call, find_builtin_longjmp_call_1):
Remove, replaced with new functions.
(inline_inhibiting_function_call_r): New function.
(find_inline_inhibiting_function_calls): New function.
(inlinable_function_p): Don't call find_alloca_call or
find_builtin_longjmp_call. Instead, use
find_inline_inhibiting_function_calls.
* cp/cp-tree.h (calls_setjmp_p): Remove prototype.
* cp/decl.c (finish_function): Don't look for setjmp here.
* cp/optimize.c (calls_setjmp_r): Remove.
(calls_setjmp_p): Likewise.
Index: c-objc-common.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-objc-common.c,v
retrieving revision 1.24
diff -c -3 -p -r1.24 c-objc-common.c
*** c-objc-common.c 10 Apr 2003 08:07:10 -0000 1.24
--- c-objc-common.c 7 May 2003 20:10:39 -0000
*************** inline_forbidden_p (nodep, walk_subtrees
*** 87,96 ****
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
--- 87,92 ----
*************** c_cannot_inline_tree_fn (fnp)
*** 216,222 ****
return 0;
}
! if (walk_tree (&DECL_SAVED_TREE (fn), inline_forbidden_p, fn, NULL))
goto cannot_inline;
return 0;
--- 212,219 ----
return 0;
}
! if (walk_tree_without_duplicates
! (&DECL_SAVED_TREE (fn), inline_forbidden_p, fn))
goto cannot_inline;
return 0;
Index: calls.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/calls.c,v
retrieving revision 1.273
diff -c -3 -p -r1.273 calls.c
*** calls.c 3 May 2003 14:25:20 -0000 1.273
--- calls.c 7 May 2003 20:10:50 -0000
*************** special_function_p (fndecl, flags)
*** 722,734 ****
return flags;
}
! /* Return nonzero when tree represent call to longjmp. */
! int
! setjmp_call_p (fndecl)
! tree fndecl;
{
! return special_function_p (fndecl, 0) & ECF_RETURNS_TWICE;
}
/* Return true when exp contains alloca call. */
--- 722,741 ----
return flags;
}
! /* Return nonzero when EXP represent a call to setjmp or longjmp. */
! bool
! setjmp_longjmp_call_p (exp)
! tree exp;
{
! if (TREE_CODE (exp) == CALL_EXPR
! && TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR
! && (TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
! == FUNCTION_DECL)
! && (special_function_p (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
! 0) & (ECF_RETURNS_TWICE | ECF_LONGJMP)))
! return true;
! return false;
}
/* Return true when exp contains alloca call. */
Index: tree-inline.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-inline.c,v
retrieving revision 1.58
diff -c -3 -p -r1.58 tree-inline.c
*** tree-inline.c 3 May 2003 13:28:33 -0000 1.58
--- tree-inline.c 7 May 2003 20:10:53 -0000
*************** static tree initialize_inlined_parameter
*** 126,135 ****
static void remap_block PARAMS ((tree *, tree, inline_data *));
static tree add_stmt_to_compound PARAMS ((tree, tree, tree));
#endif /* INLINER_FOR_JAVA */
! static tree find_alloca_call_1 PARAMS ((tree *, int *, void *));
! static tree find_alloca_call PARAMS ((tree));
! static tree find_builtin_longjmp_call_1 PARAMS ((tree *, int *, void *));
! static tree find_builtin_longjmp_call PARAMS ((tree));
/* The approximate number of instructions per statement. This number
need not be particularly accurate; it is used only to make
--- 126,133 ----
static void remap_block PARAMS ((tree *, tree, inline_data *));
static tree add_stmt_to_compound PARAMS ((tree, tree, tree));
#endif /* INLINER_FOR_JAVA */
! static tree inline_inhibiting_function_call_r PARAMS ((tree *, int *, void *));
! static tree find_inline_inhibiting_function_calls PARAMS ((tree));
/* The approximate number of instructions per statement. This number
need not be particularly accurate; it is used only to make
*************** tree_inlinable_function_p (fn, nolimit)
*** 883,936 ****
return inlinable_function_p (fn, NULL, nolimit);
}
! /* If *TP is possibly call to alloca, return nonzero. */
! static tree
! find_alloca_call_1 (tp, walk_subtrees, data)
! tree *tp;
! int *walk_subtrees ATTRIBUTE_UNUSED;
! void *data ATTRIBUTE_UNUSED;
! {
! if (alloca_call_p (*tp))
! return *tp;
! return NULL;
! }
- /* Return subexpression representing possible alloca call, if any. */
static tree
! find_alloca_call (exp)
! tree exp;
! {
! location_t saved_loc = input_location;
! tree ret = walk_tree (&exp, find_alloca_call_1, NULL, NULL);
! input_location = saved_loc;
! return ret;
! }
!
! static tree
! find_builtin_longjmp_call_1 (tp, walk_subtrees, data)
tree *tp;
int *walk_subtrees ATTRIBUTE_UNUSED;
! void *data ATTRIBUTE_UNUSED;
{
! tree exp = *tp, decl;
! 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;
! return NULL;
}
static tree
! find_builtin_longjmp_call (exp)
! tree exp;
{
location_t saved_loc = input_location;
! tree ret = walk_tree (&exp, find_builtin_longjmp_call_1, NULL, NULL);
input_location = saved_loc;
return ret;
}
--- 881,952 ----
return inlinable_function_p (fn, NULL, nolimit);
}
! /* Return nonzero if *TP is possibly call to an inlining
! inhibiting function.
! If DATA is zero, we do not check for alloca calls. */
static tree
! inline_inhibiting_function_call_r (tp, walk_subtrees, data)
tree *tp;
int *walk_subtrees ATTRIBUTE_UNUSED;
! void *data;
{
! tree exp = *tp;
!
! /* If *TP is not a CALL_EXPR, return at once. */
! if (TREE_CODE (exp) != CALL_EXPR)
! return NULL_TREE;
! /* Calls to setjmp and longjmp are never OK. */
! if (setjmp_longjmp_call_p (exp))
! return exp;
!
! /* Check for alloca calls unless we're told not to. */
! if (data && alloca_call_p (exp))
! return exp;
! return NULL_TREE;
}
+ /* Return nonzero if there is a call in FN to a function that prevents
+ FN from being inlinable. The functions we check for are setjpm,
+ longjmp, and all variants of those.
+
+ 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.
+
+ Similarly, if this is a call to `setjmp' the containing tree cannot
+ be inlined. When `longjmp' is called it is not guaranteed to
+ restore the value of local variables that have been modified since
+ the call to `setjmp'. So, if were to inline a function into some
+ called `c', then when we `longjmp', we might not restore all
+ variables in `c'. (It might seem, at first blush, that there's no
+ way for this function to modify local variables in `c', but their
+ addresses may have been stored somewhere accessible to this
+ function.)
+
+ NB: We need front end help to identify "regular" non-local gotos,
+ so checks for that should go into the cannot_inline_tree_fn
+ langhook.
+
+ Also 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. */
+
static tree
! find_inline_inhibiting_function_calls (fn)
! tree fn;
{
location_t saved_loc = input_location;
! tree fnbody = DECL_SAVED_TREE (fn);
! tree check_alloca = lookup_attribute ("always_inline", DECL_ATTRIBUTES (fn));
! tree ret = walk_tree_without_duplicates
! (&fnbody, inline_inhibiting_function_call_r, check_alloca);
input_location = saved_loc;
return ret;
}
*************** inlinable_function_p (fn, id, nolimit)
*** 989,1013 ****
&& ! (*lang_hooks.tree_inlining.disregard_inline_limits) (fn)
&& currfn_insns > max_inline_insns_single)
;
! /* We can't inline functions that call __builtin_longjmp at all.
! The non-local goto machenery 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)))
! ;
! /* 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)))
;
! /* All is well. We can inline this function. Traditionally, GCC
! has refused to inline functions using alloca, or functions whose
! values are returned in a PARALLEL, and a few other such obscure
! conditions. We are not equally constrained at the tree level. */
else
inlinable = 1;
--- 1005,1016 ----
&& ! (*lang_hooks.tree_inlining.disregard_inline_limits) (fn)
&& currfn_insns > max_inline_insns_single)
;
! /* We cannot inline a function if it calls setjmp or longjmp, and we
! also don't inline functions calling alloca unless we're explicitly
! told to do so. */
! else if (find_inline_inhibiting_function_calls (fn))
;
! /* All is well. We can inline this function. */
else
inlinable = 1;
Index: tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.h,v
retrieving revision 1.400
diff -c -3 -p -r1.400 tree.h
*** tree.h 2 May 2003 11:33:04 -0000 1.400
--- tree.h 7 May 2003 20:11:00 -0000
*************** extern rtx emit_line_note PARAMS ((cons
*** 3033,3039 ****
/* In calls.c */
! extern int setjmp_call_p PARAMS ((tree));
extern bool alloca_call_p PARAMS ((tree));
/* In attribs.c. */
--- 3033,3039 ----
/* In calls.c */
! extern bool setjmp_longjmp_call_p PARAMS ((tree));
extern bool alloca_call_p PARAMS ((tree));
/* In attribs.c. */
Index: cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.842
diff -c -3 -p -r1.842 cp-tree.h
*** cp/cp-tree.h 1 May 2003 14:39:37 -0000 1.842
--- cp/cp-tree.h 7 May 2003 20:11:17 -0000
*************** extern tree skip_artificial_parms_for (t
*** 3909,3915 ****
/* In optimize.c */
extern void optimize_function (tree);
- extern bool calls_setjmp_p (tree);
extern bool maybe_clone_body (tree);
/* in pt.c */
--- 3909,3914 ----
Index: cp/decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl.c,v
retrieving revision 1.1053
diff -c -3 -p -r1.1053 decl.c
*** cp/decl.c 5 May 2003 19:16:07 -0000 1.1053
--- cp/decl.c 7 May 2003 20:11:43 -0000
*************** finish_function (int flags)
*** 14084,14101 ****
if (!processing_template_decl)
save_function_data (fndecl);
- /* If this function calls `setjmp' it cannot be inlined. When
- `longjmp' is called it is not guaranteed to restore the value of
- local variables that have been modified since the call to
- `setjmp'. So, if were to inline this function into some caller
- `c', then when we `longjmp', we might not restore all variables
- in `c'. (It might seem, at first blush, that there's no way for
- this function to modify local variables in `c', but their
- addresses may have been stored somewhere accessible to this
- function.) */
- if (!processing_template_decl && calls_setjmp_p (fndecl))
- DECL_UNINLINABLE (fndecl) = 1;
-
/* Complain if there's just no return statement. */
if (warn_return_type
&& TREE_CODE (TREE_TYPE (fntype)) != VOID_TYPE
--- 14084,14089 ----
Index: cp/optimize.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/optimize.c,v
retrieving revision 1.90
diff -c -3 -p -r1.90 optimize.c
*** cp/optimize.c 22 Apr 2003 05:44:10 -0000 1.90
--- cp/optimize.c 7 May 2003 20:11:44 -0000
*************** Software Foundation, 59 Temple Place - S
*** 38,44 ****
/* Prototypes. */
- static tree calls_setjmp_r (tree *, int *, void *);
static void update_cloned_parm (tree, tree);
static void dump_function (enum tree_dump_index, tree);
--- 38,43 ----
*************** optimize_function (tree fn)
*** 76,107 ****
--function_depth;
dump_function (TDI_optimized, fn);
- }
-
- /* Called from calls_setjmp_p via walk_tree. */
-
- static tree
- calls_setjmp_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
- void *data ATTRIBUTE_UNUSED)
- {
- /* We're only interested in FUNCTION_DECLS. */
- if (TREE_CODE (*tp) != FUNCTION_DECL)
- return NULL_TREE;
-
- return setjmp_call_p (*tp) ? *tp : NULL_TREE;
- }
-
- /* Returns nonzero if FN calls `setjmp' or some other function that
- can return more than once. This function is conservative; it may
- occasionally return a nonzero value even when FN does not actually
- call `setjmp'. */
-
- bool
- calls_setjmp_p (tree fn)
- {
- return walk_tree_without_duplicates (&DECL_SAVED_TREE (fn),
- calls_setjmp_r,
- NULL) != NULL_TREE;
}
/* CLONED_PARM is a copy of CLONE, generated for a cloned constructor
--- 75,80 ----