Patchwork HPPA constructor merge patch, PR middle-end/45388

login
register
mail settings
Submitter John David Anglin
Date Dec. 12, 2010, 4:19 p.m.
Message ID <20101212161922.GA7838@hiauly1.hia.nrc.ca>
Download mbox | patch
Permalink /patch/75263/
State New
Headers show

Comments

John David Anglin - Dec. 12, 2010, 4:19 p.m.
The attached change reverts commit r163443.  This commit broke
constructor/destructor handling on targets using the collect2
_GLOBAL_* mechanism (e.g., 32-bit hppa*-*-hpux*).

It has now been nearly four months since the commit was made and
no progress has been made in finding a fix along the lines discussed
below.  I believe the change should be reverted to provide an
incentive to fix the issue.

With the change in place, it causes approximately 155 g++, 74 obj-c++
and 5 libgomp fails.  Thus, it is time consuming to watch for new
regressions in test runs.

The reversion is clean.  Except for the changes to ipa.c, the commit
can be directly reverted.  For ipa.c, there were some subsequent
changes to the new code but no interaction between old and new.
At this time, the change can be easily restored if a solution to
the collect2 problem is found.

The reversion has been tested on hppa2.0w-hp-hpux11.11.  It fixes
all the fails introduced in r163443.  There is one regression:
gcc.dg/ipa/ctor-empty-1.c.  This is expected.  See
http://gcc.gnu.org/ml/gcc-testresults/2010-12/msg01017.html
for test results.

Ok to commit?

On Tue, 28 Sep 2010, Jan Hubicka wrote:

> > On 09/28/2010 08:36 AM, Jan Hubicka wrote:
> > > This is bit difficult to arrange with LTO.  We produce at compile time the consturctor
> > > function with magic names, then at LTO time we want to produce single constructor function
> > > calling them all.   We would need to guess on what name is the magic name (by same logic
> > > as what collect does) and rename function back.
> > > I can definitly implement it, but it seems more hackish than the collect2 side change.
> > 
> > An alternative is that at compile time we emit
> > 
> >   _Z41__static_initialization_and_destruction_0ii
> > 
> > to the intermediate code as the constructor, and
> > 
> >   GLOBAL__I__ZN2c12f6Ev calls
> > 
> > to the object code calling _Z41.  However, we don't emit
> > GLOBAL to the intermediate code at all.  Thus when LTO 
> > replaces the object files there's no trace of the original
> > GLOBAL function at all, and thus collect2 does not see it.
> > LTO will simply see _Z41 and call that function directly.
> > 
> > This is not entirely different from the case in which we
> > have .ctor support -- it's not like we read in the piece
> > of the object code that contains the .ctor data.  Just
> > consider the GLOBAL function object file data.
> > 
> > This should be doable with a flag on the decl for GLOBAL
> > that indicates that it should not be serialized.
> 
> Or we can just produce those collected global constructors after
> serialization.  I will check...
> 
> Honza
> > 
> > 
> > r~

Dave
Mark Mitchell - Dec. 12, 2010, 6:02 p.m.
On 12/12/2010 8:19 AM, John David Anglin wrote:

> It has now been nearly four months since the commit was made and
> no progress has been made in finding a fix along the lines discussed
> below.  I believe the change should be reverted to provide an
> incentive to fix the issue.

Independent of incentives, I think that the ethos in the development
community is indeed that people fix regressions.  So, wait 24 hours, and
if the regression hasn't been fixed, go ahead and check in the reversion.

Thank you,
Jan Hubicka - Dec. 12, 2010, 7:06 p.m.
> On 12/12/2010 8:19 AM, John David Anglin wrote:
> 
> > It has now been nearly four months since the commit was made and
> > no progress has been made in finding a fix along the lines discussed
> > below.  I believe the change should be reverted to provide an
> > incentive to fix the issue.
> 
> Independent of incentives, I think that the ethos in the development
> community is indeed that people fix regressions.  So, wait 24 hours, and
> if the regression hasn't been fixed, go ahead and check in the reversion.

Hi,
We've discussed several ways of fixing the regression.  At the moment I think
it is easiest to change DECL_ASSEMBLER_NAME to be no longer recognized by
collect2 as it is simple and localized change.  It might be better to make
collect2 to not look for static symbols but I got lost on looking into that. I
will prepare patch for htat.

Honza
> 
> Thank you,
> 
> -- 
> Mark Mitchell
> CodeSourcery
> mark@codesourcery.com
> (650) 331-3385 x713

