public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc(refs/users/aoliva/heads/testme)] gimple fntype call override
@ 2021-11-16  3:49 Alexandre Oliva
  0 siblings, 0 replies; only message in thread
From: Alexandre Oliva @ 2021-11-16  3:49 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:0e81078ac4234982da8dd528be905d45cb970c59

commit 0e81078ac4234982da8dd528be905d45cb970c59
Author: Alexandre Oliva <oliva@gnu.org>
Date:   Wed Nov 10 23:13:47 2021 -0300

    gimple fntype call override

Diff:
---
 gcc/cgraph.c              | 55 +++++++++++++++++++++++++++++++++++++++++++--
 gcc/cgraphbuild.c         |  3 ++-
 gcc/cif-code.def          |  4 ++++
 gcc/doc/gimple.texi       | 22 ++++++++++++++++++
 gcc/gimple-pretty-print.c |  8 +++++++
 gcc/gimple.h              | 57 ++++++++++++++++++++++++++++++++++++++++++++++-
 gcc/ipa-strub.cc          | 32 ++++----------------------
 7 files changed, 149 insertions(+), 32 deletions(-)

diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index 466b66d5ba5..d23d851fb05 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -950,7 +950,21 @@ cgraph_node::create_edge (cgraph_node *callee,
 					   false, cloning_p);
 
   if (!cloning_p)
-    initialize_inline_failed (edge);
+    {
+      initialize_inline_failed (edge);
+
+      /* A typecast call suggests something unusual going on, we'd better not
+	 mess with the callee as if we hadn't short-circuited the address
+	 taking, and inlining it is risky as the typecast may take advantage of
+	 knowledge about calling conventions.  */
+      if (call_stmt && gimple_call_fntype_override_p (call_stmt))
+	{
+	  if (callee)
+	    callee->mark_address_taken ();
+	  edge->call_stmt_cannot_inline_p = true;
+	  edge->inline_failed = CIF_TYPECAST_CALL;
+	}
+    }
 
   edge->next_caller = callee->callers;
   if (callee->callers)
@@ -992,7 +1006,19 @@ cgraph_node::create_indirect_edge (gcall *call_stmt, int ecf_flags,
   tree target;
 
   if (!cloning_p)
-    initialize_inline_failed (edge);
+    {
+      initialize_inline_failed (edge);
+
+      /* A typecast call suggests something unusual going on, we'd better not
+	 mess with the callee as if we hadn't short-circuited the address
+	 taking, and inlining it is risky as the typecast may take advantage of
+	 knowledge about calling conventions.  */
+      if (call_stmt && gimple_call_fntype_override_p (call_stmt))
+	{
+	  edge->call_stmt_cannot_inline_p = true;
+	  edge->inline_failed = CIF_TYPECAST_CALL;
+	}
+    }
 
   edge->indirect_info = cgraph_allocate_init_indirect_info ();
   edge->indirect_info->ecf_flags = ecf_flags;
@@ -1360,6 +1386,19 @@ cgraph_edge::make_direct (cgraph_edge *edge, cgraph_node *callee)
 
   /* We need to re-determine the inlining status of the edge.  */
   initialize_inline_failed (edge);
+
+  /* A typecast call suggests something unusual going on, we'd better not mess
+     with the callee as if we hadn't short-circuited the address taking, and
+     inlining it is risky as the typecast may take advantage of knowledge about
+     calling conventions.  */
+  if (edge->call_stmt && gimple_call_fntype_override_p (edge->call_stmt))
+    {
+      if (callee)
+	callee->mark_address_taken ();
+      edge->call_stmt_cannot_inline_p = true;
+      edge->inline_failed = CIF_TYPECAST_CALL;
+    }
+
   return edge;
 }
 
@@ -1376,6 +1415,18 @@ cgraph_edge::redirect_callee (cgraph_node *n)
   /* Insert to callers list of the new callee.  */
   set_callee (n);
 
+  /* A typecast call suggests something unusual going on, we'd better not mess
+     with the callee as if we hadn't short-circuited the address taking, and
+     inlining it is risky as the typecast may take advantage of knowledge about
+     calling conventions.  */
+  if (call_stmt && gimple_call_fntype_override_p (call_stmt))
+    {
+      if (n)
+	n->mark_address_taken ();
+      call_stmt_cannot_inline_p = true;
+      inline_failed = CIF_TYPECAST_CALL;
+    }
+
   if (!inline_failed)
     return;
   if (!loc && n->comdat_local_p ())
