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 7ccfaffbf0d..06e30e5055e 100644 --- a/gcc/cp/optimize.c +++ b/gcc/cp/optimize.c @@ -46,6 +46,10 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA /* Prototypes. */ 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 */ /* CLONED_PARM is a copy of CLONE, generated for a cloned constructor or destructor. Update it to ensure that the source-position for @@ -70,6 +74,166 @@ 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; + + /* APPLE LOCAL disable de-cloner */ + if (TRUE || 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 fix -gused debug info (radar 3271957 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 */ + + /* 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_preparsed_function (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); + gcc_assert (fn_parm_typelist); + /* 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 + { + gcc_assert (clone_parm); + 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. */ @@ -94,8 +258,8 @@ maybe_clone_body (tree fn) { tree parm; tree clone_parm; - int parmno; - splay_tree decl_map; + /* APPLE LOCAL structor thunks */ + /* Delete some local variables. */ /* Update CLONE's source position information to match FN's. */ DECL_SOURCE_LOCATION (clone) = DECL_SOURCE_LOCATION (fn); @@ -130,6 +294,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. */ start_preparsed_function (clone, NULL_TREE, SF_PRE_PARSED); |