aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/optimize.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp/optimize.c')
-rw-r--r--gcc/cp/optimize.c190
1 files changed, 188 insertions, 2 deletions
diff --git a/gcc/cp/optimize.c b/gcc/cp/optimize.c
index 1be4d8afdcc..a327f847a51 100644
--- a/gcc/cp/optimize.c
+++ b/gcc/cp/optimize.c
@@ -46,6 +46,10 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
static tree calls_setjmp_r (tree *, int *, void *);
static void update_cloned_parm (tree, tree);
+/* APPLE LOCAL begin structor thunks */
+static int maybe_alias_body (tree fn, tree clone);
+static int maybe_thunk_body (tree fn);
+/* APPLE LOCAL end structor thunks */
/* Called from calls_setjmp_p via walk_tree. */
@@ -96,6 +100,165 @@ update_cloned_parm (tree parm, tree cloned_parm)
DECL_SOURCE_LOCATION (cloned_parm) = DECL_SOURCE_LOCATION (parm);
}
+/* APPLE LOCAL begin structor thunks */
+/* FN is a constructor or destructor, and there are FUNCTION_DECLs cloned from it nearby.
+ If the clone and the original funciton have identical parameter lists,
+ it is a fully-degenerate (does absolutely nothing) thunk.
+ Make the clone an alias for the original function label. */
+static int
+maybe_alias_body (tree fn ATTRIBUTE_UNUSED, tree clone ATTRIBUTE_UNUSED)
+{
+ extern FILE *asm_out_file ATTRIBUTE_UNUSED;
+
+#ifdef ASM_MAYBE_ALIAS_BODY
+ ASM_MAYBE_ALIAS_BODY (asm_out_file, fn, clone);
+#endif
+ return 0;
+}
+
+/* FN is a constructor or destructor, and there are FUNCTION_DECLs
+ cloned from it nearby. Instead of cloning this body, leave it
+ alone and create tiny one-call bodies for the cloned
+ FUNCTION_DECLs. These clones are sibcall candidates, and their
+ resulting code will be very thunk-esque. */
+static int
+maybe_thunk_body (tree fn)
+{
+ tree call, clone, expr_stmt, fn_parm, fn_parm_typelist, last_arg, start;
+ int parmno, vtt_parmno;
+
+ if (flag_apple_kext || flag_clone_structors)
+ return 0;
+
+ /* If we've already seen this structor, avoid re-processing it. */
+ if (TREE_ASM_WRITTEN (fn))
+ return 1;
+
+ /* If function accepts variable arguments, give up. */
+ last_arg = tree_last (TYPE_ARG_TYPES (TREE_TYPE (fn)));
+ if ( ! VOID_TYPE_P (TREE_VALUE (last_arg)))
+ return 0;
+
+ /* If constructor expects vector (AltiVec) arguments, give up. */
+ for (fn_parm = DECL_ARGUMENTS( fn); fn_parm; fn_parm = TREE_CHAIN (fn_parm))
+ if (TREE_CODE (fn_parm) == VECTOR_TYPE)
+ return 0;
+
+ /* If we don't see a clone, nothing to do. */
+ clone = TREE_CHAIN (fn);
+ if (!clone || ! DECL_CLONED_FUNCTION_P (clone))
+ return 0;
+
+ /* This is only a win if there are two or more clones. */
+ if ( ! TREE_CHAIN (clone))
+ return 0;
+
+ /* Only thunk-ify non-trivial structors. */
+ if (DECL_ESTIMATED_INSNS (fn) < 5)
+ return 0;
+
+ /* If we got this far, we've decided to turn the clones into thunks. */
+
+ /* We're going to generate code for fn, so it is no longer "abstract." */
+ /* APPLE LOCAL begin 3271957 and 3262497 */
+ /* Leave 'abstract' bit set for unified constructs and destructors when
+ -gused is used. */
+ if (!(flag_debug_only_used_symbols
+ && DECL_DESTRUCTOR_P (fn)
+ && DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (fn))
+ && !(flag_debug_only_used_symbols
+ && DECL_CONSTRUCTOR_P (fn)
+ && DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (fn))
+ )
+ DECL_ABSTRACT (fn) = 0;
+ /* APPLE LOCAL end 3271957 and 3262497 */
+
+ /* Find the vtt_parm, if present. */
+ for (vtt_parmno = -1, parmno = 0, fn_parm = DECL_ARGUMENTS (fn);
+ fn_parm;
+ ++parmno, fn_parm = TREE_CHAIN (fn_parm))
+ {
+ if (DECL_ARTIFICIAL (fn_parm) && DECL_NAME (fn_parm) == vtt_parm_identifier)
+ {
+ vtt_parmno = parmno; /* Compensate for removed in_charge parameter. */
+ break;
+ }
+ }
+
+ /* We know that any clones immediately follow FN in the TYPE_METHODS
+ list. */
+ for (clone = start = TREE_CHAIN (fn);
+ clone && DECL_CLONED_FUNCTION_P (clone);
+ clone = TREE_CHAIN (clone))
+ {
+ tree clone_parm, parmlist;
+
+ /* If the clone and original parmlists are identical, turn the clone into an alias. */
+ if (maybe_alias_body (fn, clone))
+ continue;
+
+ /* If we've already generated a body for this clone, avoid duplicating it.
+ (Is it possible for a clone-list to grow after we first see it?) */
+ if (DECL_SAVED_TREE (clone) || TREE_ASM_WRITTEN (clone))
+ continue;
+
+ /* Start processing the function. */
+ push_to_top_level ();
+ start_function (NULL_TREE, clone, NULL_TREE, SF_PRE_PARSED);
+
+ /* Walk parameter lists together, creating parameter list for call to original function. */
+ for (parmno = 0,
+ parmlist = NULL,
+ fn_parm = DECL_ARGUMENTS (fn),
+ fn_parm_typelist = TYPE_ARG_TYPES (TREE_TYPE (fn)),
+ clone_parm = DECL_ARGUMENTS (clone);
+ fn_parm;
+ ++parmno,
+ fn_parm = TREE_CHAIN (fn_parm))
+ {
+ if (parmno == vtt_parmno && ! DECL_HAS_VTT_PARM_P (clone))
+ {
+ tree typed_null_pointer_node = copy_node (null_pointer_node);
+ my_friendly_assert (fn_parm_typelist, 0);
+ /* Clobber actual parameter with formal parameter type. */
+ TREE_TYPE (typed_null_pointer_node) = TREE_VALUE (fn_parm_typelist);
+ parmlist = tree_cons (NULL, typed_null_pointer_node, parmlist);
+ }
+ else if (parmno == 1 && DECL_HAS_IN_CHARGE_PARM_P (fn))
+ {
+ tree in_charge = copy_node (in_charge_arg_for_name (DECL_NAME (clone)));
+ parmlist = tree_cons (NULL, in_charge, parmlist);
+ }
+ /* Map other parameters to their equivalents in the cloned
+ function. */
+ else
+ {
+ my_friendly_assert (clone_parm, 0);
+ DECL_ABSTRACT_ORIGIN (clone_parm) = NULL;
+ parmlist = tree_cons (NULL, clone_parm, parmlist);
+ clone_parm = TREE_CHAIN (clone_parm);
+ }
+ if (fn_parm_typelist)
+ fn_parm_typelist = TREE_CHAIN (fn_parm_typelist);
+ }
+
+ /* We built this list backwards; fix now. */
+ parmlist = nreverse (parmlist);
+ mark_used (fn);
+ call = build_function_call (fn, parmlist);
+ expr_stmt = build_stmt (EXPR_STMT, call);
+ add_stmt (expr_stmt);
+
+ /* Now, expand this function into RTL, if appropriate. */
+ finish_function (0);
+ DECL_ABSTRACT_ORIGIN (clone) = NULL;
+ expand_body (clone);
+ pop_from_top_level ();
+ }
+ return 1;
+}
+/* APPLE LOCAL end structor thunks */
+
/* FN is a function that has a complete body. Clone the body as
necessary. Returns nonzero if there's no longer any need to
process the main body. */
@@ -121,8 +284,7 @@ maybe_clone_body (tree fn)
{
tree parm;
tree clone_parm;
- int parmno;
- splay_tree decl_map;
+ /* APPLE LOCAL structor thunks */
/* Update CLONE's source position information to match FN's. */
DECL_SOURCE_LOCATION (clone) = DECL_SOURCE_LOCATION (fn);
@@ -138,6 +300,8 @@ maybe_clone_body (tree fn)
DECL_NOT_REALLY_EXTERN (clone) = DECL_NOT_REALLY_EXTERN (fn);
TREE_PUBLIC (clone) = TREE_PUBLIC (fn);
DECL_VISIBILITY (clone) = DECL_VISIBILITY (fn);
+ /* APPLE LOCAL coalescing */
+ DECL_COALESCED (clone) = DECL_COALESCED (fn);
/* Adjust the parameter names and locations. */
parm = DECL_ARGUMENTS (fn);
@@ -156,6 +320,28 @@ maybe_clone_body (tree fn)
parm = TREE_CHAIN (parm), clone_parm = TREE_CHAIN (clone_parm))
/* Update this parameter. */
update_cloned_parm (parm, clone_parm);
+ /* APPLE LOCAL structor thunks */
+ }
+
+ /* APPLE LOCAL begin structor thunks */
+ /* If we decide to turn clones into thunks, they will branch to fn.
+ Must have original function available to call. */
+ if (maybe_thunk_body (fn))
+ return 0;
+ /* APPLE LOCAL end structor thunks */
+
+ /* APPLE LOCAL begin structor thunks */
+ /* We know that any clones immediately follow FN in the TYPE_METHODS
+ list. */
+ for (clone = TREE_CHAIN (fn);
+ clone && DECL_CLONED_FUNCTION_P (clone);
+ clone = TREE_CHAIN (clone))
+ {
+ tree parm;
+ tree clone_parm;
+ int parmno;
+ splay_tree decl_map;
+ /* APPLE LOCAL end structor thunks */
/* Start processing the function. */
push_to_top_level ();