[llvm-commits] [llvm-gcc-4.2] r54191 - in /llvm-gcc-4.2/trunk/gcc/cp: class.c decl.c init.c optimize.c
Bill Wendling
isanbard at gmail.com
Tue Jul 29 18:08:37 PDT 2008
Author: void
Date: Tue Jul 29 20:08:37 2008
New Revision: 54191
URL: http://llvm.org/viewvc/llvm-project?rev=54191&view=rev
Log:
More merges with Apple's GCC 4.2
Modified:
llvm-gcc-4.2/trunk/gcc/cp/class.c
llvm-gcc-4.2/trunk/gcc/cp/decl.c
llvm-gcc-4.2/trunk/gcc/cp/init.c
llvm-gcc-4.2/trunk/gcc/cp/optimize.c
Modified: llvm-gcc-4.2/trunk/gcc/cp/class.c
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/gcc/cp/class.c?rev=54191&r1=54190&r2=54191&view=diff
==============================================================================
--- llvm-gcc-4.2/trunk/gcc/cp/class.c (original)
+++ llvm-gcc-4.2/trunk/gcc/cp/class.c Tue Jul 29 20:08:37 2008
@@ -1316,6 +1316,12 @@
TYPE_NEEDS_CONSTRUCTING (t) |= TYPE_NEEDS_CONSTRUCTING (basetype);
TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t)
|= TYPE_HAS_NONTRIVIAL_DESTRUCTOR (basetype);
+ /* APPLE LOCAL begin omit calls to empty destructors 5559195 */
+ if (CLASSTYPE_HAS_NONTRIVIAL_DESTRUCTOR_BODY (basetype)
+ || CLASSTYPE_DESTRUCTOR_NONTRIVIAL_BECAUSE_OF_BASE (basetype))
+ CLASSTYPE_DESTRUCTOR_NONTRIVIAL_BECAUSE_OF_BASE (t) = 1;
+ /* APPLE LOCAL end omit calls to empty destructors 5559195 */
+
TYPE_HAS_COMPLEX_ASSIGN_REF (t)
|= TYPE_HAS_COMPLEX_ASSIGN_REF (basetype);
TYPE_HAS_COMPLEX_INIT_REF (t) |= TYPE_HAS_COMPLEX_INIT_REF (basetype);
@@ -1474,6 +1480,13 @@
TYPE_HAS_NONTRIVIAL_DESTRUCTOR (variants)
= TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t);
+ /* APPLE LOCAL begin omit calls to empty destructors 5559195 */
+ CLASSTYPE_HAS_NONTRIVIAL_DESTRUCTOR_BODY (variants) =
+ CLASSTYPE_HAS_NONTRIVIAL_DESTRUCTOR_BODY (t);
+ CLASSTYPE_DESTRUCTOR_NONTRIVIAL_BECAUSE_OF_BASE (variants) =
+ CLASSTYPE_DESTRUCTOR_NONTRIVIAL_BECAUSE_OF_BASE (t);
+ /* APPLE LOCAL end omit calls to empty destructors 5559195 */
+
TYPE_POLYMORPHIC_P (variants) = TYPE_POLYMORPHIC_P (t);
TYPE_BINFO (variants) = TYPE_BINFO (t);
@@ -2584,6 +2597,13 @@
{
bool lazy_p = true;
+ /* APPLE LOCAL begin omit calls to empty destructors 5559195 */
+ /* Since this is an empty destructor, it can only be nontrivial
+ because one of its base classes has a destructor that must be
+ called. */
+ CLASSTYPE_DESTRUCTOR_NONTRIVIAL_BECAUSE_OF_BASE (t) = 1;
+ /* APPLE LOCAL end omit calls to empty destructors 5559195 */
+
if (TYPE_FOR_JAVA (t))
/* If this a Java class, any non-trivial destructor is
invalid, even if compiler-generated. Therefore, if the
@@ -3773,7 +3793,16 @@
}
/* All user-declared destructors are non-trivial. */
if (DECL_DESTRUCTOR_P (x))
- TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) = 1;
+ /* APPLE LOCAL begin omit calls to empty destructors 5559195 */
+ {
+ TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) = 1;
+
+ /* Conservatively assume that destructor body is nontrivial. Will
+ be unmarked during parsing of function body if it happens to be
+ trivial. */
+ CLASSTYPE_HAS_NONTRIVIAL_DESTRUCTOR_BODY (t) = 1;
+ }
+ /* APPLE LOCAL end omit calls to empty destructors 5559195 */
}
}
Modified: llvm-gcc-4.2/trunk/gcc/cp/decl.c
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/gcc/cp/decl.c?rev=54191&r1=54190&r2=54191&view=diff
==============================================================================
--- llvm-gcc-4.2/trunk/gcc/cp/decl.c (original)
+++ llvm-gcc-4.2/trunk/gcc/cp/decl.c Tue Jul 29 20:08:37 2008
@@ -2464,6 +2464,39 @@
return check_previous_goto_1 (NULL_TREE, level, level->names, false, NULL);
}
+/* APPLE LOCAL begin blocks 6040305 (cp) */
+/* This routine issues a diagnostic if a __block variable is seen in
+ the current scope. This is for now called from a goto statement. */
+void
+diagnose_byref_var_in_current_scope (void)
+{
+#if 0
+ /* FIXME finish this off. */
+ struct c_scope *scope;
+ struct c_binding *b;
+
+ gcc_assert (current_scope);
+ if (flag_objc_gc_only || !current_scope->byref_in_current_scope)
+ return;
+
+ scope = current_scope;
+ while (scope && scope != file_scope)
+ {
+ for (b = scope->bindings; b; b = b->prev)
+ {
+ tree p = b->decl;
+ if (p && TREE_CODE (p) == VAR_DECL && COPYABLE_BYREF_LOCAL_VAR (p)) {
+ error ("local byref variable %s is in the scope of this goto",
+ IDENTIFIER_POINTER (DECL_NAME (p)));
+ return;
+ }
+ }
+ scope = scope->outer;
+ }
+#endif
+}
+/* APPLE LOCAL begin blocks 6040305 (cp) */
+
/* Check that a new jump to a label DECL is OK. Called by
finish_goto_stmt. */
@@ -2474,6 +2507,10 @@
bool saw_catch = false, identified = false;
tree bad;
+ /* APPLE LOCAL begin 6040305 */
+ diagnose_byref_var_in_current_scope ();
+ /* APPLE LOCAL end 6040305 */
+
/* We can't know where a computed goto is jumping.
So we assume that it's OK. */
if (TREE_CODE (decl) != LABEL_DECL)
@@ -4049,18 +4086,6 @@
DECL_DLLIMPORT_P (decl) = 0;
}
- /* APPLE LOCAL begin mainline 2005-10-12 */
- /* Dllimported symbols cannot be defined. Static data members (which
- can be initialized in-class and dllimported) go through grokfield,
- not here, so we don't need to exclude those decls when checking for
- a definition. */
- if (initialized && DECL_DLLIMPORT_P (decl))
- {
- error ("definition of %q#D is marked %<dllimport%>", decl);
- DECL_DLLIMPORT_P (decl) = 0;
- }
- /* APPLE LOCAL end mainline 2005-10-12 */
-
/* If #pragma weak was used, mark the decl weak now. */
maybe_apply_pragma_weak (decl);
@@ -5889,6 +5914,16 @@
&& TYPE_HAS_TRIVIAL_DESTRUCTOR (TREE_TYPE (decl)))
return;
+ /* APPLE LOCAL begin radar 5733674 */
+ if (c_dialect_objc () && flag_objc_gc && init && TREE_CODE (init) == INIT_EXPR)
+ {
+ tree result = objc_generate_write_barrier (TREE_OPERAND (init, 0),
+ INIT_EXPR, TREE_OPERAND (init, 1));
+ if (result)
+ init = result;
+ }
+ /* APPLE LOCAL end radar 5733674 */
+
if (DECL_FUNCTION_SCOPE_P (decl))
{
/* Emit code to perform this initialization but once. */
@@ -7384,6 +7419,8 @@
case cdk_pointer:
case cdk_reference:
case cdk_ptrmem:
+ /* APPLE LOCAL blocks 6040305 */
+ case cdk_block_pointer:
break;
case cdk_error:
@@ -8079,6 +8116,33 @@
ctype = NULL_TREE;
break;
+ /* APPLE LOCAL begin blocks 6040305 (cj) */
+ case cdk_block_pointer:
+ if (TREE_CODE (type) != FUNCTION_TYPE)
+ {
+ error ("block pointer to non-function type is invalid");
+ type = error_mark_node;
+ }
+ else
+ {
+ /* We now know that the TYPE_QUALS don't apply to the decl,
+ but to the target of the pointer. */
+ type_quals = TYPE_UNQUALIFIED;
+
+ type = build_block_pointer_type (type);
+
+ if (declarator->u.pointer.qualifiers)
+ {
+ type
+ = cp_build_qualified_type (type,
+ declarator->u.pointer.qualifiers);
+ type_quals = cp_type_quals (type);
+ }
+ }
+ ctype = NULL_TREE;
+ break;
+ /* APPLE LOCAL end blocks 6040305 (cj) */
+
case cdk_error:
break;
@@ -11868,8 +11932,28 @@
{
tree type = TREE_TYPE (decl);
- if (type != error_mark_node && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
+ /* APPLE LOCAL begin omit calls to empty destructors 5559195 */
+ tree dtor = NULL_TREE;
+ bool build_cleanup = false;
+
+ if (TREE_CODE (type) == RECORD_TYPE)
+ dtor = CLASSTYPE_DESTRUCTORS (type);
+
+ if (type != error_mark_node)
+ {
+ if (TREE_CODE (type) == RECORD_TYPE)
+ /* For RECORD_TYPEs, we can refer to more precise flags than
+ TYPE_HAS_NONTRIVIAL_DESTRUCTOR. */
+ build_cleanup = (dtor && TREE_PRIVATE (dtor))
+ || CLASSTYPE_HAS_NONTRIVIAL_DESTRUCTOR_BODY (type)
+ || CLASSTYPE_DESTRUCTOR_NONTRIVIAL_BECAUSE_OF_BASE (type);
+ else
+ build_cleanup = TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type);
+ }
+
+ if (build_cleanup)
{
+ /* APPLE LOCAL end omit calls to empty destructors 5559195 */
int flags = LOOKUP_NORMAL|LOOKUP_DESTRUCTOR;
tree rval;
bool has_vbases = (TREE_CODE (type) == RECORD_TYPE
Modified: llvm-gcc-4.2/trunk/gcc/cp/init.c
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/gcc/cp/init.c?rev=54191&r1=54190&r2=54191&view=diff
==============================================================================
--- llvm-gcc-4.2/trunk/gcc/cp/init.c (original)
+++ llvm-gcc-4.2/trunk/gcc/cp/init.c Tue Jul 29 20:08:37 2008
@@ -2921,7 +2921,13 @@
for (binfo = TYPE_BINFO (current_class_type), i = 0;
BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
{
- if (TYPE_HAS_TRIVIAL_DESTRUCTOR (BINFO_TYPE (base_binfo))
+ /* APPLE LOCAL begin omit calls to empty destructors 5559195 */
+ tree dtor = CLASSTYPE_DESTRUCTORS (BINFO_TYPE (base_binfo));
+
+ if ((!CLASSTYPE_DESTRUCTOR_NONTRIVIAL_BECAUSE_OF_BASE (BINFO_TYPE (base_binfo))
+ && !CLASSTYPE_HAS_NONTRIVIAL_DESTRUCTOR_BODY (BINFO_TYPE (base_binfo))
+ && !(dtor && (TREE_PRIVATE (dtor))))
+ /* APPLE LOCAL end omit calls to empty destructors 5559195 */
|| BINFO_VIRTUAL_P (base_binfo))
continue;
@@ -2951,6 +2957,12 @@
LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_NORMAL,
0);
finish_decl_cleanup (NULL_TREE, expr);
+
+ /* APPLE LOCAL begin omit calls to empty destructors 5559195 */
+ /* Even if body of current class's destructor was found to be empty,
+ it must now be called because it must delete its members. */
+ CLASSTYPE_DESTRUCTOR_NONTRIVIAL_BECAUSE_OF_BASE (current_class_type) = 1;
+ /* APPLE LOCAL end omit calls to empty destructors 5559195 */
}
}
}
Modified: llvm-gcc-4.2/trunk/gcc/cp/optimize.c
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/gcc/cp/optimize.c?rev=54191&r1=54190&r2=54191&view=diff
==============================================================================
--- llvm-gcc-4.2/trunk/gcc/cp/optimize.c (original)
+++ llvm-gcc-4.2/trunk/gcc/cp/optimize.c Tue Jul 29 20:08:37 2008
@@ -43,13 +43,58 @@
#include "tree-dump.h"
#include "tree-gimple.h"
+/* APPLE LOCAL begin ARM structor thunks */
+/* We detect cases where two cloned structors are identical,
+ and replace the body of one by a call to the other. This
+ is normally shrunk further by the sibcall optimization later.
+
+ More could be done along these lines. Where the clones are
+ not identical, typically one consists of code identical to
+ the other one plus some additional code. It is possible
+ to replace the duplicated code with a call to the smaller
+ function.
+
+ This is primarily a space optimization. One extra unconditional
+ branch may be executed. This is cheap or free on most modern
+ hardware and is probably less important than getting the size
+ down to reduce cache and paging problems (ymmv), so the
+ optimization is done unconditionally.
+*/
+enum in_charge_use
+{
+ NO_THUNKS, /* cannot use thunks */
+ ALL_THUNKS, /* all clones are equivalent (no in-charge
+ param, or unreferenced */
+ IN_CHARGE_1, /* all uses of in-charge parm AND it with 1, so
+ clones with in-charge==0 and 2 are equivalent,
+ likewise 1 and 3 */
+ IN_CHARGE_0 /* all uses of in-charge parm test it for equality
+ with 0, so clones with in-charge==1, 2 and 3
+ are equivalent */
+};
+struct thunk_tree_walk_data
+{
+ tree in_charge_parm;
+ enum in_charge_use in_charge_use;
+};
+struct clone_info
+{
+ int next_clone;
+ tree in_charge_value[3];
+ tree clones[3];
+ enum in_charge_use which_thunks_ok;
+};
+/* APPLE LOCAL end ARM structor thunks */
+
/* Prototypes. */
static void update_cloned_parm (tree, tree, bool);
-/* 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 */
+/* APPLE LOCAL begin ARM structor thunks */
+static void thunk_body (tree, tree, tree);
+static tree examine_tree_for_in_charge_use (tree *, int *, void *);
+static enum in_charge_use compute_use_thunks (tree);
+static tree find_earlier_clone (struct clone_info *);
+/* APPLE LOCAL end ARM 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
@@ -77,81 +122,125 @@
DECL_COMPLEX_GIMPLE_REG_P (cloned_parm) = DECL_COMPLEX_GIMPLE_REG_P (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;
+/* APPLE LOCAL begin ARM structor thunks */
+/* Callback for walk_tree. We compute data->in_charge_use. */
-#ifdef ASM_MAYBE_ALIAS_BODY
- ASM_MAYBE_ALIAS_BODY (asm_out_file, fn, clone);
-#endif
- return 0;
+static tree
+examine_tree_for_in_charge_use (tree *tp, int *walk_subtrees, void *vdata)
+{
+ struct thunk_tree_walk_data *data = (struct thunk_tree_walk_data *) vdata;
+ switch (TREE_CODE (*tp))
+ {
+ case PARM_DECL:
+ if (*tp == data->in_charge_parm)
+ data->in_charge_use = NO_THUNKS;
+ return NULL;
+ case BIT_AND_EXPR:
+ if (TREE_OPERAND (*tp, 0) == data->in_charge_parm
+ && integer_onep (TREE_OPERAND (*tp, 1)))
+ {
+ *walk_subtrees = 0;
+ if (data->in_charge_use == ALL_THUNKS
+ || data->in_charge_use == IN_CHARGE_1)
+ data->in_charge_use = IN_CHARGE_1;
+ else
+ data->in_charge_use = NO_THUNKS;
+ }
+ return NULL;
+ case EQ_EXPR:
+ case NE_EXPR:
+ if (TREE_OPERAND (*tp, 0) == data->in_charge_parm
+ && integer_zerop (TREE_OPERAND (*tp, 1)))
+ {
+ *walk_subtrees = 0;
+ if (data->in_charge_use == ALL_THUNKS
+ || data->in_charge_use == IN_CHARGE_0)
+ data->in_charge_use = IN_CHARGE_0;
+ else
+ data->in_charge_use = NO_THUNKS;
+ }
+ return NULL;
+ default:
+ return NULL;
+ }
}
-/* 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)
+/* Determine which clones of FN can use the thunk implementation. */
+
+static enum in_charge_use
+compute_use_thunks (tree fn)
{
- tree call, clone, expr_stmt, fn_parm, fn_parm_typelist, last_arg, start;
- int parmno, vtt_parmno;
+ tree last_arg, fn_parm;
- /* APPLE LOCAL disable de-cloner */
- if (TRUE || TARGET_KEXTABI || flag_clone_structors)
- return 0;
+ if (DECL_HAS_VTT_PARM_P (fn))
+ return NO_THUNKS;
+
+ if (flag_apple_kext)
+ return NO_THUNKS;
- /* If we've already seen this structor, avoid re-processing it. */
- if (TREE_ASM_WRITTEN (fn))
- return 1;
+ if (flag_clone_structors)
+ return NO_THUNKS;
+
+ /* Functions that are too small will just get inlined back in anyway.
+ Let the inliner do something useful instead. */
+ if (flag_inline_functions
+ && estimate_num_insns (DECL_SAVED_TREE (fn)) < MAX_INLINE_INSNS_AUTO)
+ return NO_THUNKS;
/* 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;
+ return NO_THUNKS;
/* If constructor expects vector (AltiVec) arguments, give up. */
- for (fn_parm = DECL_ARGUMENTS( fn); fn_parm; fn_parm = TREE_CHAIN (fn_parm))
+ for (fn_parm = DECL_ARGUMENTS (fn); fn_parm; fn_parm = TREE_CHAIN (fn_parm))
if (TREE_CODE (fn_parm) == VECTOR_TYPE)
- return 0;
+ return NO_THUNKS;
- /* If we don't see a clone, nothing to do. */
- clone = TREE_CHAIN (fn);
- if (!clone || ! DECL_CLONED_FUNCTION_P (clone))
- return 0;
+ if (DECL_HAS_IN_CHARGE_PARM_P (fn))
+ {
+ int parmno;
+ struct thunk_tree_walk_data data;
+ for (parmno = 0, fn_parm = DECL_ARGUMENTS (fn);
+ fn_parm;
+ ++parmno, fn_parm = TREE_CHAIN (fn_parm))
+ if (parmno == 1)
+ {
+ data.in_charge_parm = fn_parm;
+ break;
+ }
+ /* If every use of the in-charge parameter ANDs it
+ with 1, then the functions that have in-charge
+ set to 1 and 3 are equivalent, likewise 0 and 2.
+ Check for this (common in practice). Likewise,
+ if every use tests for equality with 0, then
+ values 1, 2 and 3 are equivalent. */
+ gcc_assert (data.in_charge_parm != NULL_TREE);
+ data.in_charge_use = ALL_THUNKS;
+ walk_tree_without_duplicates (&DECL_SAVED_TREE (fn),
+ examine_tree_for_in_charge_use,
+ &data);
+ return data.in_charge_use;
+ }
- /* This is only a win if there are two or more clones. */
- if ( ! TREE_CHAIN (clone))
- return 0;
+ return ALL_THUNKS;
+}
+
+/* An earlier version of this is in Apple's 4.0 tree, and some of the
+ modifications here are in 3983462. */
- /* 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 */
+/* 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 void
+thunk_body (tree clone, tree fn, tree clone_to_call)
+{
+ tree bind, block, call, fn_parm, fn_parm_typelist;
+ int parmno, vtt_parmno;
+ tree clone_parm, parmlist;
- /* 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))
@@ -162,80 +251,108 @@
break;
}
}
+ /* Currently, we are not supposed to have a vtt argument. */
+ gcc_assert(vtt_parmno == -1);
- /* 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))
+ /* 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))
{
- tree clone_parm, parmlist;
+ 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))
+ {
+ /* Just skip it. */
+ }
+ /* 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);
+ }
- /* 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;
+ /* We built this list backwards; fix now. */
+ parmlist = nreverse (parmlist);
- /* Start processing the function. */
- push_to_top_level ();
- start_preparsed_function (clone, NULL_TREE, SF_PRE_PARSED);
+ TREE_USED (clone_to_call) = 1;
+ call = build_cxx_call (clone_to_call, parmlist);
- /* 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);
- }
+ for (parmlist = TREE_OPERAND (call, 1); parmlist; parmlist = TREE_CHAIN (parmlist))
+ {
+ fn_parm = TREE_VALUE (parmlist);
+ /* Remove the EMPTY_CLASS_EXPR because it upsets estimate_num_insns(). */
+ if (TREE_CODE (fn_parm) == COMPOUND_EXPR)
+ {
+ gcc_assert (TREE_CODE (TREE_OPERAND (fn_parm, 1)) == EMPTY_CLASS_EXPR);
+ TREE_VALUE (parmlist) = TREE_OPERAND (fn_parm, 0);
+ }
+ }
+ block = make_node (BLOCK);
+ if (targetm.cxx.cdtor_returns_this ())
+ {
+ tree clone_result = DECL_RESULT (clone);
+ tree modify = build2 (MODIFY_EXPR, TREE_TYPE (clone_result), clone_result, call);
+ add_stmt (modify);
+ BLOCK_VARS (block) = clone_result;
+ }
+ else
+ {
+ add_stmt (call);
+ }
+ bind = c_build_bind_expr (block, cur_stmt_list);
+ DECL_SAVED_TREE (clone) = push_stmt_list ();
+ add_stmt (bind);
+}
- /* 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);
+/* Determine whether the current clone (the one indexed by
+ INFO->NEXT_CLONE) can be implemented by a call to an
+ earlier (already emitted) clone. */
- /* 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;
+static tree
+find_earlier_clone (struct clone_info* info)
+{
+ int i;
+
+ if (info->which_thunks_ok == NO_THUNKS
+ || info->next_clone == 0)
+ return NULL_TREE;
+
+ if (info->which_thunks_ok == ALL_THUNKS)
+ return info->clones [0];
+
+ if (info->which_thunks_ok == IN_CHARGE_1)
+ for (i = 0; i < info->next_clone; i++)
+ if ((TREE_INT_CST_LOW (info->in_charge_value [i]) & 1)
+ == (TREE_INT_CST_LOW (info->in_charge_value [info->next_clone]) & 1))
+ return info->clones [i];
+
+ if (info->which_thunks_ok == IN_CHARGE_0)
+ for (i = 0; i < info->next_clone; i++)
+ if ((TREE_INT_CST_LOW (info->in_charge_value [i]) == 0)
+ == (TREE_INT_CST_LOW (info->in_charge_value [info->next_clone]) == 0))
+ return info->clones [i];
+
+ return NULL_TREE;
}
-/* APPLE LOCAL end structor thunks */
+/* APPLE LOCAL end ARM 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
@@ -246,6 +363,10 @@
{
tree clone;
bool first = true;
+/* APPLE LOCAL begin ARM structor thunks */
+ tree clone_to_call;
+ struct clone_info info;
+/* APPLE LOCAL end ARM structor thunks */
/* We only clone constructors and destructors. */
if (!DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (fn)
@@ -255,6 +376,13 @@
/* Emit the DWARF1 abstract instance. */
(*debug_hooks->deferred_inline_function) (fn);
+/* APPLE LOCAL begin ARM structor thunks */
+ /* Figure out whether we can use the 'thunk' implementation,
+ and if so on which clones. */
+ info.next_clone = 0;
+ info.which_thunks_ok = compute_use_thunks (fn);
+/* APPLE LOCAL end ARM structor thunks */
+
/* We know that any clones immediately follow FN in the TYPE_METHODS
list. */
push_to_top_level ();
@@ -262,8 +390,8 @@
{
tree parm;
tree clone_parm;
- /* APPLE LOCAL structor thunks */
- /* Delete some local variables. */
+ int parmno;
+ splay_tree decl_map;
/* Update CLONE's source position information to match FN's. */
DECL_SOURCE_LOCATION (clone) = DECL_SOURCE_LOCATION (fn);
@@ -298,28 +426,6 @@
parm = TREE_CHAIN (parm), clone_parm = TREE_CHAIN (clone_parm))
/* Update this parameter. */
update_cloned_parm (parm, clone_parm, first);
- /* 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);
@@ -341,6 +447,8 @@
splay_tree_insert (decl_map,
(splay_tree_key) parm,
(splay_tree_value) in_charge);
+ /* APPLE LOCAL ARM structor thunks */
+ info.in_charge_value [info.next_clone] = in_charge;
}
else if (DECL_ARTIFICIAL (parm)
&& DECL_NAME (parm) == vtt_parm_identifier)
@@ -382,11 +490,16 @@
splay_tree_insert (decl_map, (splay_tree_key) parm,
(splay_tree_value) clone_parm);
}
- /* Clone the body. */
- clone_body (clone, fn, decl_map);
-
- /* Clean up. */
- splay_tree_delete (decl_map);
+ /* APPLE LOCAL begin ARM structor thunks */
+ clone_to_call = find_earlier_clone (&info);
+ if (clone_to_call)
+ /* Bodies are identical; replace later one with call to an
+ earlier one. */
+ thunk_body (clone, fn, clone_to_call);
+ else
+ /* Clone the body. */
+ clone_body (clone, fn, decl_map);
+ /* APPLE LOCAL end ARM structor thunks */
/* The clone can throw iff the original function can throw. */
cp_function_chain->can_throw = !TREE_NOTHROW (fn);
@@ -396,6 +509,10 @@
BLOCK_ABSTRACT_ORIGIN (DECL_INITIAL (clone)) = DECL_INITIAL (fn);
expand_or_defer_fn (clone);
first = false;
+ /* APPLE LOCAL begin ARM structor thunks */
+ info.clones [info.next_clone] = clone;
+ info.next_clone++;
+ /* APPLE LOCAL end ARM structor thunks */
}
pop_from_top_level ();
More information about the llvm-commits
mailing list