Patch

Index: tree-pass.h
===================================================================
--- tree-pass.h	(revision 167709)
+++ tree-pass.h	(working copy)
@@ -465,7 +465,6 @@ 
 extern struct ipa_opt_pass_d pass_ipa_lto_wpa_fixup;
 extern struct ipa_opt_pass_d pass_ipa_lto_finish_out;
 extern struct ipa_opt_pass_d pass_ipa_profile;
-extern struct ipa_opt_pass_d pass_ipa_cdtor_merge;
 
 extern struct gimple_opt_pass pass_all_optimizations;
 extern struct gimple_opt_pass pass_cleanup_cfg_post_optimizing;
Index: cgraphunit.c
===================================================================
--- cgraphunit.c	(revision 167709)
+++ cgraphunit.c	(working copy)
@@ -147,9 +147,174 @@ 
 
 FILE *cgraph_dump_file;
 
+/* A vector of FUNCTION_DECLs declared as static constructors.  */
+static GTY (()) VEC(tree, gc) *static_ctors;
+/* A vector of FUNCTION_DECLs declared as static destructors.  */
+static GTY (()) VEC(tree, gc) *static_dtors;
+
 /* Used for vtable lookup in thunk adjusting.  */
 static GTY (()) tree vtable_entry_type;
 
+/* When target does not have ctors and dtors, we call all constructor
+   and destructor by special initialization/destruction function
+   recognized by collect2.
+
+   When we are going to build this function, collect all constructors and
+   destructors and turn them into normal functions.  */
+
+static void
+record_cdtor_fn (tree fndecl)
+{
+  struct cgraph_node *node;
+  if (targetm.have_ctors_dtors
+      || (!DECL_STATIC_CONSTRUCTOR (fndecl)
+	  && !DECL_STATIC_DESTRUCTOR (fndecl)))
+    return;
+
+  if (DECL_STATIC_CONSTRUCTOR (fndecl))
+    {
+      VEC_safe_push (tree, gc, static_ctors, fndecl);
+      DECL_STATIC_CONSTRUCTOR (fndecl) = 0;
+    }
+  if (DECL_STATIC_DESTRUCTOR (fndecl))
+    {
+      VEC_safe_push (tree, gc, static_dtors, fndecl);
+      DECL_STATIC_DESTRUCTOR (fndecl) = 0;
+    }
+  node = cgraph_node (fndecl);
+  node->local.disregard_inline_limits = 1;
+  cgraph_mark_reachable_node (node);
+}
+
+/* Define global constructors/destructor functions for the CDTORS, of
+   which they are LEN.  The CDTORS are sorted by initialization
+   priority.  If CTOR_P is true, these are constructors; otherwise,
+   they are destructors.  */
+
+static void
+build_cdtor (bool ctor_p, tree *cdtors, size_t len)
+{
+  size_t i;
+
+  i = 0;
+  while (i < len)
+    {
+      tree body;
+      tree fn;
+      priority_type priority;
+
+      priority = 0;
+      body = NULL_TREE;
+      /* Find the next batch of constructors/destructors with the same
+	 initialization priority.  */
+      do
+	{
+	  priority_type p;
+	  tree call;
+	  fn = cdtors[i];
+	  p = ctor_p ? DECL_INIT_PRIORITY (fn) : DECL_FINI_PRIORITY (fn);
+	  if (!body)
+	    priority = p;
+	  else if (p != priority)
+	    break;
+	  call = build_call_expr (fn, 0);
+	  append_to_statement_list (call, &body);
+	  ++i;
+	}
+      while (i < len);
+      gcc_assert (body != NULL_TREE);
+      /* Generate a function to call all the function of like
+	 priority.  */
+      cgraph_build_static_cdtor (ctor_p ? 'I' : 'D', body, priority);
+    }
+}
+
+/* Comparison function for qsort.  P1 and P2 are actually of type
+   "tree *" and point to static constructors.  DECL_INIT_PRIORITY is
+   used to determine the sort order.  */
+
+static int
+compare_ctor (const void *p1, const void *p2)
+{
+  tree f1;
+  tree f2;
+  int priority1;
+  int priority2;
+
+  f1 = *(const tree *)p1;
+  f2 = *(const tree *)p2;
+  priority1 = DECL_INIT_PRIORITY (f1);
+  priority2 = DECL_INIT_PRIORITY (f2);
+
+  if (priority1 < priority2)
+    return -1;
+  else if (priority1 > priority2)
+    return 1;
+  else
+    /* Ensure a stable sort.  */
+    return (const tree *)p1 - (const tree *)p2;
+}
+
+/* Comparison function for qsort.  P1 and P2 are actually of type
+   "tree *" and point to static destructors.  DECL_FINI_PRIORITY is
+   used to determine the sort order.  */
+
+static int
+compare_dtor (const void *p1, const void *p2)
+{
+  tree f1;
+  tree f2;
+  int priority1;
+  int priority2;
+
+  f1 = *(const tree *)p1;
+  f2 = *(const tree *)p2;
+  priority1 = DECL_FINI_PRIORITY (f1);
+  priority2 = DECL_FINI_PRIORITY (f2);
+
+  if (priority1 < priority2)
+    return -1;
+  else if (priority1 > priority2)
+    return 1;
+  else
+    /* Ensure a stable sort.  */
+    return (const tree *)p1 - (const tree *)p2;
+}
+
+/* Generate functions to call static constructors and destructors
+   for targets that do not support .ctors/.dtors sections.  These
+   functions have magic names which are detected by collect2.  */
+
+static void
+cgraph_build_cdtor_fns (void)
+{
+  if (!VEC_empty (tree, static_ctors))
+    {
+      gcc_assert (!targetm.have_ctors_dtors);
+      qsort (VEC_address (tree, static_ctors),
+	     VEC_length (tree, static_ctors),
+	     sizeof (tree),
+	     compare_ctor);
+      build_cdtor (/*ctor_p=*/true,
+		   VEC_address (tree, static_ctors),
+		   VEC_length (tree, static_ctors));
+      VEC_truncate (tree, static_ctors, 0);
+    }
+
+  if (!VEC_empty (tree, static_dtors))
+    {
+      gcc_assert (!targetm.have_ctors_dtors);
+      qsort (VEC_address (tree, static_dtors),
+	     VEC_length (tree, static_dtors),
+	     sizeof (tree),
+	     compare_dtor);
+      build_cdtor (/*ctor_p=*/false,
+		   VEC_address (tree, static_dtors),
+		   VEC_length (tree, static_dtors));
+      VEC_truncate (tree, static_dtors, 0);
+    }
+}
+
 /* Determine if function DECL is needed.  That is, visible to something
    either outside this translation unit, something magic in the system
    configury.  */
