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]

Re: [PATCH][C] Fix GNU extern inline heuristic again (fix C++ memory usage regression)


On Mon, 27 Aug 2007, Ian Lance Taylor wrote:

> Thanks.
> 
> Richard, the patch is OK.
> 
> Thanks.
> 
> Ian

This is what I applied after re-bootstrapping and testing on
x86_64-unknown-linux-gnu.

Richard.

2007-08-27  Richard Guenther  <rguenther@suse.de>

	* tree.h (DECL_DISREGARD_INLINE_LIMITS): New.
	(struct tree_function_decl): Make function_code a bitfield.
	Add disregard_inline_limits flag.
	* cgraphunit.c (cgraph_process_new_functions): Check
	DECL_DISREGARD_INLINE_LIMITS instead of disregard_inline_limits_p.
	(cgraph_preserve_function_body_p): Likewise.
	* ipa-inline.c (compute_inline_parameters): Likewise.
	* c-decl.c (finish_function): Set DECL_DISREGARD_INLINE_LIMITS
	for GNU C extern inline functions.
	(merge_decls): Merge DECL_DISREGARD_INLINE_LIMITS.
	* tree-inline.c (disregard_inline_limits_p): Remove.
	* tree-inline.h (disregard_inline_limits_p): Likewise.
	* c-common.c (handle_always_inline_attribute): Set
	DECL_DISREGARD_INLINE_LIMITS.
	* langhooks.c (add_builtin_function): Verify the function code
	fits in the bitfield.

	cp/
	* decl.c (duplicate_decls): Merge DECL_DISREGARD_INLINE_LIMITS.

Index: tree.h
===================================================================
*** tree.h.orig	2007-08-28 10:59:57.000000000 +0200
--- tree.h	2007-08-28 11:03:20.000000000 +0200
*************** struct tree_decl_non_common GTY(())
*** 3273,3278 ****
--- 3273,3285 ----
  #define DECL_DECLARED_INLINE_P(NODE) \
    (FUNCTION_DECL_CHECK (NODE)->function_decl.declared_inline_flag)
  
+ /* Nonzero in a FUNCTION_DECL that should be always inlined by the inliner
+    disregarding size and cost heuristics.  This is equivalent to using
+    the always_inline attribute without the required diagnostics if the
+    function cannot be inlined.  */
+ #define DECL_DISREGARD_INLINE_LIMITS(NODE) \
+   (FUNCTION_DECL_CHECK (NODE)->function_decl.disregard_inline_limits)
+ 
  /* For FUNCTION_DECL, this holds a pointer to a structure ("struct function")
     that describes the status of this function.  */
  #define DECL_STRUCT_FUNCTION(NODE) (FUNCTION_DECL_CHECK (NODE)->function_decl.f)
*************** struct tree_function_decl GTY(())
*** 3299,3325 ****
  {
    struct tree_decl_non_common common;
  
    /* In a FUNCTION_DECL for which DECL_BUILT_IN holds, this is
!      DECL_FUNCTION_CODE.  Otherwise unused.  */
!   enum built_in_function function_code;
  
    unsigned static_ctor_flag : 1;
    unsigned static_dtor_flag : 1;
    unsigned uninlinable : 1;
    unsigned possibly_inlined : 1;
    unsigned novops_flag : 1;
    unsigned returns_twice_flag : 1;
    unsigned malloc_flag : 1;
    unsigned pure_flag : 1;
- 
    unsigned declared_inline_flag : 1;
    unsigned regdecl_flag : 1;
    unsigned inline_flag : 1;
    unsigned no_instrument_function_entry_exit : 1;
    unsigned no_limit_stack : 1;
!   ENUM_BITFIELD(built_in_class) built_in_class : 2;
  
!   struct function *f;
  };
  
  /* For a TYPE_DECL, holds the "original" type.  (TREE_TYPE has the copy.) */
--- 3306,3338 ----
  {
    struct tree_decl_non_common common;
  
+   struct function *f;
+ 
    /* In a FUNCTION_DECL for which DECL_BUILT_IN holds, this is
!      DECL_FUNCTION_CODE.  Otherwise unused.
!      ???  The bitfield needs to be able to hold all target function
! 	  codes as well.  */
!   ENUM_BITFIELD(built_in_function) function_code : 10;
!   ENUM_BITFIELD(built_in_class) built_in_class : 2;
  
    unsigned static_ctor_flag : 1;
    unsigned static_dtor_flag : 1;
    unsigned uninlinable : 1;
    unsigned possibly_inlined : 1;
+ 
    unsigned novops_flag : 1;
    unsigned returns_twice_flag : 1;
    unsigned malloc_flag : 1;
    unsigned pure_flag : 1;
    unsigned declared_inline_flag : 1;
    unsigned regdecl_flag : 1;
    unsigned inline_flag : 1;
    unsigned no_instrument_function_entry_exit : 1;
+ 
    unsigned no_limit_stack : 1;
!   unsigned disregard_inline_limits : 1;
  
!   /* 6 bits left */
  };
  
  /* For a TYPE_DECL, holds the "original" type.  (TREE_TYPE has the copy.) */
