public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc(refs/users/aoliva/heads/strub)] make builtins callable
@ 2021-07-26 15:43 Alexandre Oliva
0 siblings, 0 replies; 7+ messages in thread
From: Alexandre Oliva @ 2021-07-26 15:43 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:32ad884ca9b25daf7610e32e77e2a88a4037404f
commit 32ad884ca9b25daf7610e32e77e2a88a4037404f
Author: Alexandre Oliva <oliva@adacore.com>
Date: Mon Jul 26 12:15:36 2021 -0300
make builtins callable
Diff:
---
gcc/ipa-strub.c | 251 +++++++++++++++++++++-----------------------------------
1 file changed, 95 insertions(+), 156 deletions(-)
diff --git a/gcc/ipa-strub.c b/gcc/ipa-strub.c
index 7b05321e980..18c1c9fedd4 100644
--- a/gcc/ipa-strub.c
+++ b/gcc/ipa-strub.c
@@ -438,6 +438,34 @@ strub_from_body_p (cgraph_node *node)
return false;
}
+/* Return true iff node is associated with a builtin that should be callable
+ from strub contexts. */
+static inline bool
+strub_callable_builtin_p (cgraph_node *node)
+{
+ if (DECL_BUILT_IN_CLASS (node->decl) != BUILT_IN_NORMAL)
+ return false;
+
+ enum built_in_function fcode = DECL_FUNCTION_CODE (node->decl);
+
+ switch (fcode)
+ {
+ case BUILT_IN_NONE:
+ gcc_unreachable ();
+
+ /* ??? Make all builtins callable. We wish to make any builtin call the
+ compiler might introduce on its own callable. Anything that is
+ predictable enough as to be known not to allow stack data that should
+ be strubbed to unintentionally escape to non-strub contexts can be
+ allowed, and pretty much every builtin appears to fit this description.
+ The exceptions to this rule seem to be rare, and only available as
+ explicit __builtin calls, so let's keep it simple and allow all of
+ them... */
+ default:
+ return true;
+ }
+}
+
static enum strub_mode
compute_strub_mode (cgraph_node *node, tree strub_attr)
{
@@ -495,7 +523,8 @@ compute_strub_mode (cgraph_node *node, tree strub_attr)
= (!strub_flag_disabled
&& (strub_attr
? req_mode == STRUB_CALLABLE
- : strub_flag_viable));
+ : (strub_flag_viable
+ || strub_callable_builtin_p (node))));
/* This is a shorthand for either strub-enabled mode. */
const bool consider_strub
@@ -845,6 +874,49 @@ strub_inlinable_p (cgraph_node *callee, cgraph_node *caller)
return false;
}
+/* Check that strub functions don't call non-strub functions, and that
+ always_inline strub functions are only called by strub
+ functions. */
+static void
+verify_strub ()
+{
+ cgraph_node *node;
+
+ FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
+ {
+ enum strub_mode caller_mode = get_strub_mode (node);
+ bool strub_context
+ = (caller_mode == STRUB_AT_CALLS
+ || caller_mode == STRUB_WRAPPED
+ || caller_mode == STRUB_INLINABLE);
+
+ for (cgraph_edge *e = node->callees; e; e = e->next_callee)
+ if (e->indirect_unknown_callee)
+ {
+ if (!strub_context)
+ continue;
+
+ tree callee_fntype = gimple_call_fntype (e->call_stmt);
+ enum strub_mode callee_mode
+ = get_strub_mode_from_type (callee_fntype);
+
+ if (callee_mode == STRUB_DISABLED
+ || callee_mode == STRUB_INTERNAL)
+ error_at (gimple_location (e->call_stmt),
+ "indirect non-strub call in strub context %qD",
+ node->decl);
+ }
+ else if (!strub_callable_from_p (e->callee, node))
+ error_at (gimple_location (e->call_stmt),
+ "calling non-strub %qD in strub context %qD",
+ e->callee->decl, node->decl);
+ }
+
+ /* ??? Check strub-wise pointer type compatibility of variables and
+ functions, or is this already taken care of on account of the
+ attribute's being marked as affecting type identity? */
+}
+
namespace {
const pass_data pass_data_ipa_strub_mode = {
@@ -1014,116 +1086,6 @@ public:
} // anon namespace
-#if 0
-static bool
-may_throw_p (gcall *stmt)
-{
- return flag_exceptions && !gimple_call_nothrow_p (stmt);
-}
-
-static bool
-strub_this_call_p (gcall *stmt)
-{
- if (gimple_call_internal_p (stmt))
- return false;
-
- /* If there's no outgoing path in which to do the scrubbing, don't
- bother. */
- if (gimple_call_noreturn_p (stmt) && !may_throw_p (stmt))
- return false;
-
- /* ??? Maybe non-mandatory tail calls should be disabled for
- scrubbing. Or maybe it won't matter, as long as both tail-caller
- and callee are scrubbing-capable. */
- if (gimple_call_must_tail_p (stmt) || gimple_call_tail_p (stmt))
- return false;
-
- if (gimple_alloca_call_p (stmt))
- return true;
-
- tree fndecl = gimple_call_fndecl (stmt);
- if (!fndecl)
- return true;
-
- if (DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL)
- return true;
-
- enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
-
- switch (fcode)
- {
- CASE_BUILT_IN_ALLOCA:
- return true;
-
- case BUILT_IN_NONE:
- return true;
-
- case BUILT_IN___STRUB_ENTER:
- case BUILT_IN___STRUB_UPDATE:
- case BUILT_IN___STRUB_LEAVE:
- return false;
-
- case BUILT_IN_CLASSIFY_TYPE:
- case BUILT_IN_CONSTANT_P:
- return false;
-
- case BUILT_IN_RETURN_ADDRESS:
- case BUILT_IN_FRAME_ADDRESS:
- case BUILT_IN_STACK_ADDRESS:
- case BUILT_IN_AGGREGATE_INCOMING_ADDRESS:
- return false;
-
- case BUILT_IN_STACK_SAVE:
- case BUILT_IN_STACK_RESTORE:
- case BUILT_IN_ASAN_ALLOCAS_UNPOISON:
- return false;
-
- case BUILT_IN_SETJMP_SETUP:
- case BUILT_IN_SETJMP_RECEIVER:
- case BUILT_IN_LONGJMP:
- case BUILT_IN_NONLOCAL_GOTO:
- case BUILT_IN_UPDATE_SETJMP_BUF:
- case BUILT_IN_TRAP:
- case BUILT_IN_UNREACHABLE:
- return false;
-
- case BUILT_IN_UNWIND_INIT:
- case BUILT_IN_DWARF_CFA:
-#ifdef DWARF2_UNWIND_INFO
- case BUILT_IN_DWARF_SP_COLUMN:
- case BUILT_IN_INIT_DWARF_REG_SIZES:
-#endif
- case BUILT_IN_FROB_RETURN_ADDR:
- case BUILT_IN_EXTRACT_RETURN_ADDR:
- case BUILT_IN_EH_RETURN:
- case BUILT_IN_EH_RETURN_DATA_REGNO:
- case BUILT_IN_EXTEND_POINTER:
- case BUILT_IN_EH_POINTER:
- case BUILT_IN_EH_FILTER:
- case BUILT_IN_EH_COPY_VALUES:
- return false;
-
- case BUILT_IN_VA_START:
- case BUILT_IN_VA_END:
- case BUILT_IN_VA_COPY:
- case BUILT_IN_EXPECT:
- case BUILT_IN_EXPECT_WITH_PROBABILITY:
- case BUILT_IN_ASSUME_ALIGNED:
- case BUILT_IN_PREFETCH:
- return false;
-
- case BUILT_IN_ATOMIC_ALWAYS_LOCK_FREE:
- case BUILT_IN_OBJECT_SIZE:
- case BUILT_IN_THREAD_POINTER:
- case BUILT_IN_SET_THREAD_POINTER:
- return false;
-
- default:
- return true;
- }
-}
-#endif
-
typedef hash_set<tree> indirect_parms_t;
static tree
@@ -1414,6 +1376,9 @@ pass_ipa_strub_mode::execute (function *)
bool any_strub = false;
+ /* Go through the functions twice, once over non-aliases, and then over
+ aliases, so that aliases can reuse the mode computation of their ultimate
+ targets. */
for (int aliases = 0; aliases <= 1; aliases++)
FOR_EACH_FUNCTION (onode)
{
@@ -1428,6 +1393,9 @@ pass_ipa_strub_mode::execute (function *)
if (!any_strub)
flag_strub = 0;
+ else
+ /* Verify before any inlining or other transformations. */
+ verify_strub ();
return 0;
}
@@ -1438,49 +1406,6 @@ make_pass_ipa_strub_mode (gcc::context *ctxt)
return new pass_ipa_strub_mode (ctxt);
}
-/* Check that strub functions don't call non-strub functions, and that
- always_inline strub functions are only called by strub
- functions. */
-static void
-verify_strub ()
-{
- cgraph_node *node;
-
- FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
- {
- enum strub_mode caller_mode = get_strub_mode (node);
- bool strub_context
- = (caller_mode == STRUB_AT_CALLS
- || caller_mode == STRUB_WRAPPED
- || caller_mode == STRUB_INLINABLE);
-
- for (cgraph_edge *e = node->callees; e; e = e->next_callee)
- if (e->indirect_unknown_callee)
- {
- if (!strub_context)
- continue;
-
- tree callee_fntype = gimple_call_fntype (e->call_stmt);
- enum strub_mode callee_mode
- = get_strub_mode_from_type (callee_fntype);
-
- if (callee_mode == STRUB_DISABLED
- || callee_mode == STRUB_INTERNAL)
- error_at (gimple_location (e->call_stmt),
- "indirect non-strub call in strub context %qD",
- node->decl);
- }
- else if (!strub_callable_from_p (e->callee, node))
- error_at (gimple_location (e->call_stmt),
- "calling non-strub %qD in strub context %qD",
- e->callee->decl, node->decl);
- }
-
- /* ??? Check strub-wise pointer type compatibility of variables and
- functions, or is this already taken care of on account of the
- attribute's being marked as affecting type identity? */
-}
-
unsigned int
pass_ipa_strub::execute (function *)
{
@@ -2291,7 +2216,17 @@ pass_ipa_strub::execute (function *)
}
gimple_call_set_arg (call, 1, arg);
update_stmt (call);
- e->redirect_callee (cgraph_node::get_create (bvacopy));
+
+ /* If we are causing the cgraph_node for va_copy to be needed,
+ compute a strub mode for it to make it callable, otherwise
+ verify_strub would reject it. */
+ cgraph_node *vacopy_node = cgraph_node::get (bvacopy);
+ if (!vacopy_node)
+ {
+ vacopy_node = cgraph_node::get_create (bvacopy);
+ set_strub_mode (vacopy_node);
+ }
+ e->redirect_callee (vacopy_node);
}
else if (fndecl && apply_args
&& fndecl_built_in_p (fndecl, BUILT_IN_APPLY_ARGS))
@@ -2418,7 +2353,11 @@ pass_ipa_strub::execute (function *)
#endif
}
- verify_strub ();
+ if (flag_checking)
+ /* We've already verified before any inlining or other transformations.
+ Recheck after strub transformations only if checking is enabled, since
+ they should not introduce any incompatibilities. */
+ verify_strub ();
return 0;
}
^ permalink raw reply [flat|nested] 7+ messages in thread
* [gcc(refs/users/aoliva/heads/strub)] make builtins callable
@ 2021-07-28 4:30 Alexandre Oliva
0 siblings, 0 replies; 7+ messages in thread
From: Alexandre Oliva @ 2021-07-28 4:30 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:8efece23e8d3c6c98983bf6a75d750947183d5fe
commit 8efece23e8d3c6c98983bf6a75d750947183d5fe
Author: Alexandre Oliva <oliva@adacore.com>
Date: Mon Jul 26 12:15:36 2021 -0300
make builtins callable
Diff:
---
gcc/builtins.c | 8 -
gcc/ipa-strub.c | 588 ++++++++++++++++++++++++++++++++++++++------------------
2 files changed, 399 insertions(+), 197 deletions(-)
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 373b4e90f70..23fe484dc7e 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -7987,14 +7987,6 @@ expand_builtin_strub_leave (tree exp)
tree wmtree = fold_build2 (MEM_REF, wmtype, wmptr,
build_int_cst (TREE_TYPE (wmptr), 0));
rtx wmark = expand_expr (wmtree, NULL_RTX, ptr_mode, EXPAND_MEMORY);
-
- /* If the function called between enter and leave is const or pure,
- we may assume it won't change the watermark passed indirectly to
- it. These ensure the value is neither dropped nor assumed
- unchanged. */
- emit_insn (gen_rtx_USE (VOIDmode, wmark));
- emit_insn (gen_rtx_CLOBBER (VOIDmode, wmark));
-
rtx wmarkr = force_reg (ptr_mode, wmark);
#ifndef STACK_GROWS_DOWNWARD
diff --git a/gcc/ipa-strub.c b/gcc/ipa-strub.c
index 7b05321e980..a32b9b9ead1 100644
--- a/gcc/ipa-strub.c
+++ b/gcc/ipa-strub.c
@@ -45,7 +45,6 @@ along with GCC; see the file COPYING3. If not see
#include "symbol-summary.h"
#include "ipa-prop.h"
#include "ipa-fnsummary.h"
-#include "symtab-thunks.h"
#include "gimple-fold.h"
#include "fold-const.h"
#include "gimple-walk.h"
@@ -59,7 +58,26 @@ along with GCC; see the file COPYING3. If not see
#include "diagnostic.h"
#include "intl.h"
#include "ipa-strub.h"
-#include "attr-fnspec.h"
+
+#if BUILDING_GCC_MAJOR >= 11
+# include "symtab-thunks.h"
+# include "attr-fnspec.h"
+# define HAVE_ATTR_FNSPEC 1
+# define FOR_GCC_11P 1
+#else
+# define HAVE_ATTR_FNSPEC 0
+# define FOR_GCC_11P 0
+#endif
+
+/* Const and pure functions that gain a watermark parameter for strub purposes
+ are still regarded as such, which may cause the inline expansions of the
+ __strub builtins to malfunction. Ideally, attribute "fn spec" would enable
+ us to inform the backend about requirements and side effects of the call, but
+ call_fusage building in calls.c:expand_call does not even look at
+ attr_fnspec, so we resort to asm loads and updates to attain an equivalent
+ effect. Once expand_call gains the ability to issue extra memory uses and
+ clobbers based on pure/const function's fnspec, we can define this to 1. */
+#define ATTR_FNSPEC_DECONST_WATERMARK 0
enum strub_mode {
/* This mode denotes a regular function, that does not require stack
@@ -438,6 +456,34 @@ strub_from_body_p (cgraph_node *node)
return false;
}
+/* Return true iff node is associated with a builtin that should be callable
+ from strub contexts. */
+static inline bool
+strub_callable_builtin_p (cgraph_node *node)
+{
+ if (DECL_BUILT_IN_CLASS (node->decl) != BUILT_IN_NORMAL)
+ return false;
+
+ enum built_in_function fcode = DECL_FUNCTION_CODE (node->decl);
+
+ switch (fcode)
+ {
+ case BUILT_IN_NONE:
+ gcc_unreachable ();
+
+ /* ??? Make all builtins callable. We wish to make any builtin call the
+ compiler might introduce on its own callable. Anything that is
+ predictable enough as to be known not to allow stack data that should
+ be strubbed to unintentionally escape to non-strub contexts can be
+ allowed, and pretty much every builtin appears to fit this description.
+ The exceptions to this rule seem to be rare, and only available as
+ explicit __builtin calls, so let's keep it simple and allow all of
+ them... */
+ default:
+ return true;
+ }
+}
+
static enum strub_mode
compute_strub_mode (cgraph_node *node, tree strub_attr)
{
@@ -495,7 +541,8 @@ compute_strub_mode (cgraph_node *node, tree strub_attr)
= (!strub_flag_disabled
&& (strub_attr
? req_mode == STRUB_CALLABLE
- : strub_flag_viable));
+ : (strub_flag_viable
+ || strub_callable_builtin_p (node))));
/* This is a shorthand for either strub-enabled mode. */
const bool consider_strub
@@ -730,6 +777,26 @@ set_strub_mode (cgraph_node *node)
{
tree attr = get_strub_attr_from_decl (node->decl);
+ if (attr)
+ switch (enum strub_mode mode = get_strub_mode_from_attr (attr))
+ {
+ /* These can't have been requested through user attributes, so we must
+ have already gone through them. */
+ case STRUB_WRAPPER:
+ case STRUB_WRAPPED:
+ case STRUB_INLINABLE:
+ return mode;
+
+ case STRUB_DISABLED:
+ case STRUB_AT_CALLS:
+ case STRUB_INTERNAL:
+ case STRUB_CALLABLE:
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
cgraph_node *xnode = node;
if (node->alias)
xnode = node->ultimate_alias_target ();
@@ -845,6 +912,49 @@ strub_inlinable_p (cgraph_node *callee, cgraph_node *caller)
return false;
}
+/* Check that strub functions don't call non-strub functions, and that
+ always_inline strub functions are only called by strub
+ functions. */
+static void
+verify_strub ()
+{
+ cgraph_node *node;
+
+ FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
+ {
+ enum strub_mode caller_mode = get_strub_mode (node);
+ bool strub_context
+ = (caller_mode == STRUB_AT_CALLS
+ || caller_mode == STRUB_WRAPPED
+ || caller_mode == STRUB_INLINABLE);
+
+ for (cgraph_edge *e = node->callees; e; e = e->next_callee)
+ if (e->indirect_unknown_callee)
+ {
+ if (!strub_context)
+ continue;
+
+ tree callee_fntype = gimple_call_fntype (e->call_stmt);
+ enum strub_mode callee_mode
+ = get_strub_mode_from_type (callee_fntype);
+
+ if (callee_mode == STRUB_DISABLED
+ || callee_mode == STRUB_INTERNAL)
+ error_at (gimple_location (e->call_stmt),
+ "indirect non-strub call in strub context %qD",
+ node->decl);
+ }
+ else if (!strub_callable_from_p (e->callee, node))
+ error_at (gimple_location (e->call_stmt),
+ "calling non-strub %qD in strub context %qD",
+ e->callee->decl, node->decl);
+ }
+
+ /* ??? Check strub-wise pointer type compatibility of variables and
+ functions, or is this already taken care of on account of the
+ attribute's being marked as affecting type identity? */
+}
+
namespace {
const pass_data pass_data_ipa_strub_mode = {
@@ -907,8 +1017,6 @@ public:
NULL, NULL); \
TREE_NOTHROW (decl) = true; \
set_builtin_decl ((CODE), decl, true); \
- set_strub_mode_to (cgraph_node::get_create (decl), \
- STRUB_CALLABLE); \
} \
return decl; \
}
@@ -926,7 +1034,7 @@ public:
{ \
tree type = build_function_type_list FNTYPELIST; \
tree attrs = NULL; \
- if (FNSPEC) \
+ if (FNSPEC && HAVE_ATTR_FNSPEC) \
attrs = tree_cons (get_identifier ("fn spec"), \
build_tree_list \
(NULL_TREE, \
@@ -939,8 +1047,6 @@ public:
"__strub_" #NAME, attrs); \
TREE_NOTHROW (decl) = true; \
set_builtin_decl ((CODE), decl, true); \
- set_strub_mode_to (cgraph_node::get_create (decl), \
- STRUB_CALLABLE); \
} \
return decl; \
}
@@ -1014,116 +1120,6 @@ public:
} // anon namespace
-#if 0
-static bool
-may_throw_p (gcall *stmt)
-{
- return flag_exceptions && !gimple_call_nothrow_p (stmt);
-}
-
-static bool
-strub_this_call_p (gcall *stmt)
-{
- if (gimple_call_internal_p (stmt))
- return false;
-
- /* If there's no outgoing path in which to do the scrubbing, don't
- bother. */
- if (gimple_call_noreturn_p (stmt) && !may_throw_p (stmt))
- return false;
-
- /* ??? Maybe non-mandatory tail calls should be disabled for
- scrubbing. Or maybe it won't matter, as long as both tail-caller
- and callee are scrubbing-capable. */
- if (gimple_call_must_tail_p (stmt) || gimple_call_tail_p (stmt))
- return false;
-
- if (gimple_alloca_call_p (stmt))
- return true;
-
- tree fndecl = gimple_call_fndecl (stmt);
- if (!fndecl)
- return true;
-
- if (DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL)
- return true;
-
- enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
-
- switch (fcode)
- {
- CASE_BUILT_IN_ALLOCA:
- return true;
-
- case BUILT_IN_NONE:
- return true;
-
- case BUILT_IN___STRUB_ENTER:
- case BUILT_IN___STRUB_UPDATE:
- case BUILT_IN___STRUB_LEAVE:
- return false;
-
- case BUILT_IN_CLASSIFY_TYPE:
- case BUILT_IN_CONSTANT_P:
- return false;
-
- case BUILT_IN_RETURN_ADDRESS:
- case BUILT_IN_FRAME_ADDRESS:
- case BUILT_IN_STACK_ADDRESS:
- case BUILT_IN_AGGREGATE_INCOMING_ADDRESS:
- return false;
-
- case BUILT_IN_STACK_SAVE:
- case BUILT_IN_STACK_RESTORE:
- case BUILT_IN_ASAN_ALLOCAS_UNPOISON:
- return false;
-
- case BUILT_IN_SETJMP_SETUP:
- case BUILT_IN_SETJMP_RECEIVER:
- case BUILT_IN_LONGJMP:
- case BUILT_IN_NONLOCAL_GOTO:
- case BUILT_IN_UPDATE_SETJMP_BUF:
- case BUILT_IN_TRAP:
- case BUILT_IN_UNREACHABLE:
- return false;
-
- case BUILT_IN_UNWIND_INIT:
- case BUILT_IN_DWARF_CFA:
-#ifdef DWARF2_UNWIND_INFO
- case BUILT_IN_DWARF_SP_COLUMN:
- case BUILT_IN_INIT_DWARF_REG_SIZES:
-#endif
- case BUILT_IN_FROB_RETURN_ADDR:
- case BUILT_IN_EXTRACT_RETURN_ADDR:
- case BUILT_IN_EH_RETURN:
- case BUILT_IN_EH_RETURN_DATA_REGNO:
- case BUILT_IN_EXTEND_POINTER:
- case BUILT_IN_EH_POINTER:
- case BUILT_IN_EH_FILTER:
- case BUILT_IN_EH_COPY_VALUES:
- return false;
-
- case BUILT_IN_VA_START:
- case BUILT_IN_VA_END:
- case BUILT_IN_VA_COPY:
- case BUILT_IN_EXPECT:
- case BUILT_IN_EXPECT_WITH_PROBABILITY:
- case BUILT_IN_ASSUME_ALIGNED:
- case BUILT_IN_PREFETCH:
- return false;
-
- case BUILT_IN_ATOMIC_ALWAYS_LOCK_FREE:
- case BUILT_IN_OBJECT_SIZE:
- case BUILT_IN_THREAD_POINTER:
- case BUILT_IN_SET_THREAD_POINTER:
- return false;
-
- default:
- return true;
- }
-}
-#endif
-
typedef hash_set<tree> indirect_parms_t;
static tree
@@ -1402,32 +1398,61 @@ remove_named_attribute_unsharing (const char *name, tree *attrs)
}
}
-unsigned int
-pass_ipa_strub_mode::execute (function *)
+static int last_cgraph_order;
+
+static bool
+ipa_strub_set_mode_for_new_functions ()
{
- cgraph_node *onode;
+ if (last_cgraph_order && symtab->order == last_cgraph_order)
+ /* If we're called again after the first call,
+ then the first call must have returned true. */
+ return true;
- /* If no strub flag was given in the command line,
- set the actual default. */
- if (flag_strub == -2)
- flag_strub = 3; // for testing only; was: -1;
+ cgraph_node *node;
bool any_strub = false;
+ /* Go through the functions twice, once over non-aliases, and then over
+ aliases, so that aliases can reuse the mode computation of their ultimate
+ targets. */
for (int aliases = 0; aliases <= 1; aliases++)
- FOR_EACH_FUNCTION (onode)
+ FOR_EACH_FUNCTION (node)
{
- if (!onode->alias != !aliases)
+ if (!node->alias != !aliases)
+ continue;
+
+ /* Already done. */
+ if (node->order < last_cgraph_order)
continue;
- enum strub_mode mode = set_strub_mode (onode);
+ enum strub_mode mode = set_strub_mode (node);
if (mode == STRUB_AT_CALLS || mode == STRUB_INTERNAL)
any_strub = true;
}
+ if (any_strub)
+ last_cgraph_order = symtab->order;
+
+ return any_strub;
+}
+
+unsigned int
+pass_ipa_strub_mode::execute (function *)
+{
+ /* If no strub flag was given in the command line,
+ set the actual default. */
+ if (flag_strub == -2)
+ flag_strub = 3; // for testing only; was: -1;
+
+ last_cgraph_order = 0;
+ bool any_strub = ipa_strub_set_mode_for_new_functions ();
+
if (!any_strub)
flag_strub = 0;
+ else
+ /* Verify before any inlining or other transformations. */
+ verify_strub ();
return 0;
}
@@ -1438,54 +1463,13 @@ make_pass_ipa_strub_mode (gcc::context *ctxt)
return new pass_ipa_strub_mode (ctxt);
}
-/* Check that strub functions don't call non-strub functions, and that
- always_inline strub functions are only called by strub
- functions. */
-static void
-verify_strub ()
-{
- cgraph_node *node;
-
- FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
- {
- enum strub_mode caller_mode = get_strub_mode (node);
- bool strub_context
- = (caller_mode == STRUB_AT_CALLS
- || caller_mode == STRUB_WRAPPED
- || caller_mode == STRUB_INLINABLE);
-
- for (cgraph_edge *e = node->callees; e; e = e->next_callee)
- if (e->indirect_unknown_callee)
- {
- if (!strub_context)
- continue;
-
- tree callee_fntype = gimple_call_fntype (e->call_stmt);
- enum strub_mode callee_mode
- = get_strub_mode_from_type (callee_fntype);
-
- if (callee_mode == STRUB_DISABLED
- || callee_mode == STRUB_INTERNAL)
- error_at (gimple_location (e->call_stmt),
- "indirect non-strub call in strub context %qD",
- node->decl);
- }
- else if (!strub_callable_from_p (e->callee, node))
- error_at (gimple_location (e->call_stmt),
- "calling non-strub %qD in strub context %qD",
- e->callee->decl, node->decl);
- }
-
- /* ??? Check strub-wise pointer type compatibility of variables and
- functions, or is this already taken care of on account of the
- attribute's being marked as affecting type identity? */
-}
-
unsigned int
pass_ipa_strub::execute (function *)
{
cgraph_node *onode;
+ ipa_strub_set_mode_for_new_functions ();
+
FOR_EACH_FUNCTION (onode)
{
enum strub_mode mode = get_strub_mode (onode);
@@ -1572,7 +1556,7 @@ pass_ipa_strub::execute (function *)
// Mostly copied from gimple_call_copy_skip_args.
int i = 0;
int nargs = gimple_call_num_args (stmt);
- auto_vec<tree> vargs (nargs + 1);
+ auto_vec<tree> vargs (MAX (nargs, named_args) + 1);
gcall *new_stmt;
/* pr71109.c calls a prototypeless function, then defines it with
@@ -1630,15 +1614,47 @@ pass_ipa_strub::execute (function *)
gimple_seq seq = NULL;
{
-#if 0
- tree lswm = create_tmp_var (ptr_type_node, ".L.strub.watermark");
- gassign *load = gimple_build_assign (lswm, swm);
- gimple_seq_add_stmt (&seq, load);
-#else
- tree lswm = unshare_expr (swmp);
+#if !ATTR_FNSPEC_DECONST_WATERMARK
+ /* If the call will be assumed to not modify or even read the
+ watermark, make it read and modified ourselves. */
+ if ((gimple_call_flags (wrcall)
+ & (ECF_CONST | ECF_PURE | ECF_NOVOPS)))
+ {
+ vec<tree, va_gc> *inputs = NULL;
+ vec<tree, va_gc> *outputs = NULL;
+ vec_safe_push (outputs,
+ build_tree_list
+ (build_tree_list
+ (NULL_TREE, build_string (2, "=m")),
+ swm));
+ vec_safe_push (inputs,
+ build_tree_list
+ (build_tree_list
+ (NULL_TREE, build_string (1, "m")),
+ swm));
+ gasm *forcemod = gimple_build_asm_vec ("", inputs, outputs,
+ NULL, NULL);
+ gimple_seq_add_stmt (&seq, forcemod);
+
+ /* If the call will be assumed to not even read the watermark,
+ make sure it is already in memory before the call. */
+ if ((gimple_call_flags (wrcall) & ECF_CONST))
+ {
+ vec<tree, va_gc> *inputs = NULL;
+ vec_safe_push (inputs,
+ build_tree_list
+ (build_tree_list
+ (NULL_TREE, build_string (1, "m")),
+ swm));
+ gasm *force_store = gimple_build_asm_vec ("", inputs, NULL,
+ NULL, NULL);
+ gsi_insert_before (&gsi, force_store, GSI_SAME_STMT);
+ }
+ }
#endif
- gcall *sleave = gimple_build_call (get_leave (), 1, lswm);
+ gcall *sleave = gimple_build_call (get_leave (), 1,
+ unshare_expr (swmp));
gimple_seq_add_stmt (&seq, sleave);
gassign *clobber = gimple_build_assign (swm,
@@ -1652,6 +1668,50 @@ pass_ipa_strub::execute (function *)
pop_cfun ();
}
+#if ATTR_FNSPEC_DECONST_WATERMARK
+ {
+ int flags = flags_from_decl_or_type (onode->decl);
+ tree fnspec = lookup_attribute ("fn spec", TREE_TYPE (onode->decl));
+
+ if ((flags & (ECF_CONST | ECF_PURE | ECF_NOVOPS)) || fnspec)
+ {
+ size_t xargs = 1;
+ size_t curlen = 0, tgtlen = 2 + 2 * (named_args + xargs);
+ auto_vec<char> nspecv (tgtlen);
+ char *nspec = &nspecv[0]; /* It will *not* be NUL-terminated! */
+ if (fnspec)
+ {
+ tree fnspecstr = TREE_VALUE (TREE_VALUE (fnspec));
+ curlen = TREE_STRING_LENGTH (fnspecstr);
+ memcpy (nspec, TREE_STRING_POINTER (fnspecstr), curlen);
+ }
+ if (!curlen)
+ {
+ nspec[curlen++] = '.';
+ nspec[curlen++] = ((flags & ECF_CONST)
+ ? 'c'
+ : (flags & ECF_PURE)
+ ? 'p'
+ : ' ');
+ }
+ while (curlen < tgtlen - 2 * xargs)
+ {
+ nspec[curlen++] = '.';
+ nspec[curlen++] = ' ';
+ }
+ nspec[curlen++] = 'W';
+ nspec[curlen++] = 't';
+
+ /* The type has already been copied before adding parameters. */
+ TYPE_ATTRIBUTES (TREE_TYPE (onode->decl))
+ = tree_cons (get_identifier ("fn spec"),
+ build_tree_list (NULL_TREE,
+ build_string (tgtlen, nspec)),
+ TYPE_ATTRIBUTES (TREE_TYPE (onode->decl)));
+ }
+ }
+#endif
+
if (!onode->has_gimple_body_p ())
continue;
@@ -1807,11 +1867,13 @@ pass_ipa_strub::execute (function *)
anyway, but performed at the caller. */
indirect_parms_t indirect_nparms (3, false);
unsigned adjust_ftype = 0;
+ unsigned named_args = 0;
for (tree parm = DECL_ARGUMENTS (onode->decl),
nparm = DECL_ARGUMENTS (nnode->decl),
nparmt = TYPE_ARG_TYPES (TREE_TYPE (nnode->decl));
parm;
- parm = DECL_CHAIN (parm),
+ named_args++,
+ parm = DECL_CHAIN (parm),
nparm = DECL_CHAIN (nparm),
nparmt = nparmt ? TREE_CHAIN (nparmt) : NULL_TREE)
if (!(0 /* DECL_BY_REFERENCE (narg) */
@@ -1840,7 +1902,11 @@ pass_ipa_strub::execute (function *)
relayout_decl (nparm);
TREE_ADDRESSABLE (nparm) = 0;
DECL_BY_REFERENCE (nparm) = 0;
+#if FOR_GCC_11P
DECL_NOT_GIMPLE_REG_P (nparm) = 0;
+#else
+ DECL_GIMPLE_REG_P (nparm) = 1;
+#endif
/* ??? This avoids mismatches in debug info bind stmts in
e.g. a-chahan . */
DECL_ABSTRACT_ORIGIN (nparm) = NULL;
@@ -1860,6 +1926,7 @@ pass_ipa_strub::execute (function *)
gcc_checking_assert (TYPE_ARG_TYPES (nftype)
!= TYPE_ARG_TYPES (TREE_TYPE (onode->decl)));
+#if HAVE_ATTR_FNSPEC
/* Check that fnspec still works for the modified function signature,
and drop it otherwise. */
bool drop_fnspec = false;
@@ -1871,15 +1938,20 @@ pass_ipa_strub::execute (function *)
retcopy = (unsigned) -1;
unsigned i = 0;
+#endif
for (tree nparm = DECL_ARGUMENTS (nnode->decl),
nparmt = TYPE_ARG_TYPES (nftype);
adjust_ftype > 0;
- nparm = DECL_CHAIN (nparm), nparmt = TREE_CHAIN (nparmt), i++)
+#if HAVE_ATTR_FNSPEC
+ i++,
+#endif
+ nparm = DECL_CHAIN (nparm), nparmt = TREE_CHAIN (nparmt))
if (indirect_nparms.contains (nparm))
{
TREE_VALUE (nparmt) = TREE_TYPE (nparm);
adjust_ftype--;
+#if HAVE_ATTR_FNSPEC
if (fnspec && !drop_fnspec)
{
if (i == retcopy)
@@ -1907,16 +1979,93 @@ pass_ipa_strub::execute (function *)
drop_fnspec = true;
}
}
+#endif
}
+#if HAVE_ATTR_FNSPEC
/* ??? Maybe we could adjust it instead. */
if (drop_fnspec)
remove_named_attribute_unsharing ("fn spec",
&TYPE_ATTRIBUTES (nftype));
+#endif
TREE_TYPE (nnode->decl) = nftype;
}
+#if ATTR_FNSPEC_DECONST_WATERMARK
+ {
+ int flags = flags_from_decl_or_type (nnode->decl);
+ tree fnspec = lookup_attribute ("fn spec", TREE_TYPE (nnode->decl));
+
+ if ((flags & (ECF_CONST | ECF_PURE | ECF_NOVOPS)) || fnspec)
+ {
+ size_t xargs = 1 + int (is_stdarg) + int (apply_args);
+ size_t curlen = 0, tgtlen = 2 + 2 * (named_args + xargs);
+ auto_vec<char> nspecv (tgtlen);
+ char *nspec = &nspecv[0]; /* It will *not* be NUL-terminated! */
+ bool no_writes_p = true;
+ if (fnspec)
+ {
+ tree fnspecstr = TREE_VALUE (TREE_VALUE (fnspec));
+ curlen = TREE_STRING_LENGTH (fnspecstr);
+ memcpy (nspec, TREE_STRING_POINTER (fnspecstr), curlen);
+ if (!(flags & (ECF_CONST | ECF_PURE | ECF_NOVOPS))
+ && curlen >= 2
+ && nspec[1] != 'c' && nspec[1] != 'C'
+ && nspec[1] != 'p' && nspec[1] != 'P')
+ no_writes_p = false;
+ }
+ if (!curlen)
+ {
+ nspec[curlen++] = '.';
+ nspec[curlen++] = ((flags & ECF_CONST)
+ ? 'c'
+ : (flags & ECF_PURE)
+ ? 'p'
+ : ' ');
+ }
+ while (curlen < tgtlen - 2 * xargs)
+ {
+ nspec[curlen++] = '.';
+ nspec[curlen++] = ' ';
+ }
+
+ /* These extra args are unlikely to be present in const or pure
+ functions. It's conceivable that a function that takes variable
+ arguments, or that passes its arguments on to another function,
+ could be const or pure, but it would not modify the arguments, and,
+ being pure or const, it couldn't possibly modify or even access
+ memory referenced by them. But it can read from these internal
+ data structures created by the wrapper, and from any
+ argument-passing memory referenced by them, so we denote the
+ possibility of reading from multiple levels of indirection, but
+ only of reading because const/pure. */
+ if (apply_args)
+ {
+ nspec[curlen++] = (no_writes_p ? 'r' : '.');
+ nspec[curlen++] = (no_writes_p ? 't' : ' ');
+ }
+ if (is_stdarg)
+ {
+ nspec[curlen++] = (no_writes_p ? 'r' : '.');
+ nspec[curlen++] = (no_writes_p ? 't' : ' ');
+ }
+
+ nspec[curlen++] = 'W';
+ nspec[curlen++] = 't';
+
+ /* The type has already been copied before adding parameters. */
+ gcc_checking_assert (TYPE_ARG_TYPES (TREE_TYPE (nnode->decl))
+ != TYPE_ARG_TYPES (TREE_TYPE (onode->decl)));
+ TYPE_ATTRIBUTES (TREE_TYPE (nnode->decl))
+ = tree_cons (get_identifier ("fn spec"),
+ build_tree_list (NULL_TREE,
+ build_string (tgtlen, nspec)),
+ TYPE_ATTRIBUTES (TREE_TYPE (nnode->decl)));
+ }
+ }
+#endif
+
{
tree decl = onode->decl;
cgraph_node *target = nnode;
@@ -1940,8 +2089,14 @@ pass_ipa_strub::execute (function *)
/* Turn alias into thunk and expand it into GIMPLE representation. */
onode->definition = true;
+#if FOR_GCC_11P
thunk_info::get_create (onode);
onode->thunk = true;
+#else
+ memset (&onode->thunk, 0, sizeof (cgraph_thunk_info));
+ onode->thunk.thunk_p = true;
+ onode->thunk.alias = target->decl;
+#endif
#if !IMPLICIT_CGRAPH_EDGES
onode->create_edge (target, NULL, onode->count);
#endif
@@ -1980,9 +2135,11 @@ pass_ipa_strub::execute (function *)
current_function_decl = thunk_fndecl;
+#if FOR_GCC_11P
/* Ensure thunks are emitted in their correct sections. */
resolve_unique_section (thunk_fndecl, 0,
flag_function_sections);
+#endif
bitmap_obstack_initialize (NULL);
@@ -2066,8 +2223,14 @@ pass_ipa_strub::execute (function *)
tree addr = build1 (ADDR_EXPR, ref_type, arg);
tmp = arg = addr;
}
+#if ! FOR_GCC_11P
+ else if (VECTOR_TYPE_P (TREE_TYPE (arg))
+ || TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
+ DECL_GIMPLE_REG_P (arg) = 1;
+#else
else
DECL_NOT_GIMPLE_REG_P (arg) = 0;
+#endif
/* Convert the argument back to the type used by the calling
conventions, e.g. a non-prototyped float type is passed as
@@ -2151,8 +2314,10 @@ pass_ipa_strub::execute (function *)
profile_status_for_fn (cfun)
= cfg_count.initialized_p () && cfg_count.ipa_p ()
? PROFILE_READ : PROFILE_GUESSED;
+#if FOR_GCC_11P
/* FIXME: C++ FE should stop setting TREE_ASM_WRITTEN on thunks. */
// TREE_ASM_WRITTEN (thunk_fndecl) = false;
+#endif
delete_unreachable_blocks ();
update_ssa (TODO_update_ssa);
checking_verify_flow_info ();
@@ -2160,7 +2325,11 @@ pass_ipa_strub::execute (function *)
/* Since we want to emit the thunk, we explicitly mark its name as
referenced. */
+#if FOR_GCC_11P
onode->thunk = false;
+#else
+ onode->thunk.thunk_p = false;
+#endif
onode->lowered = true;
bitmap_obstack_release (NULL);
}
@@ -2168,7 +2337,9 @@ pass_ipa_strub::execute (function *)
set_cfun (NULL);
}
+#if FOR_GCC_11P
thunk_info::remove (onode);
+#endif
// some more of create_wrapper at the end of the next block.
}
@@ -2381,15 +2552,47 @@ pass_ipa_strub::execute (function *)
update_stmt (wrcall);
{
-#if 0
- tree lswm = create_tmp_var (ptr_type_node, ".L.strub.watermark");
- gassign *load = gimple_build_assign (lswm, swm);
- gimple_seq_add_stmt (&seq, load);
-#else
- tree lswm = unshare_expr (swmp);
+#if !ATTR_FNSPEC_DECONST_WATERMARK
+ /* If the call will be assumed to not modify or even read the
+ watermark, make it read and modified ourselves. */
+ if ((gimple_call_flags (wrcall)
+ & (ECF_CONST | ECF_PURE | ECF_NOVOPS)))
+ {
+ vec<tree, va_gc> *inputs = NULL;
+ vec<tree, va_gc> *outputs = NULL;
+ vec_safe_push (outputs,
+ build_tree_list
+ (build_tree_list
+ (NULL_TREE, build_string (2, "=m")),
+ swm));
+ vec_safe_push (inputs,
+ build_tree_list
+ (build_tree_list
+ (NULL_TREE, build_string (1, "m")),
+ swm));
+ gasm *forcemod = gimple_build_asm_vec ("", inputs, outputs,
+ NULL, NULL);
+ gimple_seq_add_stmt (&seq, forcemod);
+
+ /* If the call will be assumed to not even read the watermark,
+ make sure it is already in memory before the call. */
+ if ((gimple_call_flags (wrcall) & ECF_CONST))
+ {
+ vec<tree, va_gc> *inputs = NULL;
+ vec_safe_push (inputs,
+ build_tree_list
+ (build_tree_list
+ (NULL_TREE, build_string (1, "m")),
+ swm));
+ gasm *force_store = gimple_build_asm_vec ("", inputs, NULL,
+ NULL, NULL);
+ gsi_insert_before (&gsi, force_store, GSI_SAME_STMT);
+ }
+ }
#endif
- gcall *sleave = gimple_build_call (get_leave (), 1, lswm);
+ gcall *sleave = gimple_build_call (get_leave (), 1,
+ unshare_expr (swmp));
gimple_seq_add_stmt (&seq, sleave);
gassign *clobber = gimple_build_assign (swm,
@@ -2418,7 +2621,14 @@ pass_ipa_strub::execute (function *)
#endif
}
- verify_strub ();
+ if (flag_checking)
+ {
+ /* We've already verified before any inlining or other transformations.
+ Recheck after strub transformations only if checking is enabled, since
+ they should not introduce any incompatibilities. */
+ ipa_strub_set_mode_for_new_functions ();
+ verify_strub ();
+ }
return 0;
}
^ permalink raw reply [flat|nested] 7+ messages in thread
* [gcc(refs/users/aoliva/heads/strub)] make builtins callable
@ 2021-07-26 21:05 Alexandre Oliva
0 siblings, 0 replies; 7+ messages in thread
From: Alexandre Oliva @ 2021-07-26 21:05 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:9d2df29d248f215b9ca0ec7b493273ae20d75d2b
commit 9d2df29d248f215b9ca0ec7b493273ae20d75d2b
Author: Alexandre Oliva <oliva@adacore.com>
Date: Mon Jul 26 12:15:36 2021 -0300
make builtins callable
Diff:
---
gcc/ipa-strub.c | 311 ++++++++++++++++++++++++++------------------------------
1 file changed, 142 insertions(+), 169 deletions(-)
diff --git a/gcc/ipa-strub.c b/gcc/ipa-strub.c
index 7b05321e980..7753f0207d7 100644
--- a/gcc/ipa-strub.c
+++ b/gcc/ipa-strub.c
@@ -438,6 +438,34 @@ strub_from_body_p (cgraph_node *node)
return false;
}
+/* Return true iff node is associated with a builtin that should be callable
+ from strub contexts. */
+static inline bool
+strub_callable_builtin_p (cgraph_node *node)
+{
+ if (DECL_BUILT_IN_CLASS (node->decl) != BUILT_IN_NORMAL)
+ return false;
+
+ enum built_in_function fcode = DECL_FUNCTION_CODE (node->decl);
+
+ switch (fcode)
+ {
+ case BUILT_IN_NONE:
+ gcc_unreachable ();
+
+ /* ??? Make all builtins callable. We wish to make any builtin call the
+ compiler might introduce on its own callable. Anything that is
+ predictable enough as to be known not to allow stack data that should
+ be strubbed to unintentionally escape to non-strub contexts can be
+ allowed, and pretty much every builtin appears to fit this description.
+ The exceptions to this rule seem to be rare, and only available as
+ explicit __builtin calls, so let's keep it simple and allow all of
+ them... */
+ default:
+ return true;
+ }
+}
+
static enum strub_mode
compute_strub_mode (cgraph_node *node, tree strub_attr)
{
@@ -495,7 +523,8 @@ compute_strub_mode (cgraph_node *node, tree strub_attr)
= (!strub_flag_disabled
&& (strub_attr
? req_mode == STRUB_CALLABLE
- : strub_flag_viable));
+ : (strub_flag_viable
+ || strub_callable_builtin_p (node))));
/* This is a shorthand for either strub-enabled mode. */
const bool consider_strub
@@ -730,6 +759,26 @@ set_strub_mode (cgraph_node *node)
{
tree attr = get_strub_attr_from_decl (node->decl);
+ if (attr)
+ switch (enum strub_mode mode = get_strub_mode_from_attr (attr))
+ {
+ /* These can't have been requested through user attributes, so we must
+ have already gone through them. */
+ case STRUB_WRAPPER:
+ case STRUB_WRAPPED:
+ case STRUB_INLINABLE:
+ return mode;
+
+ case STRUB_DISABLED:
+ case STRUB_AT_CALLS:
+ case STRUB_INTERNAL:
+ case STRUB_CALLABLE:
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
cgraph_node *xnode = node;
if (node->alias)
xnode = node->ultimate_alias_target ();
@@ -845,6 +894,49 @@ strub_inlinable_p (cgraph_node *callee, cgraph_node *caller)
return false;
}
+/* Check that strub functions don't call non-strub functions, and that
+ always_inline strub functions are only called by strub
+ functions. */
+static void
+verify_strub ()
+{
+ cgraph_node *node;
+
+ FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
+ {
+ enum strub_mode caller_mode = get_strub_mode (node);
+ bool strub_context
+ = (caller_mode == STRUB_AT_CALLS
+ || caller_mode == STRUB_WRAPPED
+ || caller_mode == STRUB_INLINABLE);
+
+ for (cgraph_edge *e = node->callees; e; e = e->next_callee)
+ if (e->indirect_unknown_callee)
+ {
+ if (!strub_context)
+ continue;
+
+ tree callee_fntype = gimple_call_fntype (e->call_stmt);
+ enum strub_mode callee_mode
+ = get_strub_mode_from_type (callee_fntype);
+
+ if (callee_mode == STRUB_DISABLED
+ || callee_mode == STRUB_INTERNAL)
+ error_at (gimple_location (e->call_stmt),
+ "indirect non-strub call in strub context %qD",
+ node->decl);
+ }
+ else if (!strub_callable_from_p (e->callee, node))
+ error_at (gimple_location (e->call_stmt),
+ "calling non-strub %qD in strub context %qD",
+ e->callee->decl, node->decl);
+ }
+
+ /* ??? Check strub-wise pointer type compatibility of variables and
+ functions, or is this already taken care of on account of the
+ attribute's being marked as affecting type identity? */
+}
+
namespace {
const pass_data pass_data_ipa_strub_mode = {
@@ -907,8 +999,6 @@ public:
NULL, NULL); \
TREE_NOTHROW (decl) = true; \
set_builtin_decl ((CODE), decl, true); \
- set_strub_mode_to (cgraph_node::get_create (decl), \
- STRUB_CALLABLE); \
} \
return decl; \
}
@@ -939,8 +1029,6 @@ public:
"__strub_" #NAME, attrs); \
TREE_NOTHROW (decl) = true; \
set_builtin_decl ((CODE), decl, true); \
- set_strub_mode_to (cgraph_node::get_create (decl), \
- STRUB_CALLABLE); \
} \
return decl; \
}
@@ -1014,116 +1102,6 @@ public:
} // anon namespace
-#if 0
-static bool
-may_throw_p (gcall *stmt)
-{
- return flag_exceptions && !gimple_call_nothrow_p (stmt);
-}
-
-static bool
-strub_this_call_p (gcall *stmt)
-{
- if (gimple_call_internal_p (stmt))
- return false;
-
- /* If there's no outgoing path in which to do the scrubbing, don't
- bother. */
- if (gimple_call_noreturn_p (stmt) && !may_throw_p (stmt))
- return false;
-
- /* ??? Maybe non-mandatory tail calls should be disabled for
- scrubbing. Or maybe it won't matter, as long as both tail-caller
- and callee are scrubbing-capable. */
- if (gimple_call_must_tail_p (stmt) || gimple_call_tail_p (stmt))
- return false;
-
- if (gimple_alloca_call_p (stmt))
- return true;
-
- tree fndecl = gimple_call_fndecl (stmt);
- if (!fndecl)
- return true;
-
- if (DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL)
- return true;
-
- enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
-
- switch (fcode)
- {
- CASE_BUILT_IN_ALLOCA:
- return true;
-
- case BUILT_IN_NONE:
- return true;
-
- case BUILT_IN___STRUB_ENTER:
- case BUILT_IN___STRUB_UPDATE:
- case BUILT_IN___STRUB_LEAVE:
- return false;
-
- case BUILT_IN_CLASSIFY_TYPE:
- case BUILT_IN_CONSTANT_P:
- return false;
-
- case BUILT_IN_RETURN_ADDRESS:
- case BUILT_IN_FRAME_ADDRESS:
- case BUILT_IN_STACK_ADDRESS:
- case BUILT_IN_AGGREGATE_INCOMING_ADDRESS:
- return false;
-
- case BUILT_IN_STACK_SAVE:
- case BUILT_IN_STACK_RESTORE:
- case BUILT_IN_ASAN_ALLOCAS_UNPOISON:
- return false;
-
- case BUILT_IN_SETJMP_SETUP:
- case BUILT_IN_SETJMP_RECEIVER:
- case BUILT_IN_LONGJMP:
- case BUILT_IN_NONLOCAL_GOTO:
- case BUILT_IN_UPDATE_SETJMP_BUF:
- case BUILT_IN_TRAP:
- case BUILT_IN_UNREACHABLE:
- return false;
-
- case BUILT_IN_UNWIND_INIT:
- case BUILT_IN_DWARF_CFA:
-#ifdef DWARF2_UNWIND_INFO
- case BUILT_IN_DWARF_SP_COLUMN:
- case BUILT_IN_INIT_DWARF_REG_SIZES:
-#endif
- case BUILT_IN_FROB_RETURN_ADDR:
- case BUILT_IN_EXTRACT_RETURN_ADDR:
- case BUILT_IN_EH_RETURN:
- case BUILT_IN_EH_RETURN_DATA_REGNO:
- case BUILT_IN_EXTEND_POINTER:
- case BUILT_IN_EH_POINTER:
- case BUILT_IN_EH_FILTER:
- case BUILT_IN_EH_COPY_VALUES:
- return false;
-
- case BUILT_IN_VA_START:
- case BUILT_IN_VA_END:
- case BUILT_IN_VA_COPY:
- case BUILT_IN_EXPECT:
- case BUILT_IN_EXPECT_WITH_PROBABILITY:
- case BUILT_IN_ASSUME_ALIGNED:
- case BUILT_IN_PREFETCH:
- return false;
-
- case BUILT_IN_ATOMIC_ALWAYS_LOCK_FREE:
- case BUILT_IN_OBJECT_SIZE:
- case BUILT_IN_THREAD_POINTER:
- case BUILT_IN_SET_THREAD_POINTER:
- return false;
-
- default:
- return true;
- }
-}
-#endif
-
typedef hash_set<tree> indirect_parms_t;
static tree
@@ -1402,32 +1380,61 @@ remove_named_attribute_unsharing (const char *name, tree *attrs)
}
}
-unsigned int
-pass_ipa_strub_mode::execute (function *)
+static int last_cgraph_order;
+
+static bool
+ipa_strub_set_mode_for_new_functions ()
{
- cgraph_node *onode;
+ if (last_cgraph_order && symtab->order == last_cgraph_order)
+ /* If we're called again after the first call,
+ then the first call must have returned true. */
+ return true;
- /* If no strub flag was given in the command line,
- set the actual default. */
- if (flag_strub == -2)
- flag_strub = 3; // for testing only; was: -1;
+ cgraph_node *node;
bool any_strub = false;
+ /* Go through the functions twice, once over non-aliases, and then over
+ aliases, so that aliases can reuse the mode computation of their ultimate
+ targets. */
for (int aliases = 0; aliases <= 1; aliases++)
- FOR_EACH_FUNCTION (onode)
+ FOR_EACH_FUNCTION (node)
{
- if (!onode->alias != !aliases)
+ if (!node->alias != !aliases)
continue;
- enum strub_mode mode = set_strub_mode (onode);
+ /* Already done. */
+ if (node->order < last_cgraph_order)
+ continue;
+
+ enum strub_mode mode = set_strub_mode (node);
if (mode == STRUB_AT_CALLS || mode == STRUB_INTERNAL)
any_strub = true;
}
+ if (any_strub)
+ last_cgraph_order = symtab->order;
+
+ return any_strub;
+}
+
+unsigned int
+pass_ipa_strub_mode::execute (function *)
+{
+ /* If no strub flag was given in the command line,
+ set the actual default. */
+ if (flag_strub == -2)
+ flag_strub = 3; // for testing only; was: -1;
+
+ last_cgraph_order = 0;
+ bool any_strub = ipa_strub_set_mode_for_new_functions ();
+
if (!any_strub)
flag_strub = 0;
+ else
+ /* Verify before any inlining or other transformations. */
+ verify_strub ();
return 0;
}
@@ -1438,54 +1445,13 @@ make_pass_ipa_strub_mode (gcc::context *ctxt)
return new pass_ipa_strub_mode (ctxt);
}
-/* Check that strub functions don't call non-strub functions, and that
- always_inline strub functions are only called by strub
- functions. */
-static void
-verify_strub ()
-{
- cgraph_node *node;
-
- FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
- {
- enum strub_mode caller_mode = get_strub_mode (node);
- bool strub_context
- = (caller_mode == STRUB_AT_CALLS
- || caller_mode == STRUB_WRAPPED
- || caller_mode == STRUB_INLINABLE);
-
- for (cgraph_edge *e = node->callees; e; e = e->next_callee)
- if (e->indirect_unknown_callee)
- {
- if (!strub_context)
- continue;
-
- tree callee_fntype = gimple_call_fntype (e->call_stmt);
- enum strub_mode callee_mode
- = get_strub_mode_from_type (callee_fntype);
-
- if (callee_mode == STRUB_DISABLED
- || callee_mode == STRUB_INTERNAL)
- error_at (gimple_location (e->call_stmt),
- "indirect non-strub call in strub context %qD",
- node->decl);
- }
- else if (!strub_callable_from_p (e->callee, node))
- error_at (gimple_location (e->call_stmt),
- "calling non-strub %qD in strub context %qD",
- e->callee->decl, node->decl);
- }
-
- /* ??? Check strub-wise pointer type compatibility of variables and
- functions, or is this already taken care of on account of the
- attribute's being marked as affecting type identity? */
-}
-
unsigned int
pass_ipa_strub::execute (function *)
{
cgraph_node *onode;
+ ipa_strub_set_mode_for_new_functions ();
+
FOR_EACH_FUNCTION (onode)
{
enum strub_mode mode = get_strub_mode (onode);
@@ -2418,7 +2384,14 @@ pass_ipa_strub::execute (function *)
#endif
}
- verify_strub ();
+ if (flag_checking)
+ {
+ /* We've already verified before any inlining or other transformations.
+ Recheck after strub transformations only if checking is enabled, since
+ they should not introduce any incompatibilities. */
+ ipa_strub_set_mode_for_new_functions ();
+ verify_strub ();
+ }
return 0;
}
^ permalink raw reply [flat|nested] 7+ messages in thread
* [gcc(refs/users/aoliva/heads/strub)] make builtins callable
@ 2021-07-26 20:55 Alexandre Oliva
0 siblings, 0 replies; 7+ messages in thread
From: Alexandre Oliva @ 2021-07-26 20:55 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:8ef03efec294a58d6ba2b8328c3363a34afa03a8
commit 8ef03efec294a58d6ba2b8328c3363a34afa03a8
Author: Alexandre Oliva <oliva@adacore.com>
Date: Mon Jul 26 12:15:36 2021 -0300
make builtins callable
Diff:
---
gcc/ipa-strub.c | 318 ++++++++++++++++++++++++++------------------------------
1 file changed, 148 insertions(+), 170 deletions(-)
diff --git a/gcc/ipa-strub.c b/gcc/ipa-strub.c
index 7b05321e980..573596edabd 100644
--- a/gcc/ipa-strub.c
+++ b/gcc/ipa-strub.c
@@ -438,6 +438,34 @@ strub_from_body_p (cgraph_node *node)
return false;
}
+/* Return true iff node is associated with a builtin that should be callable
+ from strub contexts. */
+static inline bool
+strub_callable_builtin_p (cgraph_node *node)
+{
+ if (DECL_BUILT_IN_CLASS (node->decl) != BUILT_IN_NORMAL)
+ return false;
+
+ enum built_in_function fcode = DECL_FUNCTION_CODE (node->decl);
+
+ switch (fcode)
+ {
+ case BUILT_IN_NONE:
+ gcc_unreachable ();
+
+ /* ??? Make all builtins callable. We wish to make any builtin call the
+ compiler might introduce on its own callable. Anything that is
+ predictable enough as to be known not to allow stack data that should
+ be strubbed to unintentionally escape to non-strub contexts can be
+ allowed, and pretty much every builtin appears to fit this description.
+ The exceptions to this rule seem to be rare, and only available as
+ explicit __builtin calls, so let's keep it simple and allow all of
+ them... */
+ default:
+ return true;
+ }
+}
+
static enum strub_mode
compute_strub_mode (cgraph_node *node, tree strub_attr)
{
@@ -495,7 +523,8 @@ compute_strub_mode (cgraph_node *node, tree strub_attr)
= (!strub_flag_disabled
&& (strub_attr
? req_mode == STRUB_CALLABLE
- : strub_flag_viable));
+ : (strub_flag_viable
+ || strub_callable_builtin_p (node))));
/* This is a shorthand for either strub-enabled mode. */
const bool consider_strub
@@ -730,6 +759,26 @@ set_strub_mode (cgraph_node *node)
{
tree attr = get_strub_attr_from_decl (node->decl);
+ if (attr)
+ switch (enum strub_mode mode = get_strub_mode_from_attr (attr))
+ {
+ /* These can't have been requested through user attributes, so we must
+ have already gone through them. */
+ case STRUB_WRAPPER:
+ case STRUB_WRAPPED:
+ case STRUB_INLINABLE:
+ return mode;
+
+ case STRUB_DISABLED:
+ case STRUB_AT_CALLS:
+ case STRUB_INTERNAL:
+ case STRUB_CALLABLE:
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
cgraph_node *xnode = node;
if (node->alias)
xnode = node->ultimate_alias_target ();
@@ -845,6 +894,49 @@ strub_inlinable_p (cgraph_node *callee, cgraph_node *caller)
return false;
}
+/* Check that strub functions don't call non-strub functions, and that
+ always_inline strub functions are only called by strub
+ functions. */
+static void
+verify_strub ()
+{
+ cgraph_node *node;
+
+ FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
+ {
+ enum strub_mode caller_mode = get_strub_mode (node);
+ bool strub_context
+ = (caller_mode == STRUB_AT_CALLS
+ || caller_mode == STRUB_WRAPPED
+ || caller_mode == STRUB_INLINABLE);
+
+ for (cgraph_edge *e = node->callees; e; e = e->next_callee)
+ if (e->indirect_unknown_callee)
+ {
+ if (!strub_context)
+ continue;
+
+ tree callee_fntype = gimple_call_fntype (e->call_stmt);
+ enum strub_mode callee_mode
+ = get_strub_mode_from_type (callee_fntype);
+
+ if (callee_mode == STRUB_DISABLED
+ || callee_mode == STRUB_INTERNAL)
+ error_at (gimple_location (e->call_stmt),
+ "indirect non-strub call in strub context %qD",
+ node->decl);
+ }
+ else if (!strub_callable_from_p (e->callee, node))
+ error_at (gimple_location (e->call_stmt),
+ "calling non-strub %qD in strub context %qD",
+ e->callee->decl, node->decl);
+ }
+
+ /* ??? Check strub-wise pointer type compatibility of variables and
+ functions, or is this already taken care of on account of the
+ attribute's being marked as affecting type identity? */
+}
+
namespace {
const pass_data pass_data_ipa_strub_mode = {
@@ -907,8 +999,6 @@ public:
NULL, NULL); \
TREE_NOTHROW (decl) = true; \
set_builtin_decl ((CODE), decl, true); \
- set_strub_mode_to (cgraph_node::get_create (decl), \
- STRUB_CALLABLE); \
} \
return decl; \
}
@@ -939,8 +1029,6 @@ public:
"__strub_" #NAME, attrs); \
TREE_NOTHROW (decl) = true; \
set_builtin_decl ((CODE), decl, true); \
- set_strub_mode_to (cgraph_node::get_create (decl), \
- STRUB_CALLABLE); \
} \
return decl; \
}
@@ -1014,116 +1102,6 @@ public:
} // anon namespace
-#if 0
-static bool
-may_throw_p (gcall *stmt)
-{
- return flag_exceptions && !gimple_call_nothrow_p (stmt);
-}
-
-static bool
-strub_this_call_p (gcall *stmt)
-{
- if (gimple_call_internal_p (stmt))
- return false;
-
- /* If there's no outgoing path in which to do the scrubbing, don't
- bother. */
- if (gimple_call_noreturn_p (stmt) && !may_throw_p (stmt))
- return false;
-
- /* ??? Maybe non-mandatory tail calls should be disabled for
- scrubbing. Or maybe it won't matter, as long as both tail-caller
- and callee are scrubbing-capable. */
- if (gimple_call_must_tail_p (stmt) || gimple_call_tail_p (stmt))
- return false;
-
- if (gimple_alloca_call_p (stmt))
- return true;
-
- tree fndecl = gimple_call_fndecl (stmt);
- if (!fndecl)
- return true;
-
- if (DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL)
- return true;
-
- enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
-
- switch (fcode)
- {
- CASE_BUILT_IN_ALLOCA:
- return true;
-
- case BUILT_IN_NONE:
- return true;
-
- case BUILT_IN___STRUB_ENTER:
- case BUILT_IN___STRUB_UPDATE:
- case BUILT_IN___STRUB_LEAVE:
- return false;
-
- case BUILT_IN_CLASSIFY_TYPE:
- case BUILT_IN_CONSTANT_P:
- return false;
-
- case BUILT_IN_RETURN_ADDRESS:
- case BUILT_IN_FRAME_ADDRESS:
- case BUILT_IN_STACK_ADDRESS:
- case BUILT_IN_AGGREGATE_INCOMING_ADDRESS:
- return false;
-
- case BUILT_IN_STACK_SAVE:
- case BUILT_IN_STACK_RESTORE:
- case BUILT_IN_ASAN_ALLOCAS_UNPOISON:
- return false;
-
- case BUILT_IN_SETJMP_SETUP:
- case BUILT_IN_SETJMP_RECEIVER:
- case BUILT_IN_LONGJMP:
- case BUILT_IN_NONLOCAL_GOTO:
- case BUILT_IN_UPDATE_SETJMP_BUF:
- case BUILT_IN_TRAP:
- case BUILT_IN_UNREACHABLE:
- return false;
-
- case BUILT_IN_UNWIND_INIT:
- case BUILT_IN_DWARF_CFA:
-#ifdef DWARF2_UNWIND_INFO
- case BUILT_IN_DWARF_SP_COLUMN:
- case BUILT_IN_INIT_DWARF_REG_SIZES:
-#endif
- case BUILT_IN_FROB_RETURN_ADDR:
- case BUILT_IN_EXTRACT_RETURN_ADDR:
- case BUILT_IN_EH_RETURN:
- case BUILT_IN_EH_RETURN_DATA_REGNO:
- case BUILT_IN_EXTEND_POINTER:
- case BUILT_IN_EH_POINTER:
- case BUILT_IN_EH_FILTER:
- case BUILT_IN_EH_COPY_VALUES:
- return false;
-
- case BUILT_IN_VA_START:
- case BUILT_IN_VA_END:
- case BUILT_IN_VA_COPY:
- case BUILT_IN_EXPECT:
- case BUILT_IN_EXPECT_WITH_PROBABILITY:
- case BUILT_IN_ASSUME_ALIGNED:
- case BUILT_IN_PREFETCH:
- return false;
-
- case BUILT_IN_ATOMIC_ALWAYS_LOCK_FREE:
- case BUILT_IN_OBJECT_SIZE:
- case BUILT_IN_THREAD_POINTER:
- case BUILT_IN_SET_THREAD_POINTER:
- return false;
-
- default:
- return true;
- }
-}
-#endif
-
typedef hash_set<tree> indirect_parms_t;
static tree
@@ -1402,32 +1380,61 @@ remove_named_attribute_unsharing (const char *name, tree *attrs)
}
}
-unsigned int
-pass_ipa_strub_mode::execute (function *)
+static int last_cgraph_order;
+
+static bool
+ipa_strub_set_mode_for_new_functions ()
{
- cgraph_node *onode;
+ if (last_cgraph_order && symtab->order == last_cgraph_order)
+ /* If we're called again after the first call,
+ then the first call must have returned true. */
+ return true;
- /* If no strub flag was given in the command line,
- set the actual default. */
- if (flag_strub == -2)
- flag_strub = 3; // for testing only; was: -1;
+ cgraph_node *node;
bool any_strub = false;
+ /* Go through the functions twice, once over non-aliases, and then over
+ aliases, so that aliases can reuse the mode computation of their ultimate
+ targets. */
for (int aliases = 0; aliases <= 1; aliases++)
- FOR_EACH_FUNCTION (onode)
+ FOR_EACH_FUNCTION (node)
{
- if (!onode->alias != !aliases)
+ if (!node->alias != !aliases)
+ continue;
+
+ /* Already done. */
+ if (node->order < last_cgraph_order)
continue;
- enum strub_mode mode = set_strub_mode (onode);
+ enum strub_mode mode = set_strub_mode (node);
if (mode == STRUB_AT_CALLS || mode == STRUB_INTERNAL)
any_strub = true;
}
+ if (any_strub)
+ last_cgraph_order = symtab->order;
+
+ return any_strub;
+}
+
+unsigned int
+pass_ipa_strub_mode::execute (function *)
+{
+ /* If no strub flag was given in the command line,
+ set the actual default. */
+ if (flag_strub == -2)
+ flag_strub = 3; // for testing only; was: -1;
+
+ last_cgraph_order = 0;
+ bool any_strub = ipa_strub_set_mode_for_new_functions ();
+
if (!any_strub)
flag_strub = 0;
+ else
+ /* Verify before any inlining or other transformations. */
+ verify_strub ();
return 0;
}
@@ -1438,54 +1445,13 @@ make_pass_ipa_strub_mode (gcc::context *ctxt)
return new pass_ipa_strub_mode (ctxt);
}
-/* Check that strub functions don't call non-strub functions, and that
- always_inline strub functions are only called by strub
- functions. */
-static void
-verify_strub ()
-{
- cgraph_node *node;
-
- FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
- {
- enum strub_mode caller_mode = get_strub_mode (node);
- bool strub_context
- = (caller_mode == STRUB_AT_CALLS
- || caller_mode == STRUB_WRAPPED
- || caller_mode == STRUB_INLINABLE);
-
- for (cgraph_edge *e = node->callees; e; e = e->next_callee)
- if (e->indirect_unknown_callee)
- {
- if (!strub_context)
- continue;
-
- tree callee_fntype = gimple_call_fntype (e->call_stmt);
- enum strub_mode callee_mode
- = get_strub_mode_from_type (callee_fntype);
-
- if (callee_mode == STRUB_DISABLED
- || callee_mode == STRUB_INTERNAL)
- error_at (gimple_location (e->call_stmt),
- "indirect non-strub call in strub context %qD",
- node->decl);
- }
- else if (!strub_callable_from_p (e->callee, node))
- error_at (gimple_location (e->call_stmt),
- "calling non-strub %qD in strub context %qD",
- e->callee->decl, node->decl);
- }
-
- /* ??? Check strub-wise pointer type compatibility of variables and
- functions, or is this already taken care of on account of the
- attribute's being marked as affecting type identity? */
-}
-
unsigned int
pass_ipa_strub::execute (function *)
{
cgraph_node *onode;
+ ipa_strub_set_mode_for_new_functions ();
+
FOR_EACH_FUNCTION (onode)
{
enum strub_mode mode = get_strub_mode (onode);
@@ -2291,7 +2257,12 @@ pass_ipa_strub::execute (function *)
}
gimple_call_set_arg (call, 1, arg);
update_stmt (call);
- e->redirect_callee (cgraph_node::get_create (bvacopy));
+
+ /* If we are causing the cgraph_node for va_copy to be needed,
+ compute a strub mode for it to make it callable, otherwise
+ verify_strub would reject it. */
+ cgraph_node *vacopy_node = cgraph_node::get (bvacopy);
+ e->redirect_callee (vacopy_node);
}
else if (fndecl && apply_args
&& fndecl_built_in_p (fndecl, BUILT_IN_APPLY_ARGS))
@@ -2418,7 +2389,14 @@ pass_ipa_strub::execute (function *)
#endif
}
- verify_strub ();
+ if (flag_checking)
+ {
+ /* We've already verified before any inlining or other transformations.
+ Recheck after strub transformations only if checking is enabled, since
+ they should not introduce any incompatibilities. */
+ ipa_strub_set_mode_for_new_functions ();
+ verify_strub ();
+ }
return 0;
}
^ permalink raw reply [flat|nested] 7+ messages in thread
* [gcc(refs/users/aoliva/heads/strub)] make builtins callable
@ 2021-07-26 20:36 Alexandre Oliva
0 siblings, 0 replies; 7+ messages in thread
From: Alexandre Oliva @ 2021-07-26 20:36 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:876827d3e0e519d3b90afcdfe5c694b26c0775ea
commit 876827d3e0e519d3b90afcdfe5c694b26c0775ea
Author: Alexandre Oliva <oliva@adacore.com>
Date: Mon Jul 26 12:15:36 2021 -0300
make builtins callable
Diff:
---
gcc/ipa-strub.c | 298 ++++++++++++++++++++++++--------------------------------
1 file changed, 128 insertions(+), 170 deletions(-)
diff --git a/gcc/ipa-strub.c b/gcc/ipa-strub.c
index 7b05321e980..05c742661d0 100644
--- a/gcc/ipa-strub.c
+++ b/gcc/ipa-strub.c
@@ -438,6 +438,34 @@ strub_from_body_p (cgraph_node *node)
return false;
}
+/* Return true iff node is associated with a builtin that should be callable
+ from strub contexts. */
+static inline bool
+strub_callable_builtin_p (cgraph_node *node)
+{
+ if (DECL_BUILT_IN_CLASS (node->decl) != BUILT_IN_NORMAL)
+ return false;
+
+ enum built_in_function fcode = DECL_FUNCTION_CODE (node->decl);
+
+ switch (fcode)
+ {
+ case BUILT_IN_NONE:
+ gcc_unreachable ();
+
+ /* ??? Make all builtins callable. We wish to make any builtin call the
+ compiler might introduce on its own callable. Anything that is
+ predictable enough as to be known not to allow stack data that should
+ be strubbed to unintentionally escape to non-strub contexts can be
+ allowed, and pretty much every builtin appears to fit this description.
+ The exceptions to this rule seem to be rare, and only available as
+ explicit __builtin calls, so let's keep it simple and allow all of
+ them... */
+ default:
+ return true;
+ }
+}
+
static enum strub_mode
compute_strub_mode (cgraph_node *node, tree strub_attr)
{
@@ -495,7 +523,8 @@ compute_strub_mode (cgraph_node *node, tree strub_attr)
= (!strub_flag_disabled
&& (strub_attr
? req_mode == STRUB_CALLABLE
- : strub_flag_viable));
+ : (strub_flag_viable
+ || strub_callable_builtin_p (node))));
/* This is a shorthand for either strub-enabled mode. */
const bool consider_strub
@@ -845,6 +874,49 @@ strub_inlinable_p (cgraph_node *callee, cgraph_node *caller)
return false;
}
+/* Check that strub functions don't call non-strub functions, and that
+ always_inline strub functions are only called by strub
+ functions. */
+static void
+verify_strub ()
+{
+ cgraph_node *node;
+
+ FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
+ {
+ enum strub_mode caller_mode = get_strub_mode (node);
+ bool strub_context
+ = (caller_mode == STRUB_AT_CALLS
+ || caller_mode == STRUB_WRAPPED
+ || caller_mode == STRUB_INLINABLE);
+
+ for (cgraph_edge *e = node->callees; e; e = e->next_callee)
+ if (e->indirect_unknown_callee)
+ {
+ if (!strub_context)
+ continue;
+
+ tree callee_fntype = gimple_call_fntype (e->call_stmt);
+ enum strub_mode callee_mode
+ = get_strub_mode_from_type (callee_fntype);
+
+ if (callee_mode == STRUB_DISABLED
+ || callee_mode == STRUB_INTERNAL)
+ error_at (gimple_location (e->call_stmt),
+ "indirect non-strub call in strub context %qD",
+ node->decl);
+ }
+ else if (!strub_callable_from_p (e->callee, node))
+ error_at (gimple_location (e->call_stmt),
+ "calling non-strub %qD in strub context %qD",
+ e->callee->decl, node->decl);
+ }
+
+ /* ??? Check strub-wise pointer type compatibility of variables and
+ functions, or is this already taken care of on account of the
+ attribute's being marked as affecting type identity? */
+}
+
namespace {
const pass_data pass_data_ipa_strub_mode = {
@@ -907,8 +979,6 @@ public:
NULL, NULL); \
TREE_NOTHROW (decl) = true; \
set_builtin_decl ((CODE), decl, true); \
- set_strub_mode_to (cgraph_node::get_create (decl), \
- STRUB_CALLABLE); \
} \
return decl; \
}
@@ -939,8 +1009,6 @@ public:
"__strub_" #NAME, attrs); \
TREE_NOTHROW (decl) = true; \
set_builtin_decl ((CODE), decl, true); \
- set_strub_mode_to (cgraph_node::get_create (decl), \
- STRUB_CALLABLE); \
} \
return decl; \
}
@@ -1014,116 +1082,6 @@ public:
} // anon namespace
-#if 0
-static bool
-may_throw_p (gcall *stmt)
-{
- return flag_exceptions && !gimple_call_nothrow_p (stmt);
-}
-
-static bool
-strub_this_call_p (gcall *stmt)
-{
- if (gimple_call_internal_p (stmt))
- return false;
-
- /* If there's no outgoing path in which to do the scrubbing, don't
- bother. */
- if (gimple_call_noreturn_p (stmt) && !may_throw_p (stmt))
- return false;
-
- /* ??? Maybe non-mandatory tail calls should be disabled for
- scrubbing. Or maybe it won't matter, as long as both tail-caller
- and callee are scrubbing-capable. */
- if (gimple_call_must_tail_p (stmt) || gimple_call_tail_p (stmt))
- return false;
-
- if (gimple_alloca_call_p (stmt))
- return true;
-
- tree fndecl = gimple_call_fndecl (stmt);
- if (!fndecl)
- return true;
-
- if (DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL)
- return true;
-
- enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
-
- switch (fcode)
- {
- CASE_BUILT_IN_ALLOCA:
- return true;
-
- case BUILT_IN_NONE:
- return true;
-
- case BUILT_IN___STRUB_ENTER:
- case BUILT_IN___STRUB_UPDATE:
- case BUILT_IN___STRUB_LEAVE:
- return false;
-
- case BUILT_IN_CLASSIFY_TYPE:
- case BUILT_IN_CONSTANT_P:
- return false;
-
- case BUILT_IN_RETURN_ADDRESS:
- case BUILT_IN_FRAME_ADDRESS:
- case BUILT_IN_STACK_ADDRESS:
- case BUILT_IN_AGGREGATE_INCOMING_ADDRESS:
- return false;
-
- case BUILT_IN_STACK_SAVE:
- case BUILT_IN_STACK_RESTORE:
- case BUILT_IN_ASAN_ALLOCAS_UNPOISON:
- return false;
-
- case BUILT_IN_SETJMP_SETUP:
- case BUILT_IN_SETJMP_RECEIVER:
- case BUILT_IN_LONGJMP:
- case BUILT_IN_NONLOCAL_GOTO:
- case BUILT_IN_UPDATE_SETJMP_BUF:
- case BUILT_IN_TRAP:
- case BUILT_IN_UNREACHABLE:
- return false;
-
- case BUILT_IN_UNWIND_INIT:
- case BUILT_IN_DWARF_CFA:
-#ifdef DWARF2_UNWIND_INFO
- case BUILT_IN_DWARF_SP_COLUMN:
- case BUILT_IN_INIT_DWARF_REG_SIZES:
-#endif
- case BUILT_IN_FROB_RETURN_ADDR:
- case BUILT_IN_EXTRACT_RETURN_ADDR:
- case BUILT_IN_EH_RETURN:
- case BUILT_IN_EH_RETURN_DATA_REGNO:
- case BUILT_IN_EXTEND_POINTER:
- case BUILT_IN_EH_POINTER:
- case BUILT_IN_EH_FILTER:
- case BUILT_IN_EH_COPY_VALUES:
- return false;
-
- case BUILT_IN_VA_START:
- case BUILT_IN_VA_END:
- case BUILT_IN_VA_COPY:
- case BUILT_IN_EXPECT:
- case BUILT_IN_EXPECT_WITH_PROBABILITY:
- case BUILT_IN_ASSUME_ALIGNED:
- case BUILT_IN_PREFETCH:
- return false;
-
- case BUILT_IN_ATOMIC_ALWAYS_LOCK_FREE:
- case BUILT_IN_OBJECT_SIZE:
- case BUILT_IN_THREAD_POINTER:
- case BUILT_IN_SET_THREAD_POINTER:
- return false;
-
- default:
- return true;
- }
-}
-#endif
-
typedef hash_set<tree> indirect_parms_t;
static tree
@@ -1402,32 +1360,61 @@ remove_named_attribute_unsharing (const char *name, tree *attrs)
}
}
-unsigned int
-pass_ipa_strub_mode::execute (function *)
+static int last_cgraph_order;
+
+static bool
+ipa_strub_set_mode_for_new_functions ()
{
- cgraph_node *onode;
+ if (last_cgraph_order && symtab->order == last_cgraph_order)
+ /* If we're called again after the first call,
+ then the first call must have returned true. */
+ return true;
- /* If no strub flag was given in the command line,
- set the actual default. */
- if (flag_strub == -2)
- flag_strub = 3; // for testing only; was: -1;
+ cgraph_node *node;
bool any_strub = false;
+ /* Go through the functions twice, once over non-aliases, and then over
+ aliases, so that aliases can reuse the mode computation of their ultimate
+ targets. */
for (int aliases = 0; aliases <= 1; aliases++)
- FOR_EACH_FUNCTION (onode)
+ FOR_EACH_FUNCTION (node)
{
- if (!onode->alias != !aliases)
+ if (!node->alias != !aliases)
continue;
- enum strub_mode mode = set_strub_mode (onode);
+ /* Already done. */
+ if (node->order < last_cgraph_order)
+ continue;
+
+ enum strub_mode mode = set_strub_mode (node);
if (mode == STRUB_AT_CALLS || mode == STRUB_INTERNAL)
any_strub = true;
}
+ if (any_strub)
+ last_cgraph_order = symtab->order;
+
+ return any_strub;
+}
+
+unsigned int
+pass_ipa_strub_mode::execute (function *)
+{
+ /* If no strub flag was given in the command line,
+ set the actual default. */
+ if (flag_strub == -2)
+ flag_strub = 3; // for testing only; was: -1;
+
+ last_cgraph_order = 0;
+ bool any_strub = ipa_strub_set_mode_for_new_functions ();
+
if (!any_strub)
flag_strub = 0;
+ else
+ /* Verify before any inlining or other transformations. */
+ verify_strub ();
return 0;
}
@@ -1438,54 +1425,13 @@ make_pass_ipa_strub_mode (gcc::context *ctxt)
return new pass_ipa_strub_mode (ctxt);
}
-/* Check that strub functions don't call non-strub functions, and that
- always_inline strub functions are only called by strub
- functions. */
-static void
-verify_strub ()
-{
- cgraph_node *node;
-
- FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
- {
- enum strub_mode caller_mode = get_strub_mode (node);
- bool strub_context
- = (caller_mode == STRUB_AT_CALLS
- || caller_mode == STRUB_WRAPPED
- || caller_mode == STRUB_INLINABLE);
-
- for (cgraph_edge *e = node->callees; e; e = e->next_callee)
- if (e->indirect_unknown_callee)
- {
- if (!strub_context)
- continue;
-
- tree callee_fntype = gimple_call_fntype (e->call_stmt);
- enum strub_mode callee_mode
- = get_strub_mode_from_type (callee_fntype);
-
- if (callee_mode == STRUB_DISABLED
- || callee_mode == STRUB_INTERNAL)
- error_at (gimple_location (e->call_stmt),
- "indirect non-strub call in strub context %qD",
- node->decl);
- }
- else if (!strub_callable_from_p (e->callee, node))
- error_at (gimple_location (e->call_stmt),
- "calling non-strub %qD in strub context %qD",
- e->callee->decl, node->decl);
- }
-
- /* ??? Check strub-wise pointer type compatibility of variables and
- functions, or is this already taken care of on account of the
- attribute's being marked as affecting type identity? */
-}
-
unsigned int
pass_ipa_strub::execute (function *)
{
cgraph_node *onode;
+ ipa_strub_set_mode_for_new_functions ();
+
FOR_EACH_FUNCTION (onode)
{
enum strub_mode mode = get_strub_mode (onode);
@@ -2291,7 +2237,12 @@ pass_ipa_strub::execute (function *)
}
gimple_call_set_arg (call, 1, arg);
update_stmt (call);
- e->redirect_callee (cgraph_node::get_create (bvacopy));
+
+ /* If we are causing the cgraph_node for va_copy to be needed,
+ compute a strub mode for it to make it callable, otherwise
+ verify_strub would reject it. */
+ cgraph_node *vacopy_node = cgraph_node::get (bvacopy);
+ e->redirect_callee (vacopy_node);
}
else if (fndecl && apply_args
&& fndecl_built_in_p (fndecl, BUILT_IN_APPLY_ARGS))
@@ -2418,7 +2369,14 @@ pass_ipa_strub::execute (function *)
#endif
}
- verify_strub ();
+ if (flag_checking)
+ {
+ /* We've already verified before any inlining or other transformations.
+ Recheck after strub transformations only if checking is enabled, since
+ they should not introduce any incompatibilities. */
+ ipa_strub_set_mode_for_new_functions ();
+ verify_strub ();
+ }
return 0;
}
^ permalink raw reply [flat|nested] 7+ messages in thread
* [gcc(refs/users/aoliva/heads/strub)] make builtins callable
@ 2021-07-26 18:25 Alexandre Oliva
0 siblings, 0 replies; 7+ messages in thread
From: Alexandre Oliva @ 2021-07-26 18:25 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:2d7e1ec7bce83f538346c36afba432eec861b542
commit 2d7e1ec7bce83f538346c36afba432eec861b542
Author: Alexandre Oliva <oliva@adacore.com>
Date: Mon Jul 26 12:15:36 2021 -0300
make builtins callable
Diff:
---
gcc/ipa-strub.c | 266 +++++++++++++++++++++++---------------------------------
1 file changed, 110 insertions(+), 156 deletions(-)
diff --git a/gcc/ipa-strub.c b/gcc/ipa-strub.c
index 7b05321e980..7ec606a4c74 100644
--- a/gcc/ipa-strub.c
+++ b/gcc/ipa-strub.c
@@ -438,6 +438,34 @@ strub_from_body_p (cgraph_node *node)
return false;
}
+/* Return true iff node is associated with a builtin that should be callable
+ from strub contexts. */
+static inline bool
+strub_callable_builtin_p (cgraph_node *node)
+{
+ if (DECL_BUILT_IN_CLASS (node->decl) != BUILT_IN_NORMAL)
+ return false;
+
+ enum built_in_function fcode = DECL_FUNCTION_CODE (node->decl);
+
+ switch (fcode)
+ {
+ case BUILT_IN_NONE:
+ gcc_unreachable ();
+
+ /* ??? Make all builtins callable. We wish to make any builtin call the
+ compiler might introduce on its own callable. Anything that is
+ predictable enough as to be known not to allow stack data that should
+ be strubbed to unintentionally escape to non-strub contexts can be
+ allowed, and pretty much every builtin appears to fit this description.
+ The exceptions to this rule seem to be rare, and only available as
+ explicit __builtin calls, so let's keep it simple and allow all of
+ them... */
+ default:
+ return true;
+ }
+}
+
static enum strub_mode
compute_strub_mode (cgraph_node *node, tree strub_attr)
{
@@ -495,7 +523,8 @@ compute_strub_mode (cgraph_node *node, tree strub_attr)
= (!strub_flag_disabled
&& (strub_attr
? req_mode == STRUB_CALLABLE
- : strub_flag_viable));
+ : (strub_flag_viable
+ || strub_callable_builtin_p (node))));
/* This is a shorthand for either strub-enabled mode. */
const bool consider_strub
@@ -746,6 +775,14 @@ set_strub_mode (cgraph_node *node)
return mode;
}
+static cgraph_node_hook_list *strub_cgraph_hook_entry = NULL;
+
+static void
+strub_cgraph_insertion_hook (cgraph_node *node, void *)
+{
+ set_strub_mode (node);
+}
+
/* Non-strub functions shouldn't be called from strub functions,
except through callable ones. Always inline strub functions can
only be called from strub functions. */
@@ -845,6 +882,49 @@ strub_inlinable_p (cgraph_node *callee, cgraph_node *caller)
return false;
}
+/* Check that strub functions don't call non-strub functions, and that
+ always_inline strub functions are only called by strub
+ functions. */
+static void
+verify_strub ()
+{
+ cgraph_node *node;
+
+ FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
+ {
+ enum strub_mode caller_mode = get_strub_mode (node);
+ bool strub_context
+ = (caller_mode == STRUB_AT_CALLS
+ || caller_mode == STRUB_WRAPPED
+ || caller_mode == STRUB_INLINABLE);
+
+ for (cgraph_edge *e = node->callees; e; e = e->next_callee)
+ if (e->indirect_unknown_callee)
+ {
+ if (!strub_context)
+ continue;
+
+ tree callee_fntype = gimple_call_fntype (e->call_stmt);
+ enum strub_mode callee_mode
+ = get_strub_mode_from_type (callee_fntype);
+
+ if (callee_mode == STRUB_DISABLED
+ || callee_mode == STRUB_INTERNAL)
+ error_at (gimple_location (e->call_stmt),
+ "indirect non-strub call in strub context %qD",
+ node->decl);
+ }
+ else if (!strub_callable_from_p (e->callee, node))
+ error_at (gimple_location (e->call_stmt),
+ "calling non-strub %qD in strub context %qD",
+ e->callee->decl, node->decl);
+ }
+
+ /* ??? Check strub-wise pointer type compatibility of variables and
+ functions, or is this already taken care of on account of the
+ attribute's being marked as affecting type identity? */
+}
+
namespace {
const pass_data pass_data_ipa_strub_mode = {
@@ -1014,116 +1094,6 @@ public:
} // anon namespace
-#if 0
-static bool
-may_throw_p (gcall *stmt)
-{
- return flag_exceptions && !gimple_call_nothrow_p (stmt);
-}
-
-static bool
-strub_this_call_p (gcall *stmt)
-{
- if (gimple_call_internal_p (stmt))
- return false;
-
- /* If there's no outgoing path in which to do the scrubbing, don't
- bother. */
- if (gimple_call_noreturn_p (stmt) && !may_throw_p (stmt))
- return false;
-
- /* ??? Maybe non-mandatory tail calls should be disabled for
- scrubbing. Or maybe it won't matter, as long as both tail-caller
- and callee are scrubbing-capable. */
- if (gimple_call_must_tail_p (stmt) || gimple_call_tail_p (stmt))
- return false;
-
- if (gimple_alloca_call_p (stmt))
- return true;
-
- tree fndecl = gimple_call_fndecl (stmt);
- if (!fndecl)
- return true;
-
- if (DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL)
- return true;
-
- enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
-
- switch (fcode)
- {
- CASE_BUILT_IN_ALLOCA:
- return true;
-
- case BUILT_IN_NONE:
- return true;
-
- case BUILT_IN___STRUB_ENTER:
- case BUILT_IN___STRUB_UPDATE:
- case BUILT_IN___STRUB_LEAVE:
- return false;
-
- case BUILT_IN_CLASSIFY_TYPE:
- case BUILT_IN_CONSTANT_P:
- return false;
-
- case BUILT_IN_RETURN_ADDRESS:
- case BUILT_IN_FRAME_ADDRESS:
- case BUILT_IN_STACK_ADDRESS:
- case BUILT_IN_AGGREGATE_INCOMING_ADDRESS:
- return false;
-
- case BUILT_IN_STACK_SAVE:
- case BUILT_IN_STACK_RESTORE:
- case BUILT_IN_ASAN_ALLOCAS_UNPOISON:
- return false;
-
- case BUILT_IN_SETJMP_SETUP:
- case BUILT_IN_SETJMP_RECEIVER:
- case BUILT_IN_LONGJMP:
- case BUILT_IN_NONLOCAL_GOTO:
- case BUILT_IN_UPDATE_SETJMP_BUF:
- case BUILT_IN_TRAP:
- case BUILT_IN_UNREACHABLE:
- return false;
-
- case BUILT_IN_UNWIND_INIT:
- case BUILT_IN_DWARF_CFA:
-#ifdef DWARF2_UNWIND_INFO
- case BUILT_IN_DWARF_SP_COLUMN:
- case BUILT_IN_INIT_DWARF_REG_SIZES:
-#endif
- case BUILT_IN_FROB_RETURN_ADDR:
- case BUILT_IN_EXTRACT_RETURN_ADDR:
- case BUILT_IN_EH_RETURN:
- case BUILT_IN_EH_RETURN_DATA_REGNO:
- case BUILT_IN_EXTEND_POINTER:
- case BUILT_IN_EH_POINTER:
- case BUILT_IN_EH_FILTER:
- case BUILT_IN_EH_COPY_VALUES:
- return false;
-
- case BUILT_IN_VA_START:
- case BUILT_IN_VA_END:
- case BUILT_IN_VA_COPY:
- case BUILT_IN_EXPECT:
- case BUILT_IN_EXPECT_WITH_PROBABILITY:
- case BUILT_IN_ASSUME_ALIGNED:
- case BUILT_IN_PREFETCH:
- return false;
-
- case BUILT_IN_ATOMIC_ALWAYS_LOCK_FREE:
- case BUILT_IN_OBJECT_SIZE:
- case BUILT_IN_THREAD_POINTER:
- case BUILT_IN_SET_THREAD_POINTER:
- return false;
-
- default:
- return true;
- }
-}
-#endif
-
typedef hash_set<tree> indirect_parms_t;
static tree
@@ -1414,6 +1384,9 @@ pass_ipa_strub_mode::execute (function *)
bool any_strub = false;
+ /* Go through the functions twice, once over non-aliases, and then over
+ aliases, so that aliases can reuse the mode computation of their ultimate
+ targets. */
for (int aliases = 0; aliases <= 1; aliases++)
FOR_EACH_FUNCTION (onode)
{
@@ -1428,6 +1401,14 @@ pass_ipa_strub_mode::execute (function *)
if (!any_strub)
flag_strub = 0;
+ else
+ {
+ /* Verify before any inlining or other transformations. */
+ verify_strub ();
+
+ strub_cgraph_hook_entry = symtab->add_cgraph_insertion_hook
+ (strub_cgraph_insertion_hook, NULL);
+ }
return 0;
}
@@ -1438,49 +1419,6 @@ make_pass_ipa_strub_mode (gcc::context *ctxt)
return new pass_ipa_strub_mode (ctxt);
}
-/* Check that strub functions don't call non-strub functions, and that
- always_inline strub functions are only called by strub
- functions. */
-static void
-verify_strub ()
-{
- cgraph_node *node;
-
- FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
- {
- enum strub_mode caller_mode = get_strub_mode (node);
- bool strub_context
- = (caller_mode == STRUB_AT_CALLS
- || caller_mode == STRUB_WRAPPED
- || caller_mode == STRUB_INLINABLE);
-
- for (cgraph_edge *e = node->callees; e; e = e->next_callee)
- if (e->indirect_unknown_callee)
- {
- if (!strub_context)
- continue;
-
- tree callee_fntype = gimple_call_fntype (e->call_stmt);
- enum strub_mode callee_mode
- = get_strub_mode_from_type (callee_fntype);
-
- if (callee_mode == STRUB_DISABLED
- || callee_mode == STRUB_INTERNAL)
- error_at (gimple_location (e->call_stmt),
- "indirect non-strub call in strub context %qD",
- node->decl);
- }
- else if (!strub_callable_from_p (e->callee, node))
- error_at (gimple_location (e->call_stmt),
- "calling non-strub %qD in strub context %qD",
- e->callee->decl, node->decl);
- }
-
- /* ??? Check strub-wise pointer type compatibility of variables and
- functions, or is this already taken care of on account of the
- attribute's being marked as affecting type identity? */
-}
-
unsigned int
pass_ipa_strub::execute (function *)
{
@@ -2291,7 +2229,17 @@ pass_ipa_strub::execute (function *)
}
gimple_call_set_arg (call, 1, arg);
update_stmt (call);
- e->redirect_callee (cgraph_node::get_create (bvacopy));
+
+ /* If we are causing the cgraph_node for va_copy to be needed,
+ compute a strub mode for it to make it callable, otherwise
+ verify_strub would reject it. */
+ cgraph_node *vacopy_node = cgraph_node::get (bvacopy);
+ if (!vacopy_node)
+ {
+ vacopy_node = cgraph_node::get_create (bvacopy);
+ set_strub_mode (vacopy_node);
+ }
+ e->redirect_callee (vacopy_node);
}
else if (fndecl && apply_args
&& fndecl_built_in_p (fndecl, BUILT_IN_APPLY_ARGS))
@@ -2418,7 +2366,13 @@ pass_ipa_strub::execute (function *)
#endif
}
- verify_strub ();
+ if (flag_checking)
+ /* We've already verified before any inlining or other transformations.
+ Recheck after strub transformations only if checking is enabled, since
+ they should not introduce any incompatibilities. */
+ verify_strub ();
+
+ symtab->remove_cgraph_insertion_hook (strub_cgraph_hook_entry);
return 0;
}
^ permalink raw reply [flat|nested] 7+ messages in thread
* [gcc(refs/users/aoliva/heads/strub)] make builtins callable
@ 2021-07-26 15:18 Alexandre Oliva
0 siblings, 0 replies; 7+ messages in thread
From: Alexandre Oliva @ 2021-07-26 15:18 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:55724817dd9d178f5671ec1db4a5d3a836f8928b
commit 55724817dd9d178f5671ec1db4a5d3a836f8928b
Author: Alexandre Oliva <oliva@adacore.com>
Date: Mon Jul 26 12:15:36 2021 -0300
make builtins callable
Diff:
---
gcc/ipa-strub.c | 153 +++++++++++++++-----------------------------------------
1 file changed, 41 insertions(+), 112 deletions(-)
diff --git a/gcc/ipa-strub.c b/gcc/ipa-strub.c
index 7b05321e980..ba80f2faed9 100644
--- a/gcc/ipa-strub.c
+++ b/gcc/ipa-strub.c
@@ -438,6 +438,34 @@ strub_from_body_p (cgraph_node *node)
return false;
}
+/* Return true iff node is associated with a builtin that should be callable
+ from strub contexts. */
+static inline bool
+strub_callable_builtin_p (cgraph_node *node)
+{
+ if (DECL_BUILT_IN_CLASS (node->decl) != BUILT_IN_NORMAL)
+ return false;
+
+ enum built_in_function fcode = DECL_FUNCTION_CODE (node->decl);
+
+ switch (fcode)
+ {
+ case BUILT_IN_NONE:
+ gcc_unreachable ();
+
+ /* ??? Make all builtins callable. We wish to make any builtin call the
+ compiler might introduce on its own callable. Anything that is
+ predictable enough as to be known not to allow stack data that should
+ be strubbed to unintentionally escape to non-strub contexts can be
+ allowed, and pretty much every builtin appears to fit this description.
+ The exceptions to this rule seem to be rare, and only available as
+ explicit __builtin calls, so let's keep it simple and allow all of
+ them... */
+ default:
+ return true;
+ }
+}
+
static enum strub_mode
compute_strub_mode (cgraph_node *node, tree strub_attr)
{
@@ -495,7 +523,8 @@ compute_strub_mode (cgraph_node *node, tree strub_attr)
= (!strub_flag_disabled
&& (strub_attr
? req_mode == STRUB_CALLABLE
- : strub_flag_viable));
+ : (strub_flag_viable
+ || strub_callable_builtin_p (node))));
/* This is a shorthand for either strub-enabled mode. */
const bool consider_strub
@@ -1014,116 +1043,6 @@ public:
} // anon namespace
-#if 0
-static bool
-may_throw_p (gcall *stmt)
-{
- return flag_exceptions && !gimple_call_nothrow_p (stmt);
-}
-
-static bool
-strub_this_call_p (gcall *stmt)
-{
- if (gimple_call_internal_p (stmt))
- return false;
-
- /* If there's no outgoing path in which to do the scrubbing, don't
- bother. */
- if (gimple_call_noreturn_p (stmt) && !may_throw_p (stmt))
- return false;
-
- /* ??? Maybe non-mandatory tail calls should be disabled for
- scrubbing. Or maybe it won't matter, as long as both tail-caller
- and callee are scrubbing-capable. */
- if (gimple_call_must_tail_p (stmt) || gimple_call_tail_p (stmt))
- return false;
-
- if (gimple_alloca_call_p (stmt))
- return true;
-
- tree fndecl = gimple_call_fndecl (stmt);
- if (!fndecl)
- return true;
-
- if (DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL)
- return true;
-
- enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
-
- switch (fcode)
- {
- CASE_BUILT_IN_ALLOCA:
- return true;
-
- case BUILT_IN_NONE:
- return true;
-
- case BUILT_IN___STRUB_ENTER:
- case BUILT_IN___STRUB_UPDATE:
- case BUILT_IN___STRUB_LEAVE:
- return false;
-
- case BUILT_IN_CLASSIFY_TYPE:
- case BUILT_IN_CONSTANT_P:
- return false;
-
- case BUILT_IN_RETURN_ADDRESS:
- case BUILT_IN_FRAME_ADDRESS:
- case BUILT_IN_STACK_ADDRESS:
- case BUILT_IN_AGGREGATE_INCOMING_ADDRESS:
- return false;
-
- case BUILT_IN_STACK_SAVE:
- case BUILT_IN_STACK_RESTORE:
- case BUILT_IN_ASAN_ALLOCAS_UNPOISON:
- return false;
-
- case BUILT_IN_SETJMP_SETUP:
- case BUILT_IN_SETJMP_RECEIVER:
- case BUILT_IN_LONGJMP:
- case BUILT_IN_NONLOCAL_GOTO:
- case BUILT_IN_UPDATE_SETJMP_BUF:
- case BUILT_IN_TRAP:
- case BUILT_IN_UNREACHABLE:
- return false;
-
- case BUILT_IN_UNWIND_INIT:
- case BUILT_IN_DWARF_CFA:
-#ifdef DWARF2_UNWIND_INFO
- case BUILT_IN_DWARF_SP_COLUMN:
- case BUILT_IN_INIT_DWARF_REG_SIZES:
-#endif
- case BUILT_IN_FROB_RETURN_ADDR:
- case BUILT_IN_EXTRACT_RETURN_ADDR:
- case BUILT_IN_EH_RETURN:
- case BUILT_IN_EH_RETURN_DATA_REGNO:
- case BUILT_IN_EXTEND_POINTER:
- case BUILT_IN_EH_POINTER:
- case BUILT_IN_EH_FILTER:
- case BUILT_IN_EH_COPY_VALUES:
- return false;
-
- case BUILT_IN_VA_START:
- case BUILT_IN_VA_END:
- case BUILT_IN_VA_COPY:
- case BUILT_IN_EXPECT:
- case BUILT_IN_EXPECT_WITH_PROBABILITY:
- case BUILT_IN_ASSUME_ALIGNED:
- case BUILT_IN_PREFETCH:
- return false;
-
- case BUILT_IN_ATOMIC_ALWAYS_LOCK_FREE:
- case BUILT_IN_OBJECT_SIZE:
- case BUILT_IN_THREAD_POINTER:
- case BUILT_IN_SET_THREAD_POINTER:
- return false;
-
- default:
- return true;
- }
-}
-#endif
-
typedef hash_set<tree> indirect_parms_t;
static tree
@@ -2291,7 +2210,17 @@ pass_ipa_strub::execute (function *)
}
gimple_call_set_arg (call, 1, arg);
update_stmt (call);
- e->redirect_callee (cgraph_node::get_create (bvacopy));
+
+ /* If we are causing the cgraph_node for va_copy to be needed,
+ compute a strub mode for it to make it callable, otherwise
+ verify_strub will reject it. */
+ cgraph_node *vacopy_node = cgraph_node::get (bvacopy);
+ if (!vacopy_node)
+ {
+ vacopy_node = cgraph_node::get_create (bvacopy);
+ set_strub_mode (vacopy_node);
+ }
+ e->redirect_callee (vacopy_node);
}
else if (fndecl && apply_args
&& fndecl_built_in_p (fndecl, BUILT_IN_APPLY_ARGS))
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2021-07-28 4:30 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-07-26 15:43 [gcc(refs/users/aoliva/heads/strub)] make builtins callable Alexandre Oliva
-- strict thread matches above, loose matches on Subject: below --
2021-07-28 4:30 Alexandre Oliva
2021-07-26 21:05 Alexandre Oliva
2021-07-26 20:55 Alexandre Oliva
2021-07-26 20:36 Alexandre Oliva
2021-07-26 18:25 Alexandre Oliva
2021-07-26 15:18 Alexandre Oliva
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).