diff mbox series

c++: Better module initializer code

Message ID ce37f56d-190b-4f77-5643-c136a6a71207@acm.org
State New
Headers show
Series c++: Better module initializer code | expand

Commit Message

Nathan Sidwell June 9, 2022, 1:23 p.m. UTC
Every module interface needs to emit a global initializer, but it
might have nothing to init.  In those cases, there's no need for any
idempotency boolean to be emitted.

nathan
diff mbox series

Patch

From 227ffed7dbbdffeeb5bc013852d61a97aa468c62 Mon Sep 17 00:00:00 2001
From: Nathan Sidwell <nathan@acm.org>
Date: Wed, 8 Jun 2022 11:25:14 -0700
Subject: [PATCH] c++: Better module initializer code

Every module interface needs to emit a global initializer, but it
might have nothing to init.  In those cases, there's no need for any
idempotency boolean to be emitted.

	gcc/cp
	* cp-tree.h (module_initializer_kind): Replace with ...
	(module_global_init_needed, module_has_import_inits): ...
	these.
	* decl2.cc (start_objects): Add has_body parm.  Reorganize
	module initializer creation.
	(generate_ctor_or_dtor_function): Adjust.
	(c_parse_final_cleanups): Adjust.
	(vtv_start_verification_constructor_init_function): Adjust.
	* module.cc (module_initializer_kind): Replace with ...
	(module_global_init_needed, module_has_import_inits): ...
	these.

	gcc/testsuite/
	* g++.dg/modules/init-2_a.C: Check no idempotency.
	* g++.dg/modules/init-2_b.C: Check idempotency.
---
 gcc/cp/cp-tree.h                        |  3 ++-
 gcc/cp/decl2.cc                         | 32 +++++++++++++------------
 gcc/cp/module.cc                        | 23 +++++++++---------
 gcc/testsuite/g++.dg/modules/init-2_a.C |  2 ++
 gcc/testsuite/g++.dg/modules/init-2_b.C |  2 ++
 5 files changed, 34 insertions(+), 28 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 3d8a08b8dd7..a5d93282167 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7179,7 +7179,8 @@  extern module_state *get_module (tree name, module_state *parent = NULL,
 				 bool partition = false);
 extern bool module_may_redeclare (tree decl);
 
-extern int module_initializer_kind ();
+extern bool module_global_init_needed ();
+extern bool module_has_import_inits ();
 extern void module_add_import_initializers ();
 
 /* Where the namespace-scope decl was originally declared.  */
diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc
index bfb6a32e3b6..9de9a7a4f8a 100644
--- a/gcc/cp/decl2.cc
+++ b/gcc/cp/decl2.cc
@@ -55,7 +55,7 @@  int raw_dump_id;
  
 extern cpp_reader *parse_in;
 
-static tree start_objects (bool, unsigned);
+static tree start_objects (bool, unsigned, bool);
 static tree finish_objects (bool, unsigned, tree);
 static tree start_partial_init_fini_fn (bool, unsigned, unsigned);
 static void finish_partial_init_fini_fn (tree);
@@ -3848,15 +3848,13 @@  generate_tls_wrapper (tree fn)
 /* Start a global constructor or destructor function.  */
 
 static tree
