This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[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 ----

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]