From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1059) id 76B8A38582B5; Thu, 16 Jun 2022 18:41:17 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 76B8A38582B5 MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Nathan Sidwell To: gcc-cvs@gcc.gnu.org Subject: [gcc r13-1137] c++: Elide inactive initializer fns from init array X-Act-Checkin: gcc X-Git-Author: Nathan Sidwell X-Git-Refname: refs/heads/master X-Git-Oldrev: 6c849e2fab3f682b715a81cb4ccc792f20c00eeb X-Git-Newrev: 9ca05d5d9b9b2bcbdc00add8a3b86d3c3361f1a1 Message-Id: <20220616184117.76B8A38582B5@sourceware.org> Date: Thu, 16 Jun 2022 18:41:17 +0000 (GMT) X-BeenThere: gcc-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 16 Jun 2022 18:41:17 -0000 https://gcc.gnu.org/g:9ca05d5d9b9b2bcbdc00add8a3b86d3c3361f1a1 commit r13-1137-g9ca05d5d9b9b2bcbdc00add8a3b86d3c3361f1a1 Author: Nathan Sidwell Date: Thu Jun 16 10:14:56 2022 -0700 c++: Elide inactive initializer fns from init array 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. Diff: --- gcc/cp/decl2.cc | 97 +++++++++++++++++---------------- gcc/testsuite/g++.dg/modules/init-2_b.C | 1 + gcc/testsuite/g++.dg/modules/init-2_c.C | 1 + 3 files changed, 53 insertions(+), 46 deletions(-) diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc index 0c4492f7354..3737e5f010c 100644 --- a/gcc/cp/decl2.cc +++ b/gcc/cp/decl2.cc @@ -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]) diff --git a/gcc/testsuite/g++.dg/modules/init-2_b.C b/gcc/testsuite/g++.dg/modules/init-2_b.C index 4350944139f..a98e67616a2 100644 --- a/gcc/testsuite/g++.dg/modules/init-2_b.C +++ b/gcc/testsuite/g++.dg/modules/init-2_b.C @@ -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-*-* } } } diff --git a/gcc/testsuite/g++.dg/modules/init-2_c.C b/gcc/testsuite/g++.dg/modules/init-2_c.C index 2b1315e2892..c386582b9c0 100644 --- a/gcc/testsuite/g++.dg/modules/init-2_c.C +++ b/gcc/testsuite/g++.dg/modules/init-2_c.C @@ -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-*-* } } }