public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r13-1014] c++: Reimplement static init/fini generation
@ 2022-06-08 15:39 Nathan Sidwell
  0 siblings, 0 replies; only message in thread
From: Nathan Sidwell @ 2022-06-08 15:39 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:90a6c3b6d69765ea9269ba7ae16ef02d5527e875

commit r13-1014-g90a6c3b6d69765ea9269ba7ae16ef02d5527e875
Author: Nathan Sidwell <nathan@acm.org>
Date:   Tue May 31 10:42:35 2022 -0700

    c++: Reimplement static init/fini generation
    
    Currently we generate static init/fini code by generating a set of
    functions taking an 'initp' bool and an unsigned priority.  (There can
    be more than one, as we repeat the end-of-compile loop.)  We then
    generate a set of real init or fini functions for each needed
    prioroty, calling the previous set of functions.  This is of course
    very tangled, but excitingly the value-range-propagator is clever
    enough to unentangle it.  However, the current arrangement makes
    generation awkward, particularly as to how to optimize the
    module-global-init generation.
    
    This reimplements the generation to generate a set of separate
    init/fini functions for each needed priority, and then call them from
    the real inits previously mentioned.  This replaces a splay tree,
    recording which priority/init combos we needed, with a pair of hash
    tables, mapping priority to init functions.  Much simpler.
    
    While there, rename several of the functions as they are only dealing
    with part of the init/fini generation, not the whole set.
    
            gcc/cp/
            * decl2.cc (struct priority_info_s, priority_info): Delete.
            (priority_map_traits, priority_map_t): New.
            (static_init_fini_fns): New.
            (INITIALIZE_P_IDENTIFIER, PRIORITY_IDENTIFIER): Delete.
            (initialize_p_decl, priority_decl): Delete.
            (ssdf_decls, priority_info_map): Delete.
            (start_static_storage_duration_function): Rename to ...
            (start_partial_init_fini_fn): ... here. Create a void arg fn.
            Add it to the slot in the appropriate static_init_fini_fns
            hash table.
            (finish_static_storage_duration_function): Rename to ...
            (finish_partial_init_fini_fn): ... here.
            (get_priority_info): Delete.
            (one_static_initialization_or_destruction): Assert not
            trivial dtor.
            (do_static_initialization_or_destruction): Rename to ...
            (emit_partial_init_fini_fn) ... here.  Start & finish the fn.
            Simply init/fini each var.
            (partition_vars_for_init_fini): Partition vars according to
            priority and add to init and/or fini list.
            (generate_ctor_or_dtor_function): Start and finish the function.
            Do santitizer calls here.
            (generate_ctor_and_dtor_functions_for_priority): Delete.
            (c_parse_final_cleanups): Reimplement global init/fini
            processing.
    
            gcc/testsuite/
            * g++.dg/init/static-cdtor1.C: New.

Diff:
---
 gcc/cp/decl2.cc                           | 488 ++++++++++++------------------
 gcc/testsuite/g++.dg/init/static-cdtor1.C |  17 ++
 2 files changed, 205 insertions(+), 300 deletions(-)

diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc
index 974afe798b6..bfb6a32e3b6 100644
--- a/gcc/cp/decl2.cc
+++ b/gcc/cp/decl2.cc
@@ -55,27 +55,14 @@ int raw_dump_id;
  
 extern cpp_reader *parse_in;
 
-/* This structure contains information about the initializations
-   and/or destructions required for a particular priority level.  */
-typedef struct priority_info_s {
-  /* Nonzero if there have been any initializations at this priority
-     throughout the translation unit.  */
-  int initializations_p;
-  /* Nonzero if there have been any destructions at this priority
-     throughout the translation unit.  */
-  int destructions_p;
-} *priority_info;
-
 static tree start_objects (bool, unsigned);
 static tree finish_objects (bool, unsigned, tree);
-static tree start_static_storage_duration_function (unsigned);
-static void finish_static_storage_duration_function (tree);
-static priority_info get_priority_info (int);
-static void do_static_initialization_or_destruction (bool, tree);
+static tree start_partial_init_fini_fn (bool, unsigned, unsigned);
+static void finish_partial_init_fini_fn (tree);
+static void emit_partial_init_fini_fn (bool, unsigned, tree,
+				       unsigned, location_t);
 static void one_static_initialization_or_destruction (bool, tree, tree);
