re PR target/33579 (INIT_PRIORITY is broken)
authorMark Mitchell <mark@codesourcery.com>
Tue, 6 Nov 2007 00:30:52 +0000 (00:30 +0000)
committerMark Mitchell <mmitchel@gcc.gnu.org>
Tue, 6 Nov 2007 00:30:52 +0000 (00:30 +0000)
PR target/33579
* tree.h (DECL_INIT_PRIORITY): Do not require
DECL_HAS_INIT_PRIORITY_P.
(DECL_FINI_PRIORITY): Likewise.
* tree.c (decl_init_priority_lookup): Remove assert.
(decl_fini_priority_insert): Likewise.
* cgraphunit.c (static_ctors): Make it a VEC.
(static_dtors): Likewise.
(record_cdtor_fn): Adjust accordingly.
(build_cdtor): Generate multiple functions for each initialization
priority.
(compare_ctor): New function.
(compare_dtor): Likewise.
(cgraph_build_cdtor_fns): Sort the functions by priority before
calling build_cdtor.
(cgraph_build_static_cdtor): Put the priority in the function's
name.

From-SVN: r129918

gcc/ChangeLog
gcc/cgraphunit.c
gcc/tree.c
gcc/tree.h

index e8720053c5d90ca8fc400fc863fe45d80c7a2339..b9d370ed9e16e1ef13cc165ac50d4b4e96e8a1a6 100644 (file)
@@ -1,3 +1,23 @@
+2007-11-05  Mark Mitchell  <mark@codesourcery.com>
+
+       PR target/33579
+       * tree.h (DECL_INIT_PRIORITY): Do not require
+       DECL_HAS_INIT_PRIORITY_P.
+       (DECL_FINI_PRIORITY): Likewise.
+       * tree.c (decl_init_priority_lookup): Remove assert.
+       (decl_fini_priority_insert): Likewise.
+       * cgraphunit.c (static_ctors): Make it a VEC.
+       (static_dtors): Likewise.
+       (record_cdtor_fn): Adjust accordingly.
+       (build_cdtor): Generate multiple functions for each initialization
+       priority.
+       (compare_ctor): New function.
+       (compare_dtor): Likewise.
+       (cgraph_build_cdtor_fns): Sort the functions by priority before
+       calling build_cdtor.
+       (cgraph_build_static_cdtor): Put the priority in the function's
+       name.
+
 2007-11-05  H.J. Lu  <hongjiu.lu@intel.com>
 
        PR driver/32632
index b2e196026bd70665c6ad60647d24887c96a4a965..11a625d0812ec219824663525ea9fde5cb873dcf 100644 (file)
@@ -158,8 +158,10 @@ static void cgraph_output_pending_asms (void);
 
 static FILE *cgraph_dump_file;
 
-static GTY (()) tree static_ctors;
-static GTY (()) tree static_dtors;
+/* 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;
 
 /* When target does not have ctors and dtors, we call all constructor
    and destructor by special initialization/destruction function
@@ -179,12 +181,12 @@ record_cdtor_fn (tree fndecl)
 
   if (DECL_STATIC_CONSTRUCTOR (fndecl))
     {
-      static_ctors = tree_cons (NULL_TREE, fndecl, static_ctors);
+      VEC_safe_push (tree, gc, static_ctors, fndecl);
       DECL_STATIC_CONSTRUCTOR (fndecl) = 0;
     }
   if (DECL_STATIC_DESTRUCTOR (fndecl))
     {
-      static_dtors = tree_cons (NULL_TREE, fndecl, static_dtors);
+      VEC_safe_push (tree, gc, static_dtors, fndecl);
       DECL_STATIC_DESTRUCTOR (fndecl) = 0;
     }
   DECL_INLINE (fndecl) = 1;
@@ -193,22 +195,98 @@ record_cdtor_fn (tree fndecl)
   cgraph_mark_reachable_node (node);
 }
 
-/* Synthesize a function which calls all the global ctors or global
-   dtors in this file.  This is only used for targets which do not
-   support .ctors/.dtors sections.  */
+/* 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 (int method_type, tree cdtors)
+build_cdtor (bool ctor_p, tree *cdtors, size_t len)
 {
-  tree body = 0;
+  size_t i;
 
-  if (!cdtors)
-    return;
+  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;
+         fn = cdtors[i];
+         p = ctor_p ? DECL_INIT_PRIORITY (fn) : DECL_FINI_PRIORITY (fn);
+         if (!body)
+           priority = p;
+         else if (p != priority)
+           break;
+         append_to_statement_list (build_function_call_expr (fn, 0),
+                                   &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.  */
 
