Improve handling of return slot in ipa-pure-const and modref.

while preparing testcase for return slot tracking I noticed that both
ipa-pure-const and modref treat return slot writes as non-local which prevents
detecting functions as pure or not modifying global state.  Fixed by making
points_to_local_or_readonly_memory_p to special case return slot.  This is bit
of a side case, but presently at all uses of
points_to_local_or_readonly_memory_p we want to handle return slot this way.

I also noticed that we handle gimple copy unnecesarily pesimistically.  This
does not make difference right now since we do no not track non-scalars, but
I fixed it anyway.

Bootstrapped/regtested x86_64-linux, comitted.

gcc/ChangeLog:

	* ipa-fnsummary.c: Include tree-dfa.h.
	(points_to_local_or_readonly_memory_p): Return true on return
	slot writes.
	* ipa-modref.c (analyze_ssa_name_flags): Fix handling of copy
	statement.

gcc/testsuite/ChangeLog:

	* g++.dg/ipa/modref-1.C: New test.
This commit is contained in:
Jan Hubicka 2021-10-31 23:14:29 +01:00
parent d41092ec52
commit ca84f39399
3 changed files with 51 additions and 2 deletions

View file

@ -86,6 +86,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree-into-ssa.h"
#include "symtab-clones.h"
#include "gimple-range.h"
#include "tree-dfa.h"
/* Summaries. */
fast_function_summary <ipa_fn_summary *, va_gc> *ipa_fn_summaries;
@ -2569,7 +2570,20 @@ points_to_local_or_readonly_memory_p (tree t)
if (integer_zerop (t))
return flag_delete_null_pointer_checks;
if (TREE_CODE (t) == SSA_NAME)
return !ptr_deref_may_alias_global_p (t);
{
/* For IPA passes we can consinder accesses to return slot local
even if it is not local in the sense that memory is dead by
the end of founction.
The outer function will see a store in the call assignment
and thus this will do right thing for all uses of this
function in the current IPA passes (modref, pure/const discovery
and inlining heuristics). */
if (DECL_RESULT (current_function_decl)
&& DECL_BY_REFERENCE (DECL_RESULT (current_function_decl))
&& t == ssa_default_def (cfun, DECL_RESULT (current_function_decl)))
return true;
return !ptr_deref_may_alias_global_p (t);
}
if (TREE_CODE (t) == ADDR_EXPR)
return refs_local_or_readonly_memory_p (TREE_OPERAND (t, 0));
return false;

View file

@ -1841,7 +1841,7 @@ analyze_ssa_name_flags (tree name, vec<modref_lattice> &lattice, int depth,
We do not track memory locations, so assume that value
is used arbitrarily. */
if (memory_access_to (gimple_assign_rhs1 (assign), name))
lattice[index].merge (0);
lattice[index].merge (deref_flags (0, false));
/* Handle *name = *exp. */
else if (memory_access_to (gimple_assign_lhs (assign), name))
lattice[index].merge_direct_store ();

View file

@ -0,0 +1,35 @@
/* { dg-do link } */
/* { dg-options "-O2 -fdump-tree-local-pure-const1 -fdump-tree-modref1 -std=gnu++2a" } */
namespace {
struct B {
int b;
struct B *bptr;
B() {b=1; }
B(B &src)
{
b=src.b;
bptr=0;
}
__attribute__ ((noinline))
static struct B genB()
{
struct B b;
b.b=2;
b.bptr = 0;
return b;
}
};
}
void linker_error ();
int main()
{
struct B b1 = B::genB();
b1.b = 1;
struct B b2 = B::genB();
if (b1.b != 1 || b2.bptr == &b2)
linker_error ();
return 0;
}
/* { dg-final { scan-ipa-dump "Function found to be const: {anonymous}::B::genB" "local-pure-const1" } } */
/* { dg-final { scan-ipa-dump "Retslot flags: direct noescape nodirectescape not_returned noread" "modref1" } } */