-static void generate_ctor_or_dtor_function (bool, unsigned, location_t *);
-static int generate_ctor_and_dtor_functions_for_priority (splay_tree_node,
-							  void *);
+static void generate_ctor_or_dtor_function (bool, unsigned, tree, location_t);
 static tree prune_vars_needing_no_initialization (tree *);
 static void write_out_vars (tree);
 static void import_export_class (tree);
@@ -136,6 +123,51 @@ struct mangled_decl_hash : ggc_remove <tree>
    we need compatibility aliases.  */
 static GTY(()) hash_table<mangled_decl_hash> *mangled_decls;
 
+// Hash table mapping priority to lists of variables or functions.
+struct priority_map_traits
+{
+  typedef unsigned key_type;
+  typedef tree value_type;
+  static const bool maybe_mx = true;
+  static hashval_t hash (key_type v)
+  {
+    return hashval_t (v);
+  }
+  static bool equal_keys (key_type k1, key_type k2)
+  {
+    return k1 == k2;
+  }
+  template <typename T> static void remove (T &)
+  {
+  }
+  // Zero is not a priority
+  static const bool empty_zero_p = true;
+  template <typename T> static bool is_empty (const T &entry)
+  {
+    return entry.m_key == 0;
+  }
+  template <typename T> static void mark_empty (T &entry)
+  {
+    entry.m_key = 0;
+  }
+  // Entries are not deleteable
+  template <typename T> static bool is_deleted (const T &)
+  {
+    return false;
+  }
+  template <typename T> static void mark_deleted (T &entry)
+  {
+    gcc_unreachable ();
+  }
+};
+
+typedef hash_map<unsigned/*Priority*/, tree/*List*/,
+		 priority_map_traits> priority_map_t;
+
+/* A pair of such hash tables, indexed by initp -- one for fini and
+   one for init.  The fini table is only ever used when !cxa_atexit.  */
+static GTY(()) priority_map_t *static_init_fini_fns[2];
+
 /* Nonzero if we're done parsing and into end-of-file activities.  */
 
 int at_eof;
@@ -3927,45 +3959,18 @@ finish_objects (bool initp, unsigned priority, tree body)
   return fn;
 }
 
-/* The names of the parameters to the function created to handle
-   initializations and destructions for objects with static storage
-   duration.  */
-#define INITIALIZE_P_IDENTIFIER "__initialize_p"
-#define PRIORITY_IDENTIFIER "__priority"
-
 /* The name of the function we create to handle initializations and
    destructions for objects with static storage duration.  */
 #define SSDF_IDENTIFIER "__static_initialization_and_destruction"
 
-/* The declaration for the __INITIALIZE_P argument.  */
-static GTY(()) tree initialize_p_decl;
-
-/* The declaration for the __PRIORITY argument.  */
-static GTY(()) tree priority_decl;
-
-/* All the static storage duration functions created in this
-   translation unit.  */
-static GTY(()) vec<tree, va_gc> *ssdf_decls;
-
-/* A map from priority levels to information about that priority
-   level.  There may be many such levels, so efficient lookup is
-   important.  */
-static splay_tree priority_info_map;
-
 /* Begins the generation of the function that will handle all
-   initialization and destruction of objects with static storage
-   duration.  The function generated takes two parameters of type
-   `int': __INITIALIZE_P and __PRIORITY.  If __INITIALIZE_P is
-   nonzero, it performs initializations.  Otherwise, it performs
-   destructions.  It only performs those initializations or
-   destructions with the indicated __PRIORITY.  The generated function
-   returns no value.
-
-   It is assumed that this function will only be called once per
-   translation unit.  */
+   initialization or destruction of objects with static storage
+   duration at PRIORITY.
+
+   It is assumed that this function will only be called once.  */
 
 static tree
