[PR 70929] IPA call type compatibility fix/workaround
Richard Biener
rguenther@suse.de
Thu Oct 10 13:28:00 GMT 2019
Now also to the list...
On Thu, 10 Oct 2019, Richard Biener wrote:
> On Thu, 10 Oct 2019, Martin Jambor wrote:
>
> > Hi,
> >
> > On Wed, Oct 09 2019, Richard Biener wrote:
> > >>
> >
> > ...
> >
> > >> + /* If we only have the fntype extracted from the call statement, check it
> > >> + against the type of declarations while being pessimistic about
> > >> + promotions. */
> > >> + tree p;
> > >> +
> > >> + if (fndecl)
> > >> + p = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
> > >> + else
> > >> + p = TYPE_ARG_TYPES (gimple_call_fntype (stmt));
> > >
> > > This else case is bougs - you are then comparing the call arguments
> > > against the call arguments... Oh, I see it was there before :/
> >
> > Right, and one hand I noticed id did not make much sense, on the other
> > there were few cases where it was necessary to make the new predicate as
> > permissive as the old one (not that any of those that I saw looked
> > interesting).
> >
> > >
> > > So it is that the FEs are expected to promote function arguments
> > > according to the originally called function and that "ABI" is
> > > recorded in gimple_call_fntype. That means that we can either
> > > look at the actual arguments or at TYPE_ARG_TYPES of
> > > gimple_call_fntype. But the fndecl ABI we want to verify
> > > against is either its DECL_ARGUMENTS or TYPE_ARG_TYPEs of its type.
> > >
> > > Verifying gimple_call_arg () against gimple_call_fntype ()
> > > is pointless. What should have been used here is
> > >
> > > else
> > > p = TYPE_ARG_TYPES (TREE_TYPE (gimple_call_fn (stmt)));
> > >
> > > so, gimple_call_fn is the function called (if no fndecl then
> > > this is a function pointer), thus look at the pointed-to type
> > > and then its arguments.
> >
> > OK, this is a very nice idea, I have made the change in the patch.
> >
> > >
> > > Maybe you can test/fix that as independent commit.
> > >
> > > Your second case
> > >
> > >> + if (fndecl
> > >> + && TYPE_ARG_TYPES (TREE_TYPE (fndecl))
> > >> + && TYPE_ARG_TYPES (gimple_call_fntype (stmt)))
> > >
> > > then collapses with this and is also the better fallback IMHO
> > > (so enter this case by using TYPE_ARG_TYPES (TREE_TYPE (gimple_call_fn
> > > (...))) instead of the fndecl).
> > >
> >
> > The fndecl here is not the decl extracted from the gimple statement. It
> > is received as a function parameter and two callers extract it from a
> > call graph edge callee and one - speculation resolution - even from the
> > ipa reference associated with the speculation. So I don't think th
> > should be replaced.
>
> Hmm, OK. But then the code cares for fndecl == NULL which as far as
> I can see should not happen. And in that case it does something
> completely different, so...
>
> > So, is the following OK (bootstrapped and tested on x86_64-linux, no
> > LTO bootstrap this time because of PR 92037)?
> >
> > Martin
> >
> >
> > 2019-10-09 Martin Jambor <mjambor@suse.cz>
> >
> > PR lto/70929
> > * cgraph.c (gimple_check_call_args): Also compare types of argumen
> > types and call statement fntype types.
> >
> > testsuite/
> > * g++.dg/lto/pr70929_[01].C: New test.
> > ---
> > gcc/cgraph.c | 83 ++++++++++++++++++++++------
> > gcc/testsuite/g++.dg/lto/pr70929_0.C | 18 ++++++
> > gcc/testsuite/g++.dg/lto/pr70929_1.C | 10 ++++
> > 3 files changed, 95 insertions(+), 16 deletions(-)
> > create mode 100644 gcc/testsuite/g++.dg/lto/pr70929_0.C
> > create mode 100644 gcc/testsuite/g++.dg/lto/pr70929_1.C
> >
> > diff --git a/gcc/cgraph.c b/gcc/cgraph.c
> > index 0c3c6e7cac4..4f7bfa28f37 100644
> > --- a/gcc/cgraph.c
> > +++ b/gcc/cgraph.c
> > @@ -3636,26 +3636,19 @@ cgraph_node::get_fun () const
> > static bool
> > gimple_check_call_args (gimple *stmt, tree fndecl, bool args_count_match)
> > {
> > - tree parms, p;
> > - unsigned int i, nargs;
> > -
> > /* Calls to internal functions always match their signature. */
> > if (gimple_call_internal_p (stmt))
> > return true;
> >
> > - nargs = gimple_call_num_args (stmt);
> > + unsigned int nargs = gimple_call_num_args (stmt);
> >
> > - /* Get argument types for verification. */
> > - if (fndecl)
> > - parms = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
> > - else
> > - parms = TYPE_ARG_TYPES (gimple_call_fntype (stmt));
> > -
> > - /* Verify if the type of the argument matches that of the function
> > - declaration. If we cannot verify this or there is a mismatch,
> > - return false. */
> > + /* If we have access to the declarations of formal parameters, match against
> > + those. */
> > if (fndecl && DECL_ARGUMENTS (fndecl))
> > {
> > + unsigned int i;
> > + tree p;
> > +
> > for (i = 0, p = DECL_ARGUMENTS (fndecl);
> > i < nargs;
> > i++, p = DECL_CHAIN (p))
> > @@ -3676,17 +3669,75 @@ gimple_check_call_args (gimple *stmt, tree fndecl, bool args_count_match)
> > }
> > if (args_count_match && p)
> > return false;
> > +
> > + return true;
> > }
> > - else if (parms)
> > +
> > + /* If we don't have decls of formal parameters, see if we have both the type
> > + of the callee arguments in the fntype of the call statement and compare
> > + those. We rely on the fact that whatever promotions happened to
> > + declarations for exactly the same sequence of types of parameters also
> > + happened on the callee side. */
> > + if (fndecl
> > + && TYPE_ARG_TYPES (TREE_TYPE (fndecl))
> > + && TYPE_ARG_TYPES (gimple_call_fntype (stmt)))
> > {
>
> You might want to check the result of this against the a simple
> types_compatible_p (TREE_TYPE (fndecl), gimple_call_fntype (stmt)).
>
> > - for (i = 0, p = parms; i < nargs; i++, p = TREE_CHAIN (p))
> > + unsigned int arg_idx = 0;
> > + for (tree f = TYPE_ARG_TYPES (TREE_TYPE (fndecl)),
> > + s = TYPE_ARG_TYPES (gimple_call_fntype (stmt));
> > + f || s;
> > + f = TREE_CHAIN (f), s = TREE_CHAIN (s), arg_idx++)
> > {
> > + if (!f
> > + || !s
> > + || TREE_VALUE (f) == error_mark_node
> > + || TREE_VALUE (s) == error_mark_node)
> > + return false;
> > + if (TREE_CODE (TREE_VALUE (f)) == VOID_TYPE)
> > + {
> > + if (TREE_CODE (TREE_VALUE (s)) != VOID_TYPE
> > + || arg_idx != nargs)
> > + return false;
> > + else
> > + break;
> > + }
> > +
> > tree arg;
> > +
> > + if (arg_idx >= nargs
> > + || (arg = gimple_call_arg (stmt, arg_idx)) == error_mark_node)
> > + return false;
> > +
> > + if (TREE_CODE (TREE_VALUE (s)) == VOID_TYPE
> > + || (!types_compatible_p (TREE_VALUE (f), TREE_VALUE (s))
> > + && !fold_convertible_p (TREE_VALUE (f), arg)))
> > + return false;
> > + }
> > +
> > + if (args_count_match && arg_idx != nargs)
> > + return false;
> > +
> > + return true;
> > + }
> > +
> > + /* If we only have the fntype extracted from the call statement, check it
> > + against the type of declarations while being pessimistic about
> > + promotions. */
> > + tree p;
>
> The code below doeesn't make any sense to me for the !fndecl case.
>
> I'm not sure if we really need to handle the apples-to-oranges
> case (comparing unpromoted types against promoted decls).
>
> Btw, I questioned whether we need all this code anyways - we mostly
> have it for QOI (not break things if the ABI makes things magically
> "work").
>
> > + if (fndecl)
> > + p = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
> > + else
> > + p = TYPE_ARG_TYPES (TREE_TYPE (gimple_call_fn (stmt)));
> > + if (p)
> > + {
> > + for (unsigned i = 0; i < nargs; i++, p = TREE_CHAIN (p))
> > + {
> > /* If this is a varargs function defer inlining decision
> > to callee. */
> > if (!p)
> > break;
> > - arg = gimple_call_arg (stmt, i);
> > + tree arg = gimple_call_arg (stmt, i);
> > if (TREE_VALUE (p) == error_mark_node
> > || arg == error_mark_node
> > || TREE_CODE (TREE_VALUE (p)) == VOID_TYPE
> > diff --git a/gcc/testsuite/g++.dg/lto/pr70929_0.C b/gcc/testsuite/g++.dg/lto/pr70929_0.C
> > new file mode 100644
> > index 00000000000..c96fb1c743a
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/lto/pr70929_0.C
> > @@ -0,0 +1,18 @@
> > +// { dg-lto-do run }
> > +// { dg-lto-options { "-O3 -flto" } }
> > +
> > +struct s
> > +{
> > + int a;
> > + s() {a=1;}
> > + ~s() {}
> > +};
> > +int t(struct s s);
> > +int main()
> > +{
> > + s s;
> > + int v=t(s);
> > + if (!__builtin_constant_p (v))
> > + __builtin_abort ();
> > + return 0;
> > +}
> > diff --git a/gcc/testsuite/g++.dg/lto/pr70929_1.C b/gcc/testsuite/g++.dg/lto/pr70929_1.C
> > new file mode 100644
> > index 00000000000..b33aa8f35f0
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/lto/pr70929_1.C
> > @@ -0,0 +1,10 @@
> > +struct s
> > +{
> > + int a;
> > + s() {a=1;}
> > + ~s() {}
> > +};
> > +int t(struct s s)
> > +{
> > + return s.a;
> > +}
> >
>
>
More information about the Gcc-patches
mailing list