-start_objects (bool initp, unsigned priority)
+start_objects (bool initp, unsigned priority, bool has_body)
 {
-  int module_init = 0;
-
-  if (priority == DEFAULT_INIT_PRIORITY && initp)
-    module_init = module_initializer_kind ();
-
+  bool default_init = initp && priority == DEFAULT_INIT_PRIORITY;
+  bool is_module_init = default_init && module_global_init_needed ();
   tree name = NULL_TREE;
-  if (module_init > 0)
+
+  if (is_module_init)
     name = mangle_module_global_init (0);
   else
     {
@@ -3880,7 +3878,7 @@  start_objects (bool initp, unsigned priority)
   tree fntype =	build_function_type (void_type_node, void_list_node);
   tree fndecl = build_lang_decl (FUNCTION_DECL, name, fntype);
   DECL_CONTEXT (fndecl) = FROB_CONTEXT (global_namespace);
-  if (module_init > 0)
+  if (is_module_init)
     {
       SET_DECL_ASSEMBLER_NAME (fndecl, name);
       TREE_PUBLIC (fndecl) = true;
@@ -3905,8 +3903,10 @@  start_objects (bool initp, unsigned priority)
 
   tree body = begin_compound_stmt (BCS_FN_BODY);
 
-  if (module_init > 0)
+  bool has_import_inits = default_init && module_has_import_inits ();
+  if (is_module_init && (has_import_inits || has_body))
     {
+      // If the function is going to be empty, don't emit idempotency.
       // 'static bool __in_chrg = false;
       // if (__inchrg) return;
       // __inchrg = true
@@ -3930,7 +3930,7 @@  start_objects (bool initp, unsigned priority)
       finish_expr_stmt (assign);
     }
 
-  if (module_init)
+  if (has_import_inits)
     module_add_import_initializers ();
 
   return body;
@@ -4321,7 +4321,7 @@  generate_ctor_or_dtor_function (bool initp, unsigned priority,
 {
   input_location = locus;
 
-  tree body = start_objects (initp, priority);
+  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
@@ -4359,7 +4359,9 @@  generate_ctor_or_dtor_function (bool initp, unsigned priority,
   if (initp && (flag_sanitize & SANITIZE_ADDRESS))
     finish_expr_stmt (asan_dynamic_init_call (/*after_p=*/true));
 
-  /* Close out the function.  */
+  /* 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));
 }
 
@@ -5205,7 +5207,7 @@  c_parse_final_cleanups (void)
   push_lang_context (lang_name_c);
 
   if ((c_dialect_objc () && objc_static_init_needed_p ())
-      || module_initializer_kind ())
+      || module_global_init_needed () || module_has_import_inits ())
     {
       // Make sure there's a default priority entry.
       if (!static_init_fini_fns[true])
@@ -5871,7 +5873,7 @@  mark_used (tree decl)
 tree
 vtv_start_verification_constructor_init_function (void)
 {
-  return start_objects (/*initp=*/true, MAX_RESERVED_INIT_PRIORITY - 1);
+  return start_objects (/*initp=*/true, MAX_RESERVED_INIT_PRIORITY - 1, true);
 }
 
 tree
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index d1dc73724d1..7e36996c0fc 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -19026,22 +19026,21 @@  declare_module (module_state *module, location_t from_loc, bool exporting_p,
     }
 }
 
-/* +1, we're the primary or a partition.  Therefore emitting a
-   globally-callable idemportent initializer function.
-   -1, we have direct imports.  Therefore emitting calls to their
-   initializers.  */
+/* Return true IFF we must emit a module global initializer function
+   (which will be called by importers' init code).  */
 
-int
-module_initializer_kind ()
+bool
+module_global_init_needed ()
 {
-  int result = 0;
+  return module_has_cmi_p () && !header_module_p ();
+}
 
-  if (module_has_cmi_p () && !header_module_p ())
-    result = +1;
-  else if (num_init_calls_needed)
-    result = -1;
+/* Return true IFF we have import global inits to call.  */
 
-  return result;
+bool
+module_has_import_inits ()
+{
+  return bool (num_init_calls_needed);
 }
 
 /* Emit calls to each direct import's global initializer.  Including
diff --git a/gcc/testsuite/g++.dg/modules/init-2_a.C b/gcc/testsuite/g++.dg/modules/init-2_a.C
index c0390a1b56e..4174cf53911 100644
--- a/gcc/testsuite/g++.dg/modules/init-2_a.C
+++ b/gcc/testsuite/g++.dg/modules/init-2_a.C
@@ -3,3 +3,5 @@  export module Foo;
 // { dg-module-cmi Foo }
 
 // { dg-final { scan-assembler {_ZGIW3Foo:} } }
+// But it is empty, and so no idempotency bool
+// { dg-final { scan-assembler-not {_ZZ9_ZGIW3FooE9__in_chrg} } }
diff --git a/gcc/testsuite/g++.dg/modules/init-2_b.C b/gcc/testsuite/g++.dg/modules/init-2_b.C
index 912ee406931..4350944139f 100644
--- a/gcc/testsuite/g++.dg/modules/init-2_b.C
+++ b/gcc/testsuite/g++.dg/modules/init-2_b.C
@@ -5,4 +5,6 @@  export module Bar;
 import Foo;
 
 // { dg-final { scan-assembler {_?_ZGIW3Bar:} } }
+// 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-*-* } } }
-- 
2.30.2