public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc(refs/users/aoliva/heads/strub)] fix strub function type sharing
@ 2021-11-16  5:13 Alexandre Oliva
  0 siblings, 0 replies; only message in thread
From: Alexandre Oliva @ 2021-11-16  5:13 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:859656002a7d255ed6697d06afe654fceb8302e7

commit 859656002a7d255ed6697d06afe654fceb8302e7
Author: Alexandre Oliva <oliva@adacore.com>
Date:   Wed Nov 10 00:24:30 2021 -0300

    fix strub function type sharing
    
    When a function type is copied and modified to add an at-calls strub
    mode, propagate the function type to fntype and address type in any
    calls involving the function, so that we don't modify unrelated types
    equivalent to the unmodified function type.
    
    
    for  gcc/ChangeLog
    
            * ipa-strub.cc (effective_strub_mode_for_call): New.
            (distinctify_node_type): New.
            (same_strub_mode_in_variants_p): New.
            (verify_strub): Use factored-out effective mode logic.
            (pass_ipa_strub::adjust_at_calls_type): Likewise.  Check mode
            in all variant and canonical types.
            (pass_ipa_strub::execute): Use dinstinctify_node_type.

Diff:
---
 gcc/ipa-strub.cc | 120 ++++++++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 96 insertions(+), 24 deletions(-)

diff --git a/gcc/ipa-strub.cc b/gcc/ipa-strub.cc
index 43b2dd80d5d..4c1efe73f7f 100644
--- a/gcc/ipa-strub.cc
+++ b/gcc/ipa-strub.cc
@@ -1317,6 +1317,90 @@ strub_comptypes (tree t1, tree t2)
   return 2;
 }
 
+/* Return the effective strub mode used for CALL, and set *TYPEP to
+   the effective type used for the call.  The effective type and mode
+   are those of the callee, unless the call involves a typecast.  */
+
+static enum strub_mode
+effective_strub_mode_for_call (gcall *call, tree *typep)
+{
+  tree type;
+  enum strub_mode mode;
+
+  if (gimple_call_fntype_override_p (call))
+    {
+      type = gimple_call_fntype (call);
+      mode = get_strub_mode_from_type (type);
+    }
+  else
+    {
+      type = TREE_TYPE (TREE_TYPE (gimple_call_fn (call)));
+      tree decl = gimple_call_fndecl (call);
+      if (decl)
+	mode = get_strub_mode_from_fndecl (decl);
+      else
+	mode = get_strub_mode_from_type (type);
+    }
+
+  if (typep)
+    *typep = type;
+
+  return mode;
+}
+
+/* Create a distinct copy of the type of NODE's function, and change
+   the fntype of all calls to it with the same main type to the new
+   type.  */
+
+static void
+distinctify_node_type (cgraph_node *node)
+{
+  tree old_type = TREE_TYPE (node->decl);
+  tree new_type = build_distinct_type_copy (old_type);
+  tree new_ptr_type = NULL_TREE;
+
+  /* Remap any calls to node->decl that use old_type, or a variant
+     thereof, to new_type as well.  We don't look for aliases, their
+     declarations will have their types changed independently, and
+     we'll adjust their fntypes then.  */
+  for (cgraph_edge *e = node->callers; e; e = e->next_caller)
+    {
+      tree fnaddr = gimple_call_fn (e->call_stmt);
+      gcc_checking_assert (TREE_CODE (fnaddr) == ADDR_EXPR
+			   && TREE_OPERAND (fnaddr, 0) == node->decl);
+      if (gimple_call_fntype_override_p (e->call_stmt))
+	continue;
+      if (!new_ptr_type)
+	new_ptr_type = build_pointer_type (new_type);
+      TREE_TYPE (fnaddr) = new_ptr_type;
+      gimple_call_set_fntype (e->call_stmt, new_type);
+    }
+
+  TREE_TYPE (node->decl) = new_type;
+}
+
+/* Return TRUE if TYPE and any variants have the same strub mode,
+   and false otherwise.  */
+
+static bool
+same_strub_mode_in_variants_p (tree type)
+{
+  if (TYPE_CANONICAL (type)
+      && (get_strub_mode_from_type (type)
+	  != get_strub_mode_from_type (TYPE_CANONICAL (type))))
+    return false;
+
+  for (tree other = TYPE_MAIN_VARIANT (type);
+       other != NULL_TREE; other = TYPE_NEXT_VARIANT (type))
+    if (other == type)
+      continue;
+    else if (get_strub_mode_from_type (type)
+	     != get_strub_mode_from_type (TYPE_MAIN_VARIANT (type)))
+      return false;
+
+  return true;
+}
+
 /* Check that strub functions don't call non-strub functions, and that
    always_inline strub functions are only called by strub
    functions.  */
