[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