File pr47278.diff of Package gcc43
2011-01-13 Richard Guenther <rguenther@suse.de>
PR tree-optimization/47278
* tree.h (DECL_REPLACEABLE_P): Remove.
(decl_replaceable_p): Declare.
(decl_binds_to_current_def_p): Likewise.
* varasm.c (decl_replaceable_p): New function.
(decl_binds_to_current_def_p): Likewise.
* cgraph.c (cgraph_function_body_availability): Use decl_replaceable_p.
* except.c (set_nothrow_function_flags): Likewise.
* tree-inline.c (inlinable_function_p): Likewise.
cp/
* decl.c (finish_function): Likewise.
Index: gcc/tree.h
===================================================================
*** gcc/tree.h (revision 168743)
--- gcc/tree.h (working copy)
*************** extern void decl_restrict_base_insert (t
*** 3023,3048 ****
something which is DECL_COMDAT. */
#define DECL_COMDAT(NODE) (DECL_WITH_VIS_CHECK (NODE)->decl_with_vis.comdat_flag)
- /* A replaceable function is one which may be replaced at link-time
- with an entirely different definition, provided that the
- replacement has the same type. For example, functions declared
- with __attribute__((weak)) on most systems are replaceable.
-
- COMDAT functions are not replaceable, since all definitions of the
- function must be equivalent. It is important that COMDAT functions
- not be treated as replaceable so that use of C++ template
- instantiations is not penalized.
-
- For example, DECL_REPLACEABLE is used to determine whether or not a
- function (including a template instantiation) which is not
- explicitly declared "inline" can be inlined. If the function is
- DECL_REPLACEABLE then it is not safe to do the inlining, since the
- implementation chosen at link-time may be different. However, a
- function that is not DECL_REPLACEABLE can be inlined, since all
- versions of the function will be functionally identical. */
- #define DECL_REPLACEABLE_P(NODE) \
- (!DECL_COMDAT (NODE) && !targetm.binds_local_p (NODE))
-
/* The name of the object as the assembler will see it (but before any
translations made by ASM_OUTPUT_LABELREF). Often this is the same
as DECL_NAME. It is an IDENTIFIER_NODE. */
--- 3023,3028 ----
*************** extern void process_pending_assemble_ext
*** 5067,5072 ****
--- 5047,5054 ----
extern void finish_aliases_1 (void);
extern void finish_aliases_2 (void);
extern tree emutls_decl (tree);
+ extern bool decl_replaceable_p (tree);
+ extern bool decl_binds_to_current_def_p (tree);
/* In stmt.c */
extern void expand_computed_goto (tree);
Index: gcc/varasm.c
===================================================================
*** gcc/varasm.c (revision 168743)
--- gcc/varasm.c (working copy)
*************** default_valid_pointer_mode (enum machine
*** 6257,6262 ****
--- 6257,6307 ----
return (mode == ptr_mode || mode == Pmode);
}
+ /* Return true when references to DECL must bind to current definition in
+ final executable.
+
+ The condition is usually equivalent to whether the function binds to the
+ current module (shared library or executable), that is to binds_local_p.
+ We use this fact to avoid need for another target hook and implement
+ the logic using binds_local_p and just special cases where
+ decl_binds_to_current_def_p is stronger than binds local_p. In particular
+ the weak definitions (that can be overwritten at linktime by other
+ definition from different object file) and when resolution info is available
+ we simply use the knowledge passed to us by linker plugin. */
+ bool
+ decl_binds_to_current_def_p (tree decl)
+ {
+ gcc_assert (DECL_P (decl));
+ if (!TREE_PUBLIC (decl))
+ return true;
+ if (!targetm.binds_local_p (decl))
+ return false;
+ /* Otherwise we have to assume the worst for DECL_WEAK (hidden weaks
+ binds localy but still can be overwritten).
+ This rely on fact that binds_local_p behave as decl_replaceable_p
+ for all other declaration types. */
+ return !DECL_WEAK (decl);
+ }
+
+ /* A replaceable function or variable is one which may be replaced
+ at link-time with an entirely different definition, provided that the
+ replacement has the same type. For example, functions declared
+ with __attribute__((weak)) on most systems are replaceable.
+
+ COMDAT functions are not replaceable, since all definitions of the
+ function must be equivalent. It is important that COMDAT functions
+ not be treated as replaceable so that use of C++ template
+ instantiations is not penalized. */
+
+ bool
+ decl_replaceable_p (tree decl)
+ {
+ gcc_assert (DECL_P (decl));
+ if (!TREE_PUBLIC (decl) || DECL_COMDAT (decl))
+ return false;
+ return !decl_binds_to_current_def_p (decl);
+ }
+
/* Default function to output code that will globalize a label. A
target must define GLOBAL_ASM_OP or provide its own function to
globalize a label. */
Index: gcc/cgraph.c
===================================================================
*** gcc/cgraph.c (revision 168743)
--- gcc/cgraph.c (working copy)
*************** cgraph_function_body_availability (struc
*** 1007,1021 ****
??? Does the C++ one definition rule allow us to always return
AVAIL_AVAILABLE here? That would be good reason to preserve this
! hook Similarly deal with extern inline functions - this is again
! necessary to get C++ shared functions having keyed templates
! right and in the C extension documentation we probably should
! document the requirement of both versions of function (extern
! inline and offline) having same side effect characteristics as
! good optimization is what this optimization is about. */
! else if (!(*targetm.binds_local_p) (node->decl)
! && !DECL_COMDAT (node->decl) && !DECL_EXTERNAL (node->decl))
avail = AVAIL_OVERWRITABLE;
else avail = AVAIL_AVAILABLE;
--- 1007,1015 ----
??? Does the C++ one definition rule allow us to always return
AVAIL_AVAILABLE here? That would be good reason to preserve this
! bit. */
! else if (decl_replaceable_p (node->decl) && !DECL_EXTERNAL (node->decl))
avail = AVAIL_OVERWRITABLE;
else avail = AVAIL_AVAILABLE;
Index: gcc/except.c
===================================================================
*** gcc/except.c (revision 168743)
--- gcc/except.c (working copy)
*************** set_nothrow_function_flags (void)
*** 2807,2813 ****
/* If we don't know that this implementation of the function will
actually be used, then we must not set TREE_NOTHROW, since
callers must not assume that this function does not throw. */
! if (DECL_REPLACEABLE_P (current_function_decl))
return 0;
TREE_NOTHROW (current_function_decl) = 1;
--- 2807,2813 ----
/* If we don't know that this implementation of the function will
actually be used, then we must not set TREE_NOTHROW, since
callers must not assume that this function does not throw. */
! if (decl_replaceable_p (current_function_decl))
return 0;
TREE_NOTHROW (current_function_decl) = 1;
Index: gcc/tree-inline.c
===================================================================
*** gcc/tree-inline.c (revision 168743)
--- gcc/tree-inline.c (working copy)
*************** inlinable_function_p (tree fn)
*** 2103,2109 ****
/* Don't auto-inline anything that might not be bound within
this unit of translation. */
else if (!DECL_DECLARED_INLINE_P (fn)
! && DECL_REPLACEABLE_P (fn))
inlinable = false;
else if (!function_attribute_inlinable_p (fn))
--- 2103,2109 ----
/* Don't auto-inline anything that might not be bound within
this unit of translation. */
else if (!DECL_DECLARED_INLINE_P (fn)
! && decl_replaceable_p (fn))
inlinable = false;
else if (!function_attribute_inlinable_p (fn))
Index: gcc/cp/decl.c
===================================================================
*** gcc/cp/decl.c (revision 168743)
--- gcc/cp/decl.c (working copy)
*************** finish_function (int flags)
*** 11885,11891 ****
if (!processing_template_decl
&& !cp_function_chain->can_throw
&& !flag_non_call_exceptions
! && !DECL_REPLACEABLE_P (fndecl))
TREE_NOTHROW (fndecl) = 1;
/* This must come after expand_function_end because cleanups might
--- 11885,11891 ----
if (!processing_template_decl
&& !cp_function_chain->can_throw
&& !flag_non_call_exceptions
! && !decl_replaceable_p (fndecl))
TREE_NOTHROW (fndecl) = 1;
/* This must come after expand_function_end because cleanups might
Index: gcc/testsuite/gcc.dg/torture/pr47278-1.c
===================================================================
*** gcc/testsuite/gcc.dg/torture/pr47278-1.c (revision 0)
--- gcc/testsuite/gcc.dg/torture/pr47278-1.c (revision 0)
***************
*** 0 ****
--- 1,4 ----
+ /* { dg-do run } */
+ /* { dg-additional-sources "pr47278-2.c" } */
+
+ int foo (void) { return 1; }
Index: gcc/testsuite/gcc.dg/torture/pr47278-2.c
===================================================================
*** gcc/testsuite/gcc.dg/torture/pr47278-2.c (revision 0)
--- gcc/testsuite/gcc.dg/torture/pr47278-2.c (revision 0)
***************
*** 0 ****
--- 1,13 ----
+ extern void abort (void);
+
+ int __attribute__((weak,visibility("hidden"))) foo (void)
+ {
+ return 0;
+ }
+
+ int main()
+ {
+ if (foo() != 1)
+ abort ();
+ return 0;
+ }