This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
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)