-start_static_storage_duration_function (unsigned count)
+start_partial_init_fini_fn (bool initp, unsigned priority, unsigned count)
 {
   char id[sizeof (SSDF_IDENTIFIER) + 1 /* '\0' */ + 32];
 
@@ -3973,9 +3978,7 @@ start_static_storage_duration_function (unsigned count)
      SSDF_IDENTIFIER_<number>.  */
   sprintf (id, "%s_%u", SSDF_IDENTIFIER, count);
 
-  tree type = build_function_type_list (void_type_node,
-					integer_type_node, integer_type_node,
-					NULL_TREE);
+  tree type = build_function_type (void_type_node, void_list_node);
 
   /* Create the FUNCTION_DECL itself.  */
   tree fn = build_lang_decl (FUNCTION_DECL, get_identifier (id), type);
@@ -3984,36 +3987,10 @@ start_static_storage_duration_function (unsigned count)
 
   /* Put this function in the list of functions to be called from the
      static constructors and destructors.  */
-  if (!ssdf_decls)
-    {
-      vec_alloc (ssdf_decls, 32);
-
-      /* Take this opportunity to initialize the map from priority
-	 numbers to information about that priority level.  */
-      priority_info_map = splay_tree_new (splay_tree_compare_ints,
-					  /*delete_key_fn=*/0,
-					  /*delete_value_fn=*/
-					  splay_tree_delete_pointers);
-
-      /* We always need to generate functions for the
-	 DEFAULT_INIT_PRIORITY so enter it now.  That way when we walk
-	 priorities later, we'll be sure to find the
-	 DEFAULT_INIT_PRIORITY.  */
-      get_priority_info (DEFAULT_INIT_PRIORITY);
-    }
-
-  vec_safe_push (ssdf_decls, fn);
-
-  /* Create the argument list.  */
-  initialize_p_decl = cp_build_parm_decl
-    (fn, get_identifier (INITIALIZE_P_IDENTIFIER), integer_type_node);
-  TREE_USED (initialize_p_decl) = 1;
-  priority_decl = cp_build_parm_decl
-    (fn, get_identifier (PRIORITY_IDENTIFIER), integer_type_node);
-  TREE_USED (priority_decl) = 1;
-
-  DECL_CHAIN (initialize_p_decl) = priority_decl;
-  DECL_ARGUMENTS (fn) = initialize_p_decl;
+  if (!static_init_fini_fns[initp])
+    static_init_fini_fns[initp] = priority_map_t::create_ggc ();
+  auto &slot = static_init_fini_fns[initp]->get_or_insert (priority);
+  slot = tree_cons (fn, NULL_TREE, slot);
 
   /* Put the function in the global scope.  */
   pushdecl (fn);
@@ -4032,46 +4009,16 @@ start_static_storage_duration_function (unsigned count)
 }
 
 /* Finish the generation of the function which performs initialization
-   and destruction of objects with static storage duration.  After
-   this point, no more such objects can be created.  */
+   or destruction of objects with static storage duration.  */
 
 static void
-finish_static_storage_duration_function (tree body)
+finish_partial_init_fini_fn (tree body)
 {
   /* Close out the function.  */
   finish_compound_stmt (body);
   expand_or_defer_fn (finish_function (/*inline_p=*/false));
 }
 
-/* Return the information about the indicated PRIORITY level.  If no
-   code to handle this level has yet been generated, generate the
-   appropriate prologue.  */
-
-static priority_info
-get_priority_info (int priority)
-{
-  priority_info pi;
-  splay_tree_node n;
-
-  n = splay_tree_lookup (priority_info_map,
-			 (splay_tree_key) priority);
-  if (!n)
-    {
-      /* Create a new priority information structure, and insert it
-	 into the map.  */
-      pi = XNEW (struct priority_info_s);
-      pi->initializations_p = 0;
-      pi->destructions_p = 0;
-      splay_tree_insert (priority_info_map,
-			 (splay_tree_key) priority,
-			 (splay_tree_value) pi);
-    }
-  else
-    pi = (priority_info) n->value;
-
-  return pi;
-}
-
 /* The effective initialization priority of a DECL.  */
 
 #define DECL_EFFECTIVE_INIT_PRIORITY(decl)				      \
