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:
parent
d41092ec52
commit
ca84f39399
3 changed files with 51 additions and 2 deletions
|
@ -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;
|
||||
|
|
|
@ -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 ();
|
||||
|
|
35
gcc/testsuite/g++.dg/ipa/modref-1.C
Normal file
35
gcc/testsuite/g++.dg/ipa/modref-1.C
Normal 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" } } */
|
||||
|
Loading…
Add table
Reference in a new issue