-  for (; cdtors; cdtors = TREE_CHAIN (cdtors))
-    append_to_statement_list (build_function_call_expr (TREE_VALUE (cdtors), 0),
-                             &body);
+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.  */
 
-  cgraph_build_static_cdtor (method_type, body, DEFAULT_INIT_PRIORITY);
+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
@@ -218,17 +296,30 @@ build_cdtor (int method_type, tree cdtors)
 static void
 cgraph_build_cdtor_fns (void)
 {
-  if (!targetm.have_ctors_dtors)
+  if (!VEC_empty (tree, static_ctors))
     {
-      build_cdtor ('I', static_ctors); 
-      static_ctors = NULL_TREE;
-      build_cdtor ('D', static_dtors); 
-      static_dtors = NULL_TREE;
+      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);
     }
-  else
+
+  if (!VEC_empty (tree, static_dtors))
     {
-      gcc_assert (!static_ctors);
-      gcc_assert (!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);
     }
 }
 
@@ -1364,9 +1455,10 @@ cgraph_optimize (void)
     }
 #endif
 }
-/* Generate and emit a static constructor or destructor.  WHICH must be
-   one of 'I' or 'D'.  BODY should be a STATEMENT_LIST containing
-   GENERIC statements.  */
+/* 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 fot this constructor or destructor.  */
 
 void
 cgraph_build_static_cdtor (char which, tree body, int priority)
@@ -1375,7 +1467,10 @@ cgraph_build_static_cdtor (char which, tree body, int priority)
   char which_buf[16];
   tree decl, name, resdecl;
 
-  sprintf (which_buf, "%c_%d", which, counter++);
+  /* 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 (FUNCTION_DECL, name,
index 24e758f12cd99449774699d3f0c75bfb97d3a287..81c54d0edf49f6fa70548976dcc988bf1f1ee2ca 100644 (file)
@@ -4306,9 +4306,6 @@ decl_init_priority_lookup (tree decl)
   struct tree_map_base in;
 
   gcc_assert (VAR_OR_FUNCTION_DECL_P (decl));
-  gcc_assert (TREE_CODE (decl) == VAR_DECL
-             ? DECL_HAS_INIT_PRIORITY_P (decl)
-             : DECL_STATIC_CONSTRUCTOR (decl));
   in.from = decl;
   h = htab_find (init_priority_for_decl, &in);
   return h ? h->init : DEFAULT_INIT_PRIORITY;
@@ -4323,7 +4320,6 @@ decl_fini_priority_lookup (tree decl)
   struct tree_map_base in;
 
   gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
-  gcc_assert (DECL_STATIC_DESTRUCTOR (decl));
   in.from = decl;
   h = htab_find (init_priority_for_decl, &in);
   return h ? h->fini : DEFAULT_INIT_PRIORITY;
index da71a8c667632339e1c3fd42af7d691340d8276a..ede0cd8303b3fc2e4350cc834cd1b183e38701d2 100644 (file)
@@ -3144,16 +3144,15 @@ extern void decl_fini_priority_insert (tree, priority_type);
 #define DECL_HAS_INIT_PRIORITY_P(NODE) \
   (VAR_DECL_CHECK (NODE)->decl_with_vis.init_priority_p)
 
-/* For a VAR_DECL or FUNCTION_DECL with DECL_HAS_INIT_PRIORITY_P set,
-   the initialization priority of NODE.  */
+/* For a VAR_DECL or FUNCTION_DECL the initialization priority of
+   NODE.  */ 
 #define DECL_INIT_PRIORITY(NODE) \
   (decl_init_priority_lookup (NODE))
 /* Set the initialization priority for NODE to VAL.  */
 #define SET_DECL_INIT_PRIORITY(NODE, VAL) \
   (decl_init_priority_insert (NODE, VAL))
 
-/* For a FUNCTION_DECL with DECL_HAS_INIT_PRIORITY_P set, the
-   finalization priority of NODE.  */
+/* For a FUNCTION_DECL the finalization priority of NODE.  */
 #define DECL_FINI_PRIORITY(NODE) \
   (decl_fini_priority_lookup (NODE))
 /* Set the finalization priority for NODE to VAL.  */