@@ -4117,9 +4064,7 @@ one_static_initialization_or_destruction (bool initp, tree decl, tree init)
 {
   /* If we are supposed to destruct and there's a trivial destructor,
      nothing has to be done.  */
-  if (!initp
-      && TYPE_HAS_TRIVIAL_DESTRUCTOR (TREE_TYPE (decl)))
-    return;
+  gcc_checking_assert (init || !TYPE_HAS_TRIVIAL_DESTRUCTOR (TREE_TYPE (decl)));
 
   /* Trick the compiler into thinking we are at the file and line
      where DECL was declared so that error-messages make sense, and so
@@ -4241,81 +4186,21 @@ one_static_initialization_or_destruction (bool initp, tree decl, tree init)
    Whether initialization or destruction is performed is specified by INITP.  */
 
 static void
-do_static_initialization_or_destruction (bool initp, tree vars)
+emit_partial_init_fini_fn (bool initp, unsigned priority, tree vars,
+			   unsigned counter, location_t locus)
 {
-  /* Build the outer if-stmt to check for initialization or destruction.  */
-  tree init_if_stmt = begin_if_stmt ();
-  tree cond = initp ? integer_one_node : integer_zero_node;
-  cond = cp_build_binary_op (input_location,
-			     EQ_EXPR,
-			     initialize_p_decl,
-			     cond,
-			     tf_warning_or_error);
-  finish_if_stmt_cond (cond, init_if_stmt);
-
-  /* To make sure dynamic construction doesn't access globals from other
-     compilation units where they might not be yet constructed, for
-     -fsanitize=address insert __asan_before_dynamic_init call that
-     prevents access to either all global variables that need construction
-     in other compilation units, or at least those that haven't been
-     initialized yet.  Variables that need dynamic construction in
-     the current compilation unit are kept accessible.  */
-  if (initp && (flag_sanitize & SANITIZE_ADDRESS))
-    finish_expr_stmt (asan_dynamic_init_call (/*after_p=*/false));
-
-  tree node = vars;
-  do {
-    tree decl = TREE_VALUE (node);
-
-    /* If we don't need a destructor, there's nothing to do.  Avoid
-       creating a possibly empty if-stmt.  */
-    if (!initp && TYPE_HAS_TRIVIAL_DESTRUCTOR (TREE_TYPE (decl)))
-      {
-	node = TREE_CHAIN (node);
-	continue;
-      }
-
-    /* Remember that we had an initialization or finalization at this
-       priority.  */
-    int priority = DECL_EFFECTIVE_INIT_PRIORITY (decl);
-    priority_info pi = get_priority_info (priority);
-    if (initp)
-      pi->initializations_p = 1;
-    else
-      pi->destructions_p = 1;
-
-    /* Conditionalize this initialization on being in the right priority
-       and being initializing/finalizing appropriately.  */
-    tree priority_if_stmt = begin_if_stmt ();
-    cond = cp_build_binary_op (input_location,
-			       EQ_EXPR,
-			       priority_decl,
-			       build_int_cst (NULL_TREE, priority),
-			       tf_warning_or_error);
-    finish_if_stmt_cond (cond, priority_if_stmt);
-
-    /* Process initializers with same priority.  */
-    for (; node
-	   && DECL_EFFECTIVE_INIT_PRIORITY (TREE_VALUE (node)) == priority;
-	 node = TREE_CHAIN (node))
-      /* Do one initialization or destruction.  */
-      one_static_initialization_or_destruction (initp, TREE_VALUE (node),
-						TREE_PURPOSE (node));
-
-    /* Finish up the priority if-stmt body.  */
-    finish_then_clause (priority_if_stmt);
-    finish_if_stmt (priority_if_stmt);
-
-  } while (node);
-
-  /* Revert what __asan_before_dynamic_init did by calling
-     __asan_after_dynamic_init.  */
-  if (initp && (flag_sanitize & SANITIZE_ADDRESS))
-    finish_expr_stmt (asan_dynamic_init_call (/*after_p=*/true));
-
-  /* Finish up the init/destruct if-stmt body.  */
-  finish_then_clause (init_if_stmt);
-  finish_if_stmt (init_if_stmt);
+  input_location = locus;
+  tree body = start_partial_init_fini_fn (initp, priority, counter);
+
+  for (tree node = vars; node; node = TREE_CHAIN (node))
+    /* Do one initialization or destruction.  */
+    one_static_initialization_or_destruction (initp, TREE_VALUE (node),
+					      TREE_PURPOSE (node));
+
+  /* Finish up the static storage duration function for this
+     round.  */
+  input_location = locus;
+  finish_partial_init_fini_fn (body);
 }
 
 /* VARS is a list of variables with static storage duration which may
@@ -4323,8 +4208,7 @@ do_static_initialization_or_destruction (bool initp, tree vars)
    that don't really need to be initialized or finalized, and return
    the resulting list.  The order in which the variables appear in
    VARS is in reverse order of the order in which they should actually
-   be initialized.  The list we return is in the unreversed order;
-   i.e., the first variable should be initialized first.  */
+   be initialized.  That order is preserved.  */
 
 static tree
 prune_vars_needing_no_initialization (tree *vars)
@@ -4375,6 +4259,39 @@ prune_vars_needing_no_initialization (tree *vars)
   return result;
 }
 