Index: cgraphunit.c
===================================================================
*** cgraphunit.c.orig	2007-08-28 10:59:57.000000000 +0200
--- cgraphunit.c	2007-08-28 11:00:25.000000000 +0200
*************** cgraph_process_new_functions (void)
*** 381,387 ****
  	  node->local.self_insns = estimate_num_insns (fndecl,
  						       &eni_inlining_weights);
  	  node->local.disregard_inline_limits
! 	    |= disregard_inline_limits_p (fndecl);
  	  /* Inlining characteristics are maintained by the
  	     cgraph_mark_inline.  */
  	  node->global.insns = node->local.self_insns;
--- 381,387 ----
  	  node->local.self_insns = estimate_num_insns (fndecl,
  						       &eni_inlining_weights);
  	  node->local.disregard_inline_limits
! 	    |= DECL_DISREGARD_INLINE_LIMITS (fndecl);
  	  /* Inlining characteristics are maintained by the
  	     cgraph_mark_inline.  */
  	  node->global.insns = node->local.self_insns;
*************** cgraph_preserve_function_body_p (tree de
*** 1252,1258 ****
    struct cgraph_node *node;
    if (!cgraph_global_info_ready)
      return (flag_really_no_inline
! 	    ? disregard_inline_limits_p (decl)
  	    : DECL_INLINE (decl));
    /* Look if there is any clone around.  */
    for (node = cgraph_node (decl); node; node = node->next_clone)
--- 1252,1258 ----
    struct cgraph_node *node;
    if (!cgraph_global_info_ready)
      return (flag_really_no_inline
! 	    ? DECL_DISREGARD_INLINE_LIMITS (decl)
  	    : DECL_INLINE (decl));
    /* Look if there is any clone around.  */
    for (node = cgraph_node (decl); node; node = node->next_clone)
Index: ipa-inline.c
===================================================================
*** ipa-inline.c.orig	2007-08-28 10:59:57.000000000 +0200
--- ipa-inline.c	2007-08-28 11:00:25.000000000 +0200
*************** compute_inline_parameters (void)
*** 1529,1535 ****
  					       &eni_inlining_weights);
    if (node->local.inlinable && !node->local.disregard_inline_limits)
      node->local.disregard_inline_limits
!       = disregard_inline_limits_p (current_function_decl);
    if (flag_really_no_inline && !node->local.disregard_inline_limits)
      node->local.inlinable = 0;
    /* Inlining characteristics are maintained by the cgraph_mark_inline.  */
--- 1529,1535 ----
  					       &eni_inlining_weights);
    if (node->local.inlinable && !node->local.disregard_inline_limits)
      node->local.disregard_inline_limits
!       = DECL_DISREGARD_INLINE_LIMITS (current_function_decl);
    if (flag_really_no_inline && !node->local.disregard_inline_limits)
      node->local.inlinable = 0;
    /* Inlining characteristics are maintained by the cgraph_mark_inline.  */
Index: c-decl.c
===================================================================
*** c-decl.c.orig	2007-08-28 10:59:57.000000000 +0200
--- c-decl.c	2007-08-28 11:00:25.000000000 +0200
*************** merge_decls (tree newdecl, tree olddecl,
*** 1819,1824 ****
--- 1819,1829 ----
  
  	  DECL_UNINLINABLE (newdecl) = DECL_UNINLINABLE (olddecl)
  	    = (DECL_UNINLINABLE (newdecl) || DECL_UNINLINABLE (olddecl));
+ 
+ 	  DECL_DISREGARD_INLINE_LIMITS (newdecl)
+ 	    = DECL_DISREGARD_INLINE_LIMITS (olddecl)
+ 	    = (DECL_DISREGARD_INLINE_LIMITS (newdecl)
+ 	       || DECL_DISREGARD_INLINE_LIMITS (olddecl));
  	}
  
        if (DECL_BUILT_IN (olddecl))
*************** finish_function (void)
*** 6771,6776 ****
--- 6776,6786 ----
    /* Finalize the ELF visibility for the function.  */
    c_determine_visibility (fndecl);
  
