diff options
Diffstat (limited to 'gcc/cp/optimize.c')
-rw-r--r-- | gcc/cp/optimize.c | 190 |
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 (); |