+/* Split VAR_LIST by init priority and add into PARTS hash table.
+   This reverses the variable ordering.  */
+
+void
+partition_vars_for_init_fini (tree var_list, priority_map_t *(&parts)[2])
+{
+  for (auto node = var_list; node; node = TREE_CHAIN (node))
+    {
+      tree decl = TREE_VALUE (node);
+      tree init = TREE_PURPOSE (node);
+      bool has_cleanup = !TYPE_HAS_TRIVIAL_DESTRUCTOR (TREE_TYPE (decl));
+      unsigned priority = DECL_EFFECTIVE_INIT_PRIORITY (decl);
+
+      if (init || (flag_use_cxa_atexit && has_cleanup))
+	{
+	  // Add to initialization list.
+	  if (!parts[true])
+	    parts[true] = priority_map_t::create_ggc ();
+	  auto &slot = parts[true]->get_or_insert (priority);
+	  slot = tree_cons (init, decl, slot);
+	}
+
+      if (!flag_use_cxa_atexit && has_cleanup)
+	{
+	  // Add to finalization list.
+	  if (!parts[false])
+	    parts[false] = priority_map_t::create_ggc ();
+	  auto &slot = parts[false]->get_or_insert (priority);
+	  slot = tree_cons (NULL_TREE, decl, slot);
+	}
+    }
+}
+
 /* Make sure we have told the back end about all the variables in
    VARS.  */
 
@@ -4399,76 +4316,51 @@ write_out_vars (tree vars)
    storage duration having the indicated PRIORITY.  */
 
 static void
