From e8609768fbbc1ec650fe245cb45ee6d893ade3d7 Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Thu, 9 Jun 2022 11:18:19 -0700 Subject: [PATCH] c++: Elide calls to NOP module initializers gcc/cp * cp-tree.h (fini_modules): Add has_inits parm. * decl2.cc (c_parse_final_cleanups): Check for inits, adjust fini_modules flags. * module.cc (module_state): Rename call_init_p to active_init_p. (module_state::write_config): Write active_init. (module_state::read_config): Read it. (module_determine_import_inits): Clear active_init_p of covered inits. (late_finish_module): Add has_init parm. Record it. (fini_modules): Adjust. gcc/testsuite/ * g++.dg/modules/init-2_a.C: Adjust. * g++.dg/modules/init-2_c.C: Adjust. * g++.dg/modules/init-2_d.C: New. --- gcc/cp/cp-tree.h | 2 +- gcc/cp/decl2.cc | 10 ++++--- gcc/cp/module.cc | 49 ++++++++++++++++++++------------- gcc/testsuite/g++.dg/modules/init-2_a.C | 9 ++++-- gcc/testsuite/g++.dg/modules/init-2_c.C | 11 ++++---- gcc/testsuite/g++.dg/modules/init-2_d.C | 11 ++++++++ 6 files changed, 60 insertions(+), 32 deletions(-) create mode 100644 gcc/testsuite/g++.dg/modules/init-2_d.C diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 60d7b20..2fde4f8 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7209,7 +7209,7 @@ extern void import_module (module_state *, location_t, bool export_p, extern void declare_module (module_state *, location_t, bool export_p, tree attr, cpp_reader *); extern void init_modules (cpp_reader *); -extern void fini_modules (cpp_reader *, void *cookie); +extern void fini_modules (cpp_reader *, void *cookie, bool); extern void maybe_check_all_macros (cpp_reader *); extern void *finish_module_processing (cpp_reader *); extern char const *module_name (unsigned, bool header_ok); diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc index cc0b413..a8f3e6e 100644 --- a/gcc/cp/decl2.cc +++ b/gcc/cp/decl2.cc @@ -5205,7 +5205,8 @@ c_parse_final_cleanups (void) if (c_dialect_objc ()) objc_write_global_declarations (); - if (module_determine_import_inits ()) + bool has_module_inits = module_determine_import_inits (); + if (has_module_inits) { input_location = locus_at_end_of_parsing; tree body = start_partial_init_fini_fn (true, DEFAULT_INIT_PRIORITY, @@ -5221,8 +5222,9 @@ c_parse_final_cleanups (void) // 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); - } + if (static_init_fini_fns[true]->get_or_insert (DEFAULT_INIT_PRIORITY)) + has_module_inits = true; + } /* Generate initialization and destruction functions for all priorities for which they are required. They have C-language @@ -5238,7 +5240,7 @@ c_parse_final_cleanups (void) } pop_lang_context (); - fini_modules (parse_in, module_cookie); + fini_modules (parse_in, module_cookie, has_module_inits); /* Generate any missing aliases. */ maybe_apply_pending_pragma_weaks (); diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index e7ce40e..5566c49 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -3439,7 +3439,7 @@ class GTY((chain_next ("%h.parent"), for_user)) module_state { bool exported_p : 1; /* directness != MD_NONE && exported. */ bool cmi_noted_p : 1; /* We've told the user about the CMI, don't do it again */ - bool call_init_p : 1; /* This module's global initializer needs + bool active_init_p : 1; /* This module's global initializer needs calling. */ bool inform_cmi_p : 1; /* Inform of a read/write. */ bool visited_p : 1; /* A walk-once flag. */ @@ -3677,7 +3677,7 @@ module_state::module_state (tree name, module_state *parent, bool partition) exported_p = false; cmi_noted_p = false; - call_init_p = false; + active_init_p = false; partition_p = partition; @@ -14393,12 +14393,14 @@ struct module_state_config { unsigned ordinary_locs; unsigned macro_locs; unsigned ordinary_loc_align; + unsigned active_init; public: module_state_config () :dialect_str (get_dialect ()), num_imports (0), num_partitions (0), num_entities (0), - ordinary_locs (0), macro_locs (0), ordinary_loc_align (0) + ordinary_locs (0), macro_locs (0), ordinary_loc_align (0), + active_init (0) { } @@ -17336,7 +17338,9 @@ module_state::write_config (elf_out *to, module_state_config &config, cfg.u (config.ordinary_locs); cfg.u (config.macro_locs); - cfg.u (config.ordinary_loc_align); + cfg.u (config.ordinary_loc_align); + + cfg.u (config.active_init); /* Now generate CRC, we'll have incorporated the inner CRC because of its serialization above. */ @@ -17522,6 +17526,8 @@ module_state::read_config (module_state_config &config) config.macro_locs = cfg.u (); config.ordinary_loc_align = cfg.u (); + config.active_init = cfg.u (); + done: return cfg.end (from ()); } @@ -17922,6 +17928,9 @@ module_state::read_initial (cpp_reader *reader) if (ok && have_locs && !read_macro_maps ()) ok = false; + /* Note whether there's an active initializer. */ + active_init_p = !is_header () && bool (config.active_init); + gcc_assert (slurp->current == ~0u); return ok; } @@ -19047,10 +19056,10 @@ module_determine_import_inits () if (!modules || header_module_p ()) return false; - /* Determine call_init_p. We need the same bitmap allocation + /* Prune active_init_p. We need the same bitmap allocation scheme as for the imports member. */ function_depth++; /* Disable GC. */ - bitmap indirect_imports (BITMAP_GGC_ALLOC ()); + bitmap covered_imports (BITMAP_GGC_ALLOC ()); bool any = false; @@ -19060,16 +19069,15 @@ module_determine_import_inits () { module_state *import = (*modules)[ix]; - if (!import->is_header () - && !bitmap_bit_p (indirect_imports, ix)) + if (!import->active_init_p) + ; + else if (bitmap_bit_p (covered_imports, ix)) + import->active_init_p = false; + else { - /* Everything this imports is therefore indirectly - imported. */ - bitmap_ior_into (indirect_imports, import->imports); - /* We don't have to worry about the self-import bit, - because of the single pass. */ - - import->call_init_p = true; + /* Everything this imports is therefore handled by its + initializer, so doesn't need initializing by us. */ + bitmap_ior_into (covered_imports, import->imports); any = true; } } @@ -19098,7 +19106,7 @@ module_add_import_initializers () for (unsigned ix = modules->length (); --ix;) { module_state *import = (*modules)[ix]; - if (import->call_init_p) + if (import->active_init_p) { tree name = mangle_module_global_init (ix); tree fndecl = build_lang_decl (FUNCTION_DECL, name, fntype); @@ -19979,7 +19987,8 @@ finish_module_processing (cpp_reader *reader) // the module static initializer is a NOP or not. static void -late_finish_module (cpp_reader *reader, module_processing_cookie *cookie) +late_finish_module (cpp_reader *reader, module_processing_cookie *cookie, + bool init_fn_non_empty) { timevar_start (TV_MODULE_EXPORT); @@ -19987,6 +19996,7 @@ late_finish_module (cpp_reader *reader, module_processing_cookie *cookie) unsigned n = dump.push (state); state->announce ("finishing"); + cookie->config.active_init = init_fn_non_empty; if (cookie->began) state->write_end (&cookie->out, reader, cookie->config, cookie->crc); @@ -20029,11 +20039,12 @@ late_finish_module (cpp_reader *reader, module_processing_cookie *cookie) } void -fini_modules (cpp_reader *reader, void *cookie) +fini_modules (cpp_reader *reader, void *cookie, bool has_inits) { if (cookie) late_finish_module (reader, - static_cast (cookie)); + static_cast (cookie), + has_inits); /* We're done with the macro tables now. */ vec_free (macro_exports); diff --git a/gcc/testsuite/g++.dg/modules/init-2_a.C b/gcc/testsuite/g++.dg/modules/init-2_a.C index 4174cf5..c7ec782 100644 --- a/gcc/testsuite/g++.dg/modules/init-2_a.C +++ b/gcc/testsuite/g++.dg/modules/init-2_a.C @@ -2,6 +2,11 @@ export module Foo; // { dg-module-cmi Foo } +static int init () +{ + return 1; +} + +int var = init (); + // { 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_c.C b/gcc/testsuite/g++.dg/modules/init-2_c.C index 4ca880d..2b1315e 100644 --- a/gcc/testsuite/g++.dg/modules/init-2_c.C +++ b/gcc/testsuite/g++.dg/modules/init-2_c.C @@ -1,8 +1,7 @@ // { dg-additional-options "-fmodules-ts -fno-inline" } +export module Baz; +// { dg-module-cmi Baz } -import Foo; -import Bar; - -// We know Bar imports Foo, so only call Bar's Global Init -// { dg-final { scan-assembler {call[ \t]+_?_ZGIW3Bar} { target i?86-*-* x86_64-*-* } } } -// { dg-final { scan-assembler-not {call[ \t]+_?_ZGIW3Foo} { target i?86-*-* x86_64-*-* } } } +// { dg-final { scan-assembler {_ZGIW3Baz:} } } +// But it is empty, and so no idempotency bool +// { dg-final { scan-assembler-not {_ZZ9_ZGIW3BazE9__in_chrg} } } diff --git a/gcc/testsuite/g++.dg/modules/init-2_d.C b/gcc/testsuite/g++.dg/modules/init-2_d.C new file mode 100644 index 0000000..d125cfc --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/init-2_d.C @@ -0,0 +1,11 @@ +// { dg-additional-options "-fmodules-ts -fno-inline" } + +import Foo; +import Bar; +import Baz; + +// We know Bar imports Foo, so only call Bar's Global Init +// { dg-final { scan-assembler {call[ \t]+_?_ZGIW3Bar} { target i?86-*-* x86_64-*-* } } } +// { dg-final { scan-assembler-not {call[ \t]+_?_ZGIW3Foo} { target i?86-*-* x86_64-*-* } } } +// We know Baz has a nop init, so don't call it. +// { dg-final { scan-assembler-not {call[ \t]+_?_ZGIW3Baz} { target i?86-*-* x86_64-*-* } } } -- 2.7.4