@@ -1341,9 +1425,8 @@ verify_strub ()
       {
 	gcc_checking_assert (e->indirect_unknown_callee);
 
-	tree callee_fntype = gimple_call_fntype (e->call_stmt);
 	enum strub_mode callee_mode
-	  = get_strub_mode_from_type (callee_fntype);
+	  = effective_strub_mode_for_call (e->call_stmt, NULL);
 
 	if (!strub_callable_from_p (caller_mode, callee_mode))
 	  error_at (gimple_location (e->call_stmt),
@@ -1355,17 +1438,9 @@ verify_strub ()
       {
 	gcc_checking_assert (!e->indirect_unknown_callee);
 
-	tree callee_fntype = gimple_call_fntype (e->call_stmt);
-	/* fntype is NULL for internal calls, and builtins may carry a
-	   variant type.  */
-	bool use_callee_mode_p
-	  = (!callee_fntype
-	     || (TYPE_MAIN_VARIANT (TREE_TYPE (e->callee->decl))
-		 == TYPE_MAIN_VARIANT (callee_fntype)));
-	strub_mode callee_mode
-	  = (use_callee_mode_p
-	     ? get_strub_mode (e->callee)
-	     : get_strub_mode_from_type (callee_fntype));
+	tree callee_fntype;
+	enum strub_mode callee_mode
+	  = effective_strub_mode_for_call (e->call_stmt, &callee_fntype);
 
 	if (!strub_callable_from_p (caller_mode, callee_mode))
 	  {
@@ -1379,7 +1454,7 @@ verify_strub ()
 	      /* This is ok, it will be kept in the STRUB_WRAPPER, and removed
 		 from the STRUB_WRAPPED's strub context.  */
 	      continue;
-	    else if (use_callee_mode_p)
+	    else if (!gimple_call_fntype_override_p (e->call_stmt))
 	      error_at (gimple_location (e->call_stmt),
 			"calling non-%<strub%> %qD in %<strub%> context %qD",
 			e->callee->decl, node->decl);
@@ -2056,6 +2131,8 @@ pass_ipa_strub::adjust_at_calls_type (tree type)
 {
   int named_args = 0;
 
+  gcc_checking_assert (same_strub_mode_in_variants_p (type));
+
   if (!TYPE_ARG_TYPES (type))
     return named_args;
 
@@ -2312,9 +2389,9 @@ pass_ipa_strub::adjust_at_calls_calls (cgraph_node *node)
 	{
 	  gcc_checking_assert (e->indirect_unknown_callee);
 
-	  tree callee_fntype = gimple_call_fntype (e->call_stmt);
+	  tree callee_fntype;
 	  enum strub_mode callee_mode
-	    = get_strub_mode_from_type (callee_fntype);
+	    = effective_strub_mode_for_call (e->call_stmt, &callee_fntype);
 
 	  if (callee_mode != STRUB_AT_CALLS
 	      && callee_mode != STRUB_AT_CALLS_OPT)
@@ -2334,13 +2411,9 @@ pass_ipa_strub::adjust_at_calls_calls (cgraph_node *node)
 	{
 	  gcc_checking_assert (!e->indirect_unknown_callee);
 
-	  tree callee_fntype = gimple_call_fntype (e->call_stmt);
+	  tree callee_fntype;
 	  enum strub_mode callee_mode
-	    = (!callee_fntype
-	       || (TYPE_MAIN_VARIANT (callee_fntype)
-		   != TYPE_MAIN_VARIANT (TREE_TYPE (e->callee->decl)))
-	       ? get_strub_mode (e->callee)
-	       : get_strub_mode_from_type (callee_fntype));
+	    = effective_strub_mode_for_call (e->call_stmt, &callee_fntype);
 
 	  if (callee_mode != STRUB_AT_CALLS
 	      && callee_mode != STRUB_AT_CALLS_OPT)
@@ -2401,8 +2474,7 @@ pass_ipa_strub::execute (function *)
 	/* Create a type variant if strubbing was not explicitly requested in
 	   the function type.  */
 	if (get_strub_mode_from_type (TREE_TYPE (onode->decl)) != mode)
-	  TREE_TYPE (onode->decl) = build_distinct_type_copy (TREE_TYPE
-							      (onode->decl));
+	  distinctify_node_type (onode);
 
 	int named_args = adjust_at_calls_type (TREE_TYPE (onode->decl));


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2021-11-16  5:13 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-11-16  5:13 [gcc(refs/users/aoliva/heads/strub)] fix strub function type sharing 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).