-generate_ctor_or_dtor_function (bool initp, unsigned priority, location_t *locus)
+generate_ctor_or_dtor_function (bool initp, unsigned priority,
+				tree fns, location_t locus)
 {
-  input_location = *locus;
+  input_location = locus;
 
-  /* We emit the function lazily, to avoid generating empty
-     global constructors and destructors.  */
-  tree body = NULL_TREE;
+  tree body = start_objects (initp, priority);
 
-  if (initp && priority == DEFAULT_INIT_PRIORITY)
+  /* To make sure dynamic construction doesn't access globals from other
+     compilation units where they might not be yet constructed, for
+     -fsanitize=address insert __asan_before_dynamic_init call that
+     prevents access to either all global variables that need construction
+     in other compilation units, or at least those that haven't been
+     initialized yet.  Variables that need dynamic construction in
+     the current compilation unit are kept accessible.  */
+  if (initp && (flag_sanitize & SANITIZE_ADDRESS))
+    finish_expr_stmt (asan_dynamic_init_call (/*after_p=*/false));
+
+  if (initp && priority == DEFAULT_INIT_PRIORITY
+      && c_dialect_objc () && objc_static_init_needed_p ())
+    /* For Objective-C++, we may need to initialize metadata found in
+       this module.  This must be done _before_ any other static
+       initializations.  */
+    objc_generate_static_init_call (NULL_TREE);
+
+  /* Call the static init/fini functions.  */
+  for (tree node = fns; node; node = TREE_CHAIN (node))
     {
-      bool objc = c_dialect_objc () && objc_static_init_needed_p ();
+      tree fn = TREE_PURPOSE (node);
 
-      /* We may have module initialization to emit and/or insert
-	 before other intializations.  */
-      if (module_initializer_kind () || objc)
-	body = start_objects (initp, priority);
+      // We should never find a pure or constant cdtor.
+      gcc_checking_assert (!(flags_from_decl_or_type (fn)
+			     & (ECF_CONST | ECF_PURE)));
 
-      /* For Objective-C++, we may need to initialize metadata found
-         in this module.  This must be done _before_ any other static
-         initializations.  */
-      if (objc)
-	objc_generate_static_init_call (NULL_TREE);
+      tree call = cp_build_function_call_nary (fn, tf_warning_or_error,
+					       NULL_TREE);
+      finish_expr_stmt (call);
     }
 
-  /* Call the static storage duration function with appropriate
-     arguments.  */
-  tree fndecl;
-  size_t i;
-  FOR_EACH_VEC_SAFE_ELT (ssdf_decls, i, fndecl)
-    {
-      /* Calls to pure or const functions will expand to nothing.  */
-      if (! (flags_from_decl_or_type (fndecl) & (ECF_CONST | ECF_PURE)))
-	{
-	  if (! body)
-	    body = start_objects (initp, priority);
-
-	  tree call = cp_build_function_call_nary (fndecl, tf_warning_or_error,
-						   build_int_cst (NULL_TREE,
-								  initp),
-						   build_int_cst (NULL_TREE,
-								  priority),
-						   NULL_TREE);
-	  finish_expr_stmt (call);
-	}
-    }
+  /* Revert what __asan_before_dynamic_init did by calling
+     __asan_after_dynamic_init.  */
+  if (initp && (flag_sanitize & SANITIZE_ADDRESS))
+    finish_expr_stmt (asan_dynamic_init_call (/*after_p=*/true));
 
   /* Close out the function.  */
-  if (body)
-    expand_or_defer_fn (finish_objects (initp, priority, body));
-}
-
-/* Generate constructor and destructor functions for the priority
-   indicated by N.  */
-
-static int
-generate_ctor_and_dtor_functions_for_priority (splay_tree_node n, void * data)
-{
-  location_t *locus = (location_t *) data;
-  int priority = (int) n->key;
-  priority_info pi = (priority_info) n->value;
-
-  /* Generate the functions themselves, but only if they are really
-     needed.  */
-  if (pi->initializations_p)
-    generate_ctor_or_dtor_function (/*initp=*/true, priority, locus);
-  if (pi->destructions_p)
-    generate_ctor_or_dtor_function (/*initp=*/false, priority, locus);
-
-  /* Keep iterating.  */
-  return 0;
+  expand_or_defer_fn (finish_objects (initp, priority, body));
 }
 
 /* Return C++ property of T, based on given operation OP.  */
@@ -5124,44 +5016,29 @@ c_parse_final_cleanups (void)
 	  /* Make sure the back end knows about all the variables.  */
 	  write_out_vars (vars);
 
-	  /* We need to start a new initialization function each time
-	     through the loop.  That's because we need to know which
-	     vtables have been referenced, and TREE_SYMBOL_REFERENCED
-	     isn't computed until a function is finished, and written
-	     out.  That's a deficiency in the back end.  When this is
-	     fixed, these initialization functions could all become
-	     inline, with resulting performance improvements.  */
-
-	  /* Set the line and file, so that it is obviously not from
-	     the source file.  */
-	  input_location = locus_at_end_of_parsing;
-	  tree ssdf_body = start_static_storage_duration_function (ssdf_count);
-
-	  /* First generate code to do all the initializations.  */
-	  do_static_initialization_or_destruction (/*initp=*/true, vars);
-
-	  /* Then, generate code to do all the destructions.  Do these
-	     in reverse order so that the most recently constructed
-	     variable is the first destroyed.  If we're using
-	     __cxa_atexit, then we don't need to do this; functions
-	     were registered at initialization time to destroy the
-	     local statics.  */
-	  if (!flag_use_cxa_atexit)
-	    {
-	      vars = nreverse (vars);
-	      do_static_initialization_or_destruction (/*initp=*/false, vars);
-	    }
+	  function_depth++; // Disable GC
+	  priority_map_t *parts[2] = {nullptr, nullptr};
+	  partition_vars_for_init_fini (vars, parts);
 
