Introduce the new strub passes, adjust other passes and front-end declaration for strub.
for gcc/ChangeLog * Makefile.in (OBJS): Add ipa-strub.o. * ipa-inline.cc: Include ipa-strub.h. (can_inline_edge_p): Test strub_inlinable_to_p. * ipa-split.cc: Include ipa-strub.h. (execute_split_functions): Test strub_splittable_p. * ipa-strub.h: New. * passes.def: Add strub_mode and strub passes. * tree-cfg.cc (gimple_verify_flow_info): Note on debug stmts. * tree-pass.h (make_pass_ipa_strub_mode): Declare. (make_pass_ipa_strub): Declare. (make_pass_ipa_function_and_variable_visibility): Fix formatting. * tree-ssa-ccp.cc (optimize_stack_restore): Keep restores before strub leave. * multiple_target.cc (pass_target_clone::gate): Test seen_error. for gcc/ada/ChangeLog * gcc-interface/trans.cc: Include ipa-strub.h. (gigi): Make internal decls for targets of compiler-generated calls strub-callable too. (build_raise_check): Likewise. diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 203f0a15187d2..4100531d73ae7 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1480,6 +1480,7 @@ OBJS = \ ipa-reference.o \ ipa-ref.o \ ipa-utils.o \ + ipa-strub.o \ ipa.o \ ira.o \ ira-build.o \ diff --git a/gcc/ada/gcc-interface/trans.cc b/gcc/ada/gcc-interface/trans.cc index c1dd567b2e4e2..e3553a7a87bfc 100644 --- a/gcc/ada/gcc-interface/trans.cc +++ b/gcc/ada/gcc-interface/trans.cc @@ -69,6 +69,21 @@ #include "ada-tree.h" #include "gigi.h" +/* The following #include is for strub_make_callable. + + This function marks a function as safe to call from strub contexts. We mark + Ada subprograms that may be called implicitly by the compiler, and that won't + leave on the stack caller data passed to them. This stops implicit calls + introduced in subprograms that have their stack scrubbed from being flagged + as unsafe, even in -fstrub=strict mode. + + These subprograms are also marked with the strub(callable) attribute in Ada + sources, but their declarations aren't necessarily imported by GNAT, or made + visible to gigi, in units that end up relying on them. So when gigi + introduces their declarations on its own, it must also add the attribute, by + calling strub_make_callable. */ +#include "ipa-strub.h" + /* We should avoid allocating more than ALLOCA_THRESHOLD bytes via alloca, for fear of running out of stack space. If we need more, we use xmalloc instead. */ @@ -449,6 +464,7 @@ gigi (Node_Id gnat_root, int64_type, NULL_TREE), NULL_TREE, is_default, true, true, true, false, false, NULL, Empty); + strub_make_callable (mulv64_decl); if (Enable_128bit_Types) { @@ -461,6 +477,7 @@ gigi (Node_Id gnat_root, NULL_TREE), NULL_TREE, is_default, true, true, true, false, false, NULL, Empty); + strub_make_callable (mulv128_decl); } /* Name of the _Parent field in tagged record types. */ @@ -716,6 +733,7 @@ build_raise_check (int check, enum exception_info_kind kind) = create_subprog_decl (get_identifier (Name_Buffer), NULL_TREE, ftype, NULL_TREE, is_default, true, true, true, false, false, NULL, Empty); + strub_make_callable (result); return result; } diff --git a/gcc/ipa-inline.cc b/gcc/ipa-inline.cc index 14969198cde1c..0674fe138574d 100644 --- a/gcc/ipa-inline.cc +++ b/gcc/ipa-inline.cc @@ -119,6 +119,7 @@ along with GCC; see the file COPYING3. If not see #include "stringpool.h" #include "attribs.h" #include "asan.h" +#include "ipa-strub.h" typedef fibonacci_heap <sreal, cgraph_edge> edge_heap_t; typedef fibonacci_node <sreal, cgraph_edge> edge_heap_node_t; @@ -397,6 +398,11 @@ can_inline_edge_p (struct cgraph_edge *e, bool report, inlinable = false; } + if (inlinable && !strub_inlinable_to_p (callee, caller)) + { + e->inline_failed = CIF_UNSPECIFIED; + inlinable = false; + } if (!inlinable && report) report_inline_failed_reason (e); return inlinable; diff --git a/gcc/ipa-split.cc b/gcc/ipa-split.cc index 16734617d0381..b3b9963f13669 100644 --- a/gcc/ipa-split.cc +++ b/gcc/ipa-split.cc @@ -104,6 +104,7 @@ along with GCC; see the file COPYING3. If not see #include "ipa-fnsummary.h" #include "cfgloop.h" #include "attribs.h" +#include "ipa-strub.h" /* Per basic block info. */ @@ -1810,6 +1811,12 @@ execute_split_functions (void) "section.\n"); return 0; } + if (!strub_splittable_p (node)) + { + if (dump_file) + fprintf (dump_file, "Not splitting: function is a strub context.\n"); + return 0; + } /* We enforce splitting after loop headers when profile info is not available. */ diff --git a/gcc/ipa-strub.h b/gcc/ipa-strub.h new file mode 100644 index 0000000000000..29869fadfa6c9 --- /dev/null +++ b/gcc/ipa-strub.h @@ -0,0 +1,45 @@ +/* strub (stack scrubbing) infrastructure. + Copyright (C) 2021-2022 Free Software Foundation, Inc. + Contributed by Alexandre Oliva <ol...@adacore.com>. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +/* Return TRUE if CALLEE can be inlined into CALLER, as far as stack scrubbing + constraints are concerned. CALLEE doesn't have to be called directly by + CALLER, but the returned value says nothing about intervening functions. */ +extern bool strub_inlinable_to_p (cgraph_node *callee, cgraph_node *caller); + +/* Return FALSE if NODE is a strub context, and TRUE otherwise. */ +extern bool strub_splittable_p (cgraph_node *node); + +/* Locate and return the watermark_ptr parameter for FNDECL. If FNDECL is not a + strub context, return NULL. */ +extern tree strub_watermark_parm (tree fndecl); + +/* Make a function type or declaration callable. */ +extern void strub_make_callable (tree fndecl); + +/* Return zero iff ID is NOT an acceptable parameter for a user-supplied strub + attribute for a function. Otherwise, return >0 if it enables strub, <0 if it + does not. Return +/-1 if the attribute-modified type is compatible with the + type without the attribute, or +/-2 if it is not compatible. */ +extern int strub_validate_fn_attr_parm (tree id); + +/* Like comptypes, return 0 if t1 and t2 are not compatible, 1 if they are + compatible, and 2 if they are nearly compatible. Same strub mode is + compatible, interface-compatible strub modes are nearly compatible. */ +extern int strub_comptypes (tree t1, tree t2); diff --git a/gcc/multiple_target.cc b/gcc/multiple_target.cc index 3e2d26882c8e9..7cbd0a571e1ff 100644 --- a/gcc/multiple_target.cc +++ b/gcc/multiple_target.cc @@ -536,7 +536,7 @@ public: bool pass_target_clone::gate (function *) { - return true; + return !seen_error (); } } // anon namespace diff --git a/gcc/passes.def b/gcc/passes.def index 6bb92efacd451..513c5c29cd281 100644 --- a/gcc/passes.def +++ b/gcc/passes.def @@ -52,6 +52,7 @@ along with GCC; see the file COPYING3. If not see INSERT_PASSES_AFTER (all_small_ipa_passes) NEXT_PASS (pass_ipa_free_lang_data); NEXT_PASS (pass_ipa_function_and_variable_visibility); + NEXT_PASS (pass_ipa_strub_mode); NEXT_PASS (pass_build_ssa_passes); PUSH_INSERT_PASSES_WITHIN (pass_build_ssa_passes) NEXT_PASS (pass_fixup_cfg); @@ -113,6 +114,7 @@ along with GCC; see the file COPYING3. If not see POP_INSERT_PASSES () NEXT_PASS (pass_ipa_remove_symbols); + NEXT_PASS (pass_ipa_strub); NEXT_PASS (pass_ipa_oacc); PUSH_INSERT_PASSES_WITHIN (pass_ipa_oacc) NEXT_PASS (pass_ipa_pta); diff --git a/gcc/tree-cfg.cc b/gcc/tree-cfg.cc index 5bcf78198e78b..6144b9ee4fca4 100644 --- a/gcc/tree-cfg.cc +++ b/gcc/tree-cfg.cc @@ -5658,6 +5658,7 @@ gimple_verify_flow_info (void) { gimple *stmt = gsi_stmt (gsi); + /* Do NOT disregard debug stmts after found_ctrl_stmt. */ if (found_ctrl_stmt) { error ("control flow in the middle of basic block %d", diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h index 4dfe05ed8e0de..ecf1f9ef28b12 100644 --- a/gcc/tree-pass.h +++ b/gcc/tree-pass.h @@ -502,8 +502,9 @@ extern gimple_opt_pass *make_pass_adjust_alignment (gcc::context *ctxt); /* IPA Passes */ extern simple_ipa_opt_pass *make_pass_ipa_lower_emutls (gcc::context *ctxt); -extern simple_ipa_opt_pass - *make_pass_ipa_function_and_variable_visibility (gcc::context *ctxt); +extern simple_ipa_opt_pass *make_pass_ipa_function_and_variable_visibility (gcc::context *ctxt); +extern simple_ipa_opt_pass *make_pass_ipa_strub_mode (gcc::context *ctxt); +extern simple_ipa_opt_pass *make_pass_ipa_strub (gcc::context *ctxt); extern simple_ipa_opt_pass *make_pass_ipa_tree_profile (gcc::context *ctxt); extern simple_ipa_opt_pass *make_pass_ipa_auto_profile (gcc::context *ctxt); diff --git a/gcc/tree-ssa-ccp.cc b/gcc/tree-ssa-ccp.cc index 85c046078249c..8d04e55ba6523 100644 --- a/gcc/tree-ssa-ccp.cc +++ b/gcc/tree-ssa-ccp.cc @@ -3054,7 +3054,9 @@ optimize_stack_restore (gimple_stmt_iterator i) if (!callee || !fndecl_built_in_p (callee, BUILT_IN_NORMAL) /* All regular builtins are ok, just obviously not alloca. */ - || ALLOCA_FUNCTION_CODE_P (DECL_FUNCTION_CODE (callee))) + || ALLOCA_FUNCTION_CODE_P (DECL_FUNCTION_CODE (callee)) + /* Do not remove stack updates before strub leave. */ + || fndecl_built_in_p (callee, BUILT_IN___STRUB_LEAVE)) return NULL_TREE; if (fndecl_built_in_p (callee, BUILT_IN_STACK_RESTORE)) -- Alexandre Oliva, happy hacker https://FSFLA.org/blogs/lxo/ Free Software Activist GNU Toolchain Engineer Disinformation flourishes because many people care deeply about injustice but very few check the facts. Ask me about <https://stallmansupport.org>