@@ -1480,6 +1480,7 @@ OBJS = \
ipa-reference.o \
ipa-ref.o \
ipa-utils.o \
+ ipa-strub.o \
ipa.o \
ira.o \
ira-build.o \
@@ -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;
}
@@ -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;
@@ -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. */
new file mode 100644
@@ -0,0 +1,45 @@
+/* strub (stack scrubbing) infrastructure.
+ Copyright (C) 2021-2022 Free Software Foundation, Inc.
+ Contributed by Alexandre Oliva <oliva@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);
@@ -536,7 +536,7 @@ public:
bool
pass_target_clone::gate (function *)
{
- return true;
+ return !seen_error ();
}
} // anon namespace
@@ -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);
@@ -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",
@@ -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);
@@ -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))