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).