@@ -353,6 +518,7 @@ 
   node->local.finalized = true;
   node->lowered = DECL_STRUCT_FUNCTION (decl)->cfg != NULL;
   node->finalized_by_frontend = true;
+  record_cdtor_fn (node->decl);
 
   if (cgraph_decide_is_function_needed (node, decl))
     cgraph_mark_needed_node (node);
@@ -1008,6 +1174,10 @@ 
   /* Emit size functions we didn't inline.  */
   finalize_size_functions ();
 
+  /* Call functions declared with the "constructor" or "destructor"
+     attribute.  */
+  cgraph_build_cdtor_fns ();
+
   /* Mark alias targets necessary and emit diagnostics.  */
   finish_aliases_1 ();
 
@@ -1861,7 +2031,79 @@ 
 #endif
 }
 
+
+/* Generate and emit a static constructor or destructor.  WHICH must
+   be one of 'I' (for a constructor) or 'D' (for a destructor).  BODY
+   is a STATEMENT_LIST containing GENERIC statements.  PRIORITY is the
+   initialization priority for this constructor or destructor.  */
+
 void
+cgraph_build_static_cdtor (char which, tree body, int priority)
+{
+  static int counter = 0;
+  char which_buf[16];
+  tree decl, name, resdecl;
+
+  /* The priority is encoded in the constructor or destructor name.
+     collect2 will sort the names and arrange that they are called at
+     program startup.  */
+  sprintf (which_buf, "%c_%.5d_%d", which, priority, counter++);
+  name = get_file_function_name (which_buf);
+
+  decl = build_decl (input_location, FUNCTION_DECL, name,
+		     build_function_type_list (void_type_node, NULL_TREE));
+  current_function_decl = decl;
+
+  resdecl = build_decl (input_location,
+			RESULT_DECL, NULL_TREE, void_type_node);
+  DECL_ARTIFICIAL (resdecl) = 1;
+  DECL_RESULT (decl) = resdecl;
+  DECL_CONTEXT (resdecl) = decl;
+
+  allocate_struct_function (decl, false);
+
+  TREE_STATIC (decl) = 1;
+  TREE_USED (decl) = 1;
+  DECL_ARTIFICIAL (decl) = 1;
+  DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl) = 1;
+  DECL_SAVED_TREE (decl) = body;
+  if (!targetm.have_ctors_dtors)
+    {
+      TREE_PUBLIC (decl) = 1;
+      DECL_PRESERVE_P (decl) = 1;
+    }
+  DECL_UNINLINABLE (decl) = 1;
+
+  DECL_INITIAL (decl) = make_node (BLOCK);
+  TREE_USED (DECL_INITIAL (decl)) = 1;
+
+  DECL_SOURCE_LOCATION (decl) = input_location;
+  cfun->function_end_locus = input_location;
+
+  switch (which)
+    {
+    case 'I':
+      DECL_STATIC_CONSTRUCTOR (decl) = 1;
+      decl_init_priority_insert (decl, priority);
+      break;
+    case 'D':
+      DECL_STATIC_DESTRUCTOR (decl) = 1;
+      decl_fini_priority_insert (decl, priority);
+      break;
+    default:
+      gcc_unreachable ();
+    }
+
+  gimplify_function_tree (decl);
+
+  cgraph_add_new_function (decl, false);
+  cgraph_mark_needed_node (cgraph_node (decl));
+
+  set_cfun (NULL);
+  current_function_decl = NULL;
+}
+
+void
 init_cgraph (void)
 {
   if (!cgraph_dump_file)
Index: ipa.c
===================================================================
--- ipa.c	(revision 167709)
+++ ipa.c	(working copy)
@@ -29,8 +29,6 @@ 
 #include "ggc.h"
 #include "flags.h"
 #include "pointer-set.h"
-#include "target.h"
-#include "tree-iterator.h"
 
 /* Fill array order with all nodes with output flag set in the reverse
    topological order.  */
@@ -1492,296 +1490,3 @@ 
  NULL,			                /* function_transform */
  NULL					/* variable_transform */
 };
