]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: Elide inactive initializer fns from init array
authorNathan Sidwell <nathan@acm.org>
Thu, 16 Jun 2022 17:14:56 +0000 (10:14 -0700)
committerNathan Sidwell <nathan@acm.org>
Thu, 16 Jun 2022 18:41:07 +0000 (11:41 -0700)
There's no point adding no-op initializer fns (that a module might
have) to the static initializer list.  Also, we can add any objc
initializer call to a partial initializer function and simplify some
control flow.

gcc/cp/
* decl2.cc (finish_objects): Add startp parameter, adjust.
(generate_ctor_or_dtor_function): Detect empty fn, and don't
generate unnecessary code.  Remove objc startup here ...
(c_parse_final_cleanyps): ... do it here.

gcc/testsuite/
* g++.dg/modules/init-2_b.C: Add init check.
* g++.dg/modules/init-2_c.C: Add init check.

gcc/cp/decl2.cc
gcc/testsuite/g++.dg/modules/init-2_b.C
gcc/testsuite/g++.dg/modules/init-2_c.C

index 0c4492f7354c449d88fd5aad5b46fe6cb8544f7e..3737e5f010cf82bc847599c6a1fa21fd484930f6 100644 (file)
@@ -56,7 +56,7 @@ int raw_dump_id;
 extern cpp_reader *parse_in;
 
 static tree start_objects (bool, unsigned, bool);
-static tree finish_objects (bool, unsigned, tree);
+static tree finish_objects (bool, unsigned, tree, bool = true);
 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,
@@ -3932,16 +3932,19 @@ start_objects (bool initp, unsigned priority, bool has_body)
   return body;
 }
 
-/* Finish a global constructor or destructor.  */
+/* Finish a global constructor or destructor.  Add it to the global
+   ctors or dtors, if STARTP is true.  */
 
 static tree
-finish_objects (bool initp, unsigned priority, tree body)
+finish_objects (bool initp, unsigned priority, tree body, bool startp)
 {
   /* Finish up.  */
   finish_compound_stmt (body);
   tree fn = finish_function (/*inline_p=*/false);
 
-  if (initp)
+  if (!startp)
+    ; // Neither ctor nor dtor I be.
+  else if (initp)
     {
       DECL_STATIC_CONSTRUCTOR (fn) = 1;
       decl_init_priority_insert (fn, priority);
@@ -4307,58 +4310,54 @@ write_out_vars (tree vars)
     }
 }
 
-/* Generate a static constructor (if CONSTRUCTOR_P) or destructor
-   (otherwise) that will initialize all global objects with static
-   storage duration having the indicated PRIORITY.  */
+/* Generate a static constructor or destructor that calls the given
+   init/fini fns at the indicated priority.  */
 
 static void
 generate_ctor_or_dtor_function (bool initp, unsigned priority,
                                tree fns, location_t locus)
 {
   input_location = locus;
-
   tree body = start_objects (initp, priority, bool (fns));
 
-  /* 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 (fns)
+    {
+      /* 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));
+
+      /* Call the static init/fini functions.  */
+      for (tree node = fns; node; node = TREE_CHAIN (node))
+       {
+         tree fn = TREE_PURPOSE (node);
 
-  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);
+         // We should never find a pure or constant cdtor.
+         gcc_checking_assert (!(flags_from_decl_or_type (fn)
+                                & (ECF_CONST | ECF_PURE)));
 
-  /* Call the static init/fini functions.  */
-  for (tree node = fns; node; node = TREE_CHAIN (node))
-    {
-      tree fn = TREE_PURPOSE (node);
-
-      // We should never find a pure or constant cdtor.
-      gcc_checking_assert (!(flags_from_decl_or_type (fn)
-                            & (ECF_CONST | ECF_PURE)));
+         tree call = cp_build_function_call_nary (fn, tf_warning_or_error,
+                                                  NULL_TREE);
+         finish_expr_stmt (call);
+       }
 
-      tree call = cp_build_function_call_nary (fn, tf_warning_or_error,
-                                              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));
     }
 
-  /* 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, and arrange for it to be called at init
-     or fini time.  (Even module initializer functions need this, as
-     we cannot guarantee the module is imported somewhere in the programq.)  */
-  expand_or_defer_fn (finish_objects (initp, priority, body));
+     or fini time, if non-empty.  (Even non-nop module initializer
+     functions need this, as we cannot guarantee the module is
+     imported somewhere in the program.)  */
+  expand_or_defer_fn (finish_objects (initp, priority, body, fns != NULL_TREE));
 }
 
 /* Return C++ property of T, based on given operation OP.  */
@@ -5206,18 +5205,24 @@ c_parse_final_cleanups (void)
     objc_write_global_declarations ();
 
   bool has_module_inits = module_determine_import_inits ();
-  if (has_module_inits)
+  bool has_objc_init = c_dialect_objc () && objc_static_init_needed_p ();
+  if (has_module_inits || has_objc_init)
     {
       input_location = locus_at_end_of_parsing;
       tree body = start_partial_init_fini_fn (true, DEFAULT_INIT_PRIORITY,
                                              ssdf_count++);
-      module_add_import_initializers ();
+      /* For Objective-C++, we may need to initialize metadata found
+        in this module.  This must be done _before_ any other static
+        initializations.  */
+      if (has_objc_init)
+       objc_generate_static_init_call (NULL_TREE);
+      if (has_module_inits)
+       module_add_import_initializers ();
       input_location = locus_at_end_of_parsing;
       finish_partial_init_fini_fn (body);
     }
 
-  if ((c_dialect_objc () && objc_static_init_needed_p ())
-      || module_global_init_needed ())
+  if (module_global_init_needed ())
     {
       // Make sure there's a default priority entry.
       if (!static_init_fini_fns[true])
index 4350944139f6cec42469331a78819d8b8e79c009..a98e67616a2ebf845a51534901ae08c20f212862 100644 (file)
@@ -8,3 +8,4 @@ import Foo;
 // There should be an idempotency check
 // { dg-final { scan-assembler {_ZZ9_ZGIW3BarE9__in_chrg} } }
 // { dg-final { scan-assembler {call[ \t]+_?_ZGIW3Foo} { target i?86-*-* x86_64-*-* } } }
+// { dg-final { scan-assembler {.(quad|long)[ \t]+_ZGIW3Bar} { target i?86-*-* x86_64-*-* } } }
index 2b1315e2892f5577318e6c3808a5f5893db9dd81..c386582b9c0c607bffb2c9431696e20ac77a5823 100644 (file)
@@ -5,3 +5,4 @@ export module Baz;
 // { dg-final { scan-assembler {_ZGIW3Baz:} } }
 // But it is empty, and so no idempotency bool
 // { dg-final { scan-assembler-not {_ZZ9_ZGIW3BazE9__in_chrg} } }
+// { dg-final { scan-assembler-not {.(quad|long)[ \t]+_ZGIW3Baz} { target i?86-*-* x86_64-*-* } } }