diff --git a/gcc/cgraphbuild.c b/gcc/cgraphbuild.c
index e7acfc2dbfb..0dd7b5d363b 100644
--- a/gcc/cgraphbuild.c
+++ b/gcc/cgraphbuild.c
@@ -319,7 +319,8 @@ pass_build_cgraph_edges::execute (function *fun)
 	    {
 	      decl = gimple_call_fndecl (call_stmt);
 	      if (decl)
-		node->create_edge (cgraph_node::get_create (decl), call_stmt, bb->count);
+		node->create_edge (cgraph_node::get_create (decl), call_stmt,
+				   bb->count);
 	      else if (gimple_call_internal_p (call_stmt))
 		;
 	      else
diff --git a/gcc/cif-code.def b/gcc/cif-code.def
index 39b89da155f..6cbf34d6f1c 100644
--- a/gcc/cif-code.def
+++ b/gcc/cif-code.def
@@ -142,3 +142,7 @@ DEFCIFCODE(EXTERN_LIVE_ONLY_STATIC, CIF_FINAL_ERROR,
 /* We proved that the call is unreachable.  */
 DEFCIFCODE(UNREACHABLE, CIF_FINAL_ERROR,
 	   N_("unreachable"))
+
+/* It's not usually safe to inline when the function is typecast.  */
+DEFCIFCODE(TYPECAST_CALL, CIF_FINAL_ERROR,
+	   N_("function is called with a different type"))
diff --git a/gcc/doc/gimple.texi b/gcc/doc/gimple.texi
index 5d89dbcc68d..7ec4367f909 100644
--- a/gcc/doc/gimple.texi
+++ b/gcc/doc/gimple.texi
@@ -1371,6 +1371,28 @@ Set the called function to @code{FNDECL}.
 Return the type returned by call statement @code{G}.
 @end deftypefn
 
+@deftypefn {GIMPLE function} tree gimple_call_fntype (gcall *g)
+Return the type of the function called by @code{GIMPLE_CALL} @code{G},
+unless it calls an internal function.  The type is taken from the called
+function, if the function is known, or from the callee address, unless a
+function type overrider has been recorded.
+@end deftypefn
+
+@deftypefn {GIMPLE function} tree gimple_call_set_fntype (gcall *g, tree fntype)
+Sets the type of the function called by @code{GIMPLE_CALL} @code{G} to
+@code{fntype}.  It must not be an internal function call.  If it matches
+the type of the called function, when the function is known, or the type
+designated by the callee address, @code{fntype} is not recorded, so that
+it varies along with any changes to the callee expression or its type.
+If there is a mismatch, however, the overriding type is recorded, and
+used for the call even if the callee changes.
+@end deftypefn
+
+@deftypefn {GIMPLE function} bool gimple_call_fntype_override_p (gcall *g)
+Return true if @code{GIMPLE_CALL} @code{G} has had a function type
+overrider recorded.
+@end deftypefn
+
 @deftypefn {GIMPLE function} tree gimple_call_chain (gimple g)
 Return the static chain for call statement @code{G}.
 @end deftypefn
diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c
index 1cd1597359e..23d29560aad 100644
--- a/gcc/gimple-pretty-print.c
+++ b/gcc/gimple-pretty-print.c
@@ -940,6 +940,14 @@ dump_gimple_call (pretty_printer *buffer, const gcall *gs, int spc,
 	  pp_dot (buffer);
 	  pp_string (buffer, internal_fn_name (gimple_call_internal_fn (gs)));
 	}
+      else if (gimple_call_fntype_override_p (gs))
+	{
+	  pp_string (buffer, "(*(");
+	  dump_generic_node (buffer, gimple_call_fntype (gs), spc, flags, false);
+	  pp_string (buffer, ")&");
+	  print_call_name (buffer, fn, flags);
+	  pp_character (buffer, ')');
+	}
       else
 	print_call_name (buffer, fn, flags);
       pp_string (buffer, " (");
diff --git a/gcc/gimple.h b/gcc/gimple.h
index 3cde3cde7fe..5aa1248443b 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -3108,6 +3108,31 @@ gimple_call_ctrl_altering_p (const gimple *gs)
   return gimple_call_ctrl_altering_p (gc);
 }
 
+static inline tree gimple_call_fn (const gcall *gs);
+static inline tree gimple_call_fndecl (const gcall *gs);
+
+/* Return true if a fntype distinct from that of the called function was
+   recorded for the call.  */
+
+static inline bool
+gimple_call_fntype_override_p (const gcall *gs)
+{
+  if (gimple_call_internal_p (gs))
+    return false;
+#if 1 /* ??? */
+  tree fn_type = TREE_TYPE (TREE_TYPE (gimple_call_fn (gs)));
+  tree decl = gimple_call_fndecl (gs);
+  if (decl)
+    {
+      tree fntype = TREE_TYPE (decl);
+      if (!useless_type_conversion_p (fn_type, fntype))
+	return true;
+    }
+  return !useless_type_conversion_p (gs->u.fntype, fn_type);
+#else
+  return gs->u.fntype != NULL_TREE;
+#endif
+}
 
 /* Return the function type of the function called by GS.  */
 
@@ -3116,7 +3141,16 @@ gimple_call_fntype (const gcall *gs)
 {
   if (gimple_call_internal_p (gs))
     return NULL_TREE;
+#if 1 /* ??? */
   return gs->u.fntype;
+#else  
+  if (gs->u.fntype)
+    return gs->u.fntype;
+  tree decl = gimple_call_fndecl (gs);
+  if (decl)
+    return TREE_TYPE (decl);
+  return TREE_TYPE (TREE_TYPE (gimple_call_fn (gs)));
+#endif
 }
 
 static inline tree
@@ -3132,10 +3166,31 @@ static inline void
 gimple_call_set_fntype (gcall *call_stmt, tree fntype)
 {
   gcc_gimple_checking_assert (!gimple_call_internal_p (call_stmt));
+#if 1 /* ??? */
   call_stmt->u.fntype = fntype;
+#else
+  /* Tentatively set it to NULL so that gimple_call_fntype
+     computes the type we would get by default.  */
+  call_stmt->u.fntype = NULL;
+  tree default_type = gimple_call_fntype (call_stmt);
+
+  /* Select the types to compare.  Use canonical types, but fallback to
+     identity if TYPE_CANONICAL is not (yet?) set.  Function types usually have
+     canonical set, but atribute-annotated ones may not be.  */
+  tree canon_fntype = TYPE_CANONICAL (fntype);
+  tree canon_default = TYPE_CANONICAL (default_type);
+
+  if (!canon_fntype)
+    canon_fntype = fntype;
+  if (!canon_default)
+    canon_default = default_type;
+
+  /* If we've got a different type, it's a conversion, recall it.  */
+  if (canon_fntype != canon_default)
+    call_stmt->u.fntype = fntype;
+#endif
 }
 
-
 /* Return the tree node representing the function called by call
    statement GS.  */
 
diff --git a/gcc/ipa-strub.cc b/gcc/ipa-strub.cc
index 6765b835606..4c1efe73f7f 100644
--- a/gcc/ipa-strub.cc
+++ b/gcc/ipa-strub.cc
@@ -1317,30 +1317,6 @@ strub_comptypes (tree t1, tree t2)
   return 2;
 }
 