-
-/* Generate and emit a static constructor or destructor.  WHICH must
-   be one of 'I' (for a constructor) or 'D' (for a destructor).  BODY
-   is a STATEMENT_LIST containing GENERIC statements.  PRIORITY is the
-   initialization priority for this constructor or destructor.  */
-
-void
-cgraph_build_static_cdtor (char which, tree body, int priority)
-{
-  static int counter = 0;
-  char which_buf[16];
-  tree decl, name, resdecl;
-
-  /* The priority is encoded in the constructor or destructor name.
-     collect2 will sort the names and arrange that they are called at
-     program startup.  */
-  sprintf (which_buf, "%c_%.5d_%d", which, priority, counter++);
-  name = get_file_function_name (which_buf);
-
-  decl = build_decl (input_location, FUNCTION_DECL, name,
-		     build_function_type_list (void_type_node, NULL_TREE));
-  current_function_decl = decl;
-
-  resdecl = build_decl (input_location,
-			RESULT_DECL, NULL_TREE, void_type_node);
-  DECL_ARTIFICIAL (resdecl) = 1;
-  DECL_RESULT (decl) = resdecl;
-  DECL_CONTEXT (resdecl) = decl;
-
-  allocate_struct_function (decl, false);
-
-  TREE_STATIC (decl) = 1;
-  TREE_USED (decl) = 1;
-  DECL_ARTIFICIAL (decl) = 1;
-  DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl) = 1;
-  DECL_SAVED_TREE (decl) = body;
-  if (!targetm.have_ctors_dtors)
-    {
-      TREE_PUBLIC (decl) = 1;
-      DECL_PRESERVE_P (decl) = 1;
-    }
-  DECL_UNINLINABLE (decl) = 1;
-
-  DECL_INITIAL (decl) = make_node (BLOCK);
-  TREE_USED (DECL_INITIAL (decl)) = 1;
-
-  DECL_SOURCE_LOCATION (decl) = input_location;
-  cfun->function_end_locus = input_location;
-
-  switch (which)
-    {
-    case 'I':
-      DECL_STATIC_CONSTRUCTOR (decl) = 1;
-      decl_init_priority_insert (decl, priority);
-      break;
-    case 'D':
-      DECL_STATIC_DESTRUCTOR (decl) = 1;
-      decl_fini_priority_insert (decl, priority);
-      break;
-    default:
-      gcc_unreachable ();
-    }
-
-  gimplify_function_tree (decl);
-
-  cgraph_add_new_function (decl, false);
-
-  set_cfun (NULL);
-  current_function_decl = NULL;
-}
-
-
-/* A vector of FUNCTION_DECLs declared as static constructors.  */
-static VEC(tree, heap) *static_ctors;
-/* A vector of FUNCTION_DECLs declared as static destructors.  */
-static VEC(tree, heap) *static_dtors;
-
-/* When target does not have ctors and dtors, we call all constructor
-   and destructor by special initialization/destruction function
-   recognized by collect2.
-
-   When we are going to build this function, collect all constructors and
-   destructors and turn them into normal functions.  */
-
-static void
-record_cdtor_fn (struct cgraph_node *node)
-{
-  if (DECL_STATIC_CONSTRUCTOR (node->decl))
-    VEC_safe_push (tree, heap, static_ctors, node->decl);
-  if (DECL_STATIC_DESTRUCTOR (node->decl))
-    VEC_safe_push (tree, heap, static_dtors, node->decl);
-  node = cgraph_node (node->decl);
-  node->local.disregard_inline_limits = 1;
-}
-
-/* Define global constructors/destructor functions for the CDTORS, of
-   which they are LEN.  The CDTORS are sorted by initialization
-   priority.  If CTOR_P is true, these are constructors; otherwise,
-   they are destructors.  */
-
-static void
-build_cdtor (bool ctor_p, VEC (tree, heap) *cdtors)
-{
-  size_t i,j;
-  size_t len = VEC_length (tree, cdtors);
-
-  i = 0;
-  while (i < len)
-    {
-      tree body;
-      tree fn;
-      priority_type priority;
-
-      priority = 0;
-      body = NULL_TREE;
-      j = i;
-      do
-	{
-	  priority_type p;
-	  fn = VEC_index (tree, cdtors, j);
-	  p = ctor_p ? DECL_INIT_PRIORITY (fn) : DECL_FINI_PRIORITY (fn);
-	  if (j == i)
-	    priority = p;
-	  else if (p != priority)
-	    break;
-	  j++;
-	}
-      while (j < len);
-
-      /* When there is only one cdtor and target supports them, do nothing.  */
-      if (j == i + 1
-	  && targetm.have_ctors_dtors)
-	{
-	  i++;
-	  continue;
-	}
-      /* Find the next batch of constructors/destructors with the same
-	 initialization priority.  */
-      for (;i < j; i++)
-	{
-	  tree call;
-	  fn = VEC_index (tree, cdtors, i);
-	  call = build_call_expr (fn, 0);
-	  if (ctor_p)
-	    DECL_STATIC_CONSTRUCTOR (fn) = 0;
-	  else
-	    DECL_STATIC_DESTRUCTOR (fn) = 0;
-	  /* We do not want to optimize away pure/const calls here.
-	     When optimizing, these should be already removed, when not
-	     optimizing, we want user to be able to breakpoint in them.  */
-	  TREE_SIDE_EFFECTS (call) = 1;
-	  append_to_statement_list (call, &body);
-	}
-      gcc_assert (body != NULL_TREE);
-      /* Generate a function to call all the function of like
-	 priority.  */
-      cgraph_build_static_cdtor (ctor_p ? 'I' : 'D', body, priority);
-    }
-}
-
-/* Comparison function for qsort.  P1 and P2 are actually of type
-   "tree *" and point to static constructors.  DECL_INIT_PRIORITY is
-   used to determine the sort order.  */
-
-static int
-compare_ctor (const void *p1, const void *p2)
-{
-  tree f1;
-  tree f2;
-  int priority1;
-  int priority2;
-
-  f1 = *(const tree *)p1;
-  f2 = *(const tree *)p2;
-  priority1 = DECL_INIT_PRIORITY (f1);
-  priority2 = DECL_INIT_PRIORITY (f2);
-
-  if (priority1 < priority2)
-    return -1;
-  else if (priority1 > priority2)
-    return 1;
-  else
-    /* Ensure a stable sort.  Constructors are executed in backwarding
-       order to make LTO initialize braries first.  */
-    return DECL_UID (f2) - DECL_UID (f1);
-}
-
-/* Comparison function for qsort.  P1 and P2 are actually of type
-   "tree *" and point to static destructors.  DECL_FINI_PRIORITY is
-   used to determine the sort order.  */
-
-static int
-compare_dtor (const void *p1, const void *p2)
-{
-  tree f1;
-  tree f2;
-  int priority1;
-  int priority2;
-
-  f1 = *(const tree *)p1;
-  f2 = *(const tree *)p2;
-  priority1 = DECL_FINI_PRIORITY (f1);
-  priority2 = DECL_FINI_PRIORITY (f2);
-
-  if (priority1 < priority2)
-    return -1;
-  else if (priority1 > priority2)
-    return 1;
-  else
-    /* Ensure a stable sort.  */
-    return DECL_UID (f1) - DECL_UID (f2);
-}
-
-/* Generate functions to call static constructors and destructors
-   for targets that do not support .ctors/.dtors sections.  These
-   functions have magic names which are detected by collect2.  */
-
-static void
-build_cdtor_fns (void)
-{
-  if (!VEC_empty (tree, static_ctors))
-    {
-      gcc_assert (!targetm.have_ctors_dtors || in_lto_p);
-      VEC_qsort (tree, static_ctors, compare_ctor);
-      build_cdtor (/*ctor_p=*/true, static_ctors);
-    }
-
-  if (!VEC_empty (tree, static_dtors))
-    {
-      gcc_assert (!targetm.have_ctors_dtors || in_lto_p);
-      VEC_qsort (tree, static_dtors, compare_dtor);
-      build_cdtor (/*ctor_p=*/false, static_dtors);
-    }
-}
-
-/* Look for constructors and destructors and produce function calling them.
-   This is needed for targets not supporting ctors or dtors, but we perform the
-   transformation also at linktime to merge possibly numberous
-   constructors/destructors into single function to improve code locality and
-   reduce size.  */
-
-static unsigned int
-ipa_cdtor_merge (void)
-{
-  struct cgraph_node *node;
-  for (node = cgraph_nodes; node; node = node->next)
-    if (node->analyzed
-	&& (DECL_STATIC_CONSTRUCTOR (node->decl)
-	    || DECL_STATIC_DESTRUCTOR (node->decl)))
-       record_cdtor_fn (node);
-  build_cdtor_fns ();
-  VEC_free (tree, heap, static_ctors);
-  VEC_free (tree, heap, static_dtors);
-  return 0;
-}
-
-/* Perform the pass when we have no ctors/dtors support
-   or at LTO time to merge multiple constructors into single
-   function.  */
-
-static bool
-gate_ipa_cdtor_merge (void)
-{
-  return !targetm.have_ctors_dtors || (optimize && in_lto_p);
-}
-
-struct ipa_opt_pass_d pass_ipa_cdtor_merge =
-{
- {
-  IPA_PASS,
-  "cdtor",				/* name */
-  gate_ipa_cdtor_merge,			/* gate */
-  ipa_cdtor_merge,		        /* execute */
-  NULL,					/* sub */
-  NULL,					/* next */
-  0,					/* static_pass_number */
-  TV_CGRAPHOPT,			        /* tv_id */
-  0,	                                /* properties_required */
-  0,					/* properties_provided */
-  0,					/* properties_destroyed */
-  0,					/* todo_flags_start */
-  0                                     /* todo_flags_finish */
- },
- NULL,				        /* generate_summary */
- NULL,					/* write_summary */
- NULL,					/* read_summary */
- NULL,					/* write_optimization_summary */
- NULL,					/* read_optimization_summary */
- NULL,					/* stmt_fixup */
- 0,					/* TODOs */
- NULL,			                /* function_transform */
- NULL					/* variable_transform */
-};
Index: ipa-prop.c
===================================================================
--- ipa-prop.c	(revision 167709)
+++ ipa-prop.c	(working copy)
@@ -1575,12 +1575,11 @@ 
 				      struct cgraph_node *node,
 				      VEC (cgraph_edge_p, heap) **new_edges)
 {
-  struct ipa_edge_args *top;
+  struct ipa_edge_args *top = IPA_EDGE_REF (cs);
   struct cgraph_edge *ie, *next_ie, *new_direct_edge;
   bool res = false;
 
   ipa_check_create_edge_args ();
-  top = IPA_EDGE_REF (cs);
 
   for (ie = node->indirect_calls; ie; ie = next_ie)
     {
Index: passes.c
===================================================================
--- passes.c	(revision 167709)
+++ passes.c	(working copy)
@@ -794,7 +794,6 @@ 
   NEXT_PASS (pass_ipa_whole_program_visibility);
   NEXT_PASS (pass_ipa_profile);
   NEXT_PASS (pass_ipa_cp);
-  NEXT_PASS (pass_ipa_cdtor_merge);
   NEXT_PASS (pass_ipa_inline);
   NEXT_PASS (pass_ipa_pure_const);
   NEXT_PASS (pass_ipa_reference);