-	  /* Finish up the static storage duration function for this
-	     round.  */
-	  input_location = locus_at_end_of_parsing;
-	  finish_static_storage_duration_function (ssdf_body);
+	  for (unsigned initp = 2; initp--;)
+	    if (parts[initp])
+	      for (auto iter : *parts[initp])
+		{
+		  auto list = iter.second;
+		  if (initp)
+		    // Partitioning kept the vars in reverse order.
+		    // We only want that for dtors.
+		    list = nreverse (list);
+		  emit_partial_init_fini_fn (initp, iter.first, list,
+					     ssdf_count++,
+					     locus_at_end_of_parsing);
+		}
+	  function_depth--; // Re-enable GC
 
 	  /* All those initializations and finalizations might cause
 	     us to need more inline functions, more template
 	     instantiations, etc.  */
 	  reconsider = true;
-	  ssdf_count++;
 	}
 
       /* Now do the same for thread_local variables.  */
@@ -5327,22 +5204,33 @@ c_parse_final_cleanups (void)
   /* We give C linkage to static constructors and destructors.  */
   push_lang_context (lang_name_c);
 
+  if ((c_dialect_objc () && objc_static_init_needed_p ())
+      || module_initializer_kind ())
+    {
+      // Make sure there's a default priority entry.
+      if (!static_init_fini_fns[true])
+	static_init_fini_fns[true] = priority_map_t::create_ggc ();
+      static_init_fini_fns[true]->get_or_insert (DEFAULT_INIT_PRIORITY);
+    } 
+
   /* Generate initialization and destruction functions for all
      priorities for which they are required.  */
-  if (priority_info_map)
-    splay_tree_foreach (priority_info_map,
-			generate_ctor_and_dtor_functions_for_priority,
-			/*data=*/&locus_at_end_of_parsing);
-  else if ((c_dialect_objc () && objc_static_init_needed_p ())
-	   || module_initializer_kind ())
-    generate_ctor_or_dtor_function (/*constructor_p=*/true,
-				    DEFAULT_INIT_PRIORITY,
-				    &locus_at_end_of_parsing);
-
-  /* We're done with the splay-tree now.  */
-  if (priority_info_map)
-    splay_tree_delete (priority_info_map);
-
+  for (unsigned initp = 2; initp--;)
+    if (static_init_fini_fns[initp])
+      {
+	for (auto iter : *static_init_fini_fns[initp])
+	  {
+	    tree fns = iter.second;
+	    // The list of functions was constructed in reverse
+	    // order, which we only want for dtors.
+	    if (initp)
+	      fns = nreverse (fns);
+	    generate_ctor_or_dtor_function (initp, iter.first, fns,
+					    locus_at_end_of_parsing);
+	  }
+	static_init_fini_fns[initp] = nullptr;
+      }
+  
   fini_modules ();
 
   /* Generate any missing aliases.  */
diff --git a/gcc/testsuite/g++.dg/init/static-cdtor1.C b/gcc/testsuite/g++.dg/init/static-cdtor1.C
new file mode 100644
index 00000000000..343178a6114
--- /dev/null
+++ b/gcc/testsuite/g++.dg/init/static-cdtor1.C
@@ -0,0 +1,17 @@
+// { dg-do compile { target { lp64 && { i?86-*-linux* x86_64-*-linux* } } } }
+// { dg-additional-options -fno-use-cxa-atexit }
+// Make sure we emit initializers in the correct order.
+
+// ctors
+// { dg-final { scan-assembler {_Z41__static_initialization_and_destruction_0v:.*movl	\$var1[^\n]*\n[^\n]*_ZN5LeelaC1Ev[^\n]*\n[^\n]*movl	\$var2[^\n]*\n[^\n]*_ZN5LeelaC1Ev[^\n]*\n[^\n]*movl	\$var3[^\n]*\n[^\n]*_ZN5LeelaC1Ev} } }
+// dtors
+// { dg-final { scan-assembler {_Z41__static_initialization_and_destruction_1v:.*movl	\$var3[^\n]*\n[^\n]*_ZN5LeelaD1Ev[^\n]*\n[^\n]*movl	\$var2[^\n]*\n[^\n]*_ZN5LeelaD1Ev[^\n]*\n[^\n]*movl	\$var1[^\n]*\n[^\n]*_ZN5LeelaD1Ev} } }
+
+struct Leela {
+  Leela ();
+  ~Leela ();
+};
+
+Leela var1;
+Leela var2;
+Leela var3;


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-06-08 15:39 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-06-08 15:39 [gcc r13-1014] c++: Reimplement static init/fini generation Nathan Sidwell

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).