-/* Return true if CALL uses a function type different from that of the
-   callee.  ??? This cannot tell when a function has a non-explicit
-   strub mode, and it's converted to a type that does not have a strub
-   mode.  This should never happen, since such conversions necessarily
-   involve address-taking, which makes transformations that would add
-   type-changing modes non-viable.  */
-
-static bool
-call_typecast_p (gcall *call)
-{
-  tree fntype = gimple_call_fntype (call);
-  tree fndecl = gimple_call_fndecl (call);
-  tree fn_type = TREE_TYPE (fndecl
-			    ? fndecl
-			    : TREE_TYPE (gimple_call_fn (call)));
-
-  if (!fntype)
-    return false;
-
-  gcc_checking_assert (TYPE_CANONICAL (fntype));
-
-  return TYPE_CANONICAL (fntype) != TYPE_CANONICAL (fn_type);
-}
-
 /* 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.  */
@@ -1351,7 +1327,7 @@ effective_strub_mode_for_call (gcall *call, tree *typep)
   tree type;
   enum strub_mode mode;
 
-  if (call_typecast_p (call))
+  if (gimple_call_fntype_override_p (call))
     {
       type = gimple_call_fntype (call);
       mode = get_strub_mode_from_type (type);
@@ -1392,11 +1368,11 @@ distinctify_node_type (cgraph_node *node)
       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;
-      if (call_typecast_p (e->call_stmt))
-	continue;
       gimple_call_set_fntype (e->call_stmt, new_type);
     }
 
@@ -1478,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 (!call_typecast_p (e->call_stmt))
+	    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);


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

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

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-11-16  3:49 [gcc(refs/users/aoliva/heads/testme)] gimple fntype call override 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).