+   /* For GNU C extern inline functions disregard inline limits.  */
+   if (DECL_EXTERNAL (fndecl) 
+       && DECL_DECLARED_INLINE_P (fndecl))
+     DECL_DISREGARD_INLINE_LIMITS (fndecl) = 1;
+ 
    /* Genericize before inlining.  Delay genericizing nested functions
       until their parent function is genericized.  Since finalizing
       requires GENERIC, delay that as well.  */
Index: tree-inline.c
===================================================================
*** tree-inline.c.orig	2007-08-28 10:59:57.000000000 +0200
--- tree-inline.c	2007-08-28 11:00:25.000000000 +0200
*************** inlinable_function_p (tree fn)
*** 1936,1955 ****
    return inlinable;
  }
  
- /* Return true if we shall disregard inlining limits for the function
-    FN during inlining.  */
- 
- bool
- disregard_inline_limits_p (tree fn)
- {
-   /* GNU extern inline functions are supposed to be cheap.  */
-   if (DECL_DECLARED_INLINE_P (fn)
-       && DECL_EXTERNAL (fn))
-     return true;
- 
-   return lookup_attribute ("always_inline", DECL_ATTRIBUTES (fn)) != NULL_TREE;
- }
- 
  /* Estimate the cost of a memory move.  Use machine dependent
     word size and take possible memcpy call into account.  */
  
--- 1936,1941 ----
Index: tree-inline.h
===================================================================
*** tree-inline.h.orig	2007-08-28 10:59:57.000000000 +0200
--- tree-inline.h	2007-08-28 11:00:25.000000000 +0200
*************** extern void insert_decl_map (copy_body_d
*** 130,136 ****
  
  unsigned int optimize_inline_calls (tree);
  bool tree_inlinable_function_p (tree);
- bool disregard_inline_limits_p (tree);
  tree copy_tree_r (tree *, int *, void *);
  void clone_body (tree, tree, void *);
  void save_body (tree, tree *, tree *);
--- 130,135 ----
Index: c-common.c
===================================================================
*** c-common.c.orig	2007-08-28 10:59:57.000000000 +0200
--- c-common.c	2007-08-28 11:00:25.000000000 +0200
*************** handle_always_inline_attribute (tree *no
*** 4864,4871 ****
  {
    if (TREE_CODE (*node) == FUNCTION_DECL)
      {
!       /* Do nothing else, just set the attribute.  We'll get at
! 	 it later with lookup_attribute.  */
      }
    else
      {
--- 4864,4872 ----
  {
    if (TREE_CODE (*node) == FUNCTION_DECL)
      {
!       /* Set the attribute and mark it for disregarding inline
! 	 limits.  */
!       DECL_DISREGARD_INLINE_LIMITS (*node) = 1;
      }
    else
      {
Index: cp/decl.c
===================================================================
*** cp/decl.c.orig	2007-08-28 10:59:57.000000000 +0200
--- cp/decl.c	2007-08-28 11:00:25.000000000 +0200
*************** duplicate_decls (tree newdecl, tree oldd
*** 1896,1901 ****
--- 1896,1906 ----
  
  	  DECL_UNINLINABLE (newdecl) = DECL_UNINLINABLE (olddecl)
  	    = (DECL_UNINLINABLE (newdecl) || DECL_UNINLINABLE (olddecl));
+ 
+ 	  DECL_DISREGARD_INLINE_LIMITS (newdecl)
+ 	    = DECL_DISREGARD_INLINE_LIMITS (olddecl)
+ 	    = (DECL_DISREGARD_INLINE_LIMITS (newdecl)
+ 	       || DECL_DISREGARD_INLINE_LIMITS (olddecl));
  	}
  
        /* Preserve abstractness on cloned [cd]tors.  */
Index: langhooks.c
===================================================================
*** langhooks.c.orig	2007-08-28 10:59:57.000000000 +0200
--- langhooks.c	2007-08-28 11:00:25.000000000 +0200
*************** add_builtin_function (const char *name,
*** 480,485 ****
--- 480,488 ----
    TREE_PUBLIC (decl)         = 1;
    DECL_EXTERNAL (decl)       = 1;
    DECL_BUILT_IN_CLASS (decl) = cl;
+ 
+   DECL_FUNCTION_CODE (decl)  = -1;
+   gcc_assert (DECL_FUNCTION_CODE (decl) >= function_code);
    DECL_FUNCTION_CODE (decl)  = function_code;
  
    if (library_name)


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