Introduce EAF_NOREAD and cleanup EAF_UNUSED + ipa-modref

this patch add EAF_NOREAD (as disucssed on IRC already) and fixes meaning
of EAF_UNUSED to be really unused and not "does not escape, is not clobbered,
read or returned" since we have separate flags for each of the properties
now.

Since number of flags has grown I refactored the code a bit to avoid
repeated uses of complex flag combinations and also simplified the logic of
merging.

Merging is bit tricky since we have flags that implies other flags
(like NOESCAPE implies NODIRECTESCAPE) but code that sets only NOESCAPE.
Perhaps it would make sense to update fnspecs to always set flag along with
all the implications, but for now I am handlingit in merge.

I made only trivial update to tree-ssa-structalias to handle EAF_NORETURN in
normal function handling, but not in pure functions.  The problem is that the
way constraints are generated for pure functions makes this difficult.
I think logical step is to track whether function reads/stores global memory
and rewrite the constraint generation so we can handle normal, pure and const
in unified manner.

Bootstrapped/regtested x86_64-linux, plan to commit it after furhter testing.

The patch improves alias oracle stats for cc1plus somewhat.

From:

Alias oracle query stats:
  refs_may_alias_p: 72380497 disambiguations, 82649832 queries
  ref_maybe_used_by_call_p: 495184 disambiguations, 73366950 queries
  call_may_clobber_ref_p: 259312 disambiguations, 263253 queries
  nonoverlapping_component_refs_p: 0 disambiguations, 38006 queries
  nonoverlapping_refs_since_match_p: 21157 disambiguations, 65698 must overlaps, 87756 queries
  aliasing_component_refs_p: 63141 disambiguations, 2164695 queries
  TBAA oracle: 25975753 disambiguations 61449632 queries
               12138220 are in alias set 0
               11316663 queries asked about the same object
               144 queries asked about the same alias set
               0 access volatile
               10472885 are dependent in the DAG
               1545967 are aritificially in conflict with void *

Modref stats:
  modref use: 23857 disambiguations, 754515 queries
  modref clobber: 1392162 disambiguations, 17753512 queries
  3450241 tbaa queries (0.194341 per modref query)
  534816 base compares (0.030125 per modref query)

PTA query stats:
  pt_solution_includes: 12394915 disambiguations, 20235925 queries
  pt_solutions_intersect: 1365299 disambiguations, 14638068 queries

To:

Alias oracle query stats:
  refs_may_alias_p: 72629640 disambiguations, 82903333 queries
  ref_maybe_used_by_call_p: 502474 disambiguations, 73612186 queries
  call_may_clobber_ref_p: 261806 disambiguations, 265659 queries
  nonoverlapping_component_refs_p: 0 disambiguations, 38007 queries
  nonoverlapping_refs_since_match_p: 21139 disambiguations, 65772 must overlaps, 87816 queries
  aliasing_component_refs_p: 63144 disambiguations, 2164330 queries
  TBAA oracle: 26059018 disambiguations 61571714 queries
               12158033 are in alias set 0
               11326115 queries asked about the same object
               144 queries asked about the same alias set
               0 access volatile
               10484493 are dependent in the DAG
               1543911 are aritificially in conflict with void *

Modref stats:
  modref use: 24008 disambiguations, 712712 queries
  modref clobber: 1395917 disambiguations, 17163694 queries
  3465657 tbaa queries (0.201918 per modref query)
  537591 base compares (0.031321 per modref query)

PTA query stats:
  pt_solution_includes: 12468934 disambiguations, 20295402 queries
  pt_solutions_intersect: 1391917 disambiguations, 14665265 queries

I think it is mostly due to better heandling of EAF_NODIRECTESCAPE.

Honza

gcc/ChangeLog:

2021-08-12  Jan Hubicka  <hubicka@ucw.cz>

	* ipa-modref.c (dump_eaf_flags): Dump EAF_NOREAD.
	(implicit_const_eaf_flags, implicit_pure_eaf_flags,
	 ignore_stores_eaf_flags): New constants.
	(remove_useless_eaf_flags): New function.
	(eaf_flags_useful_p): Use it.
	(deref_flags): Add EAF_NOT_RETURNED if flag is unused;
	handle EAF_NOREAD.
	(modref_lattice::init): Add EAF_NOREAD.
	(modref_lattice::add_escape_point): Do not reacord escape point if
	result is unused.
	(modref_lattice::merge): EAF_NOESCAPE implies EAF_NODIRECTESCAPE;
	use remove_useless_eaf_flags.
	(modref_lattice::merge_deref): Use ignore_stores_eaf_flags.
	(modref_lattice::merge_direct_load): Add EAF_NOREAD
	(analyze_ssa_name_flags): Fix handling EAF_NOT_RETURNED
	(analyze_parms): Use remove_useless_eaf_flags.
	(ipa_merge_modref_summary_after_inlining): Use ignore_stores_eaf_flags.
	(modref_merge_call_site_flags): Add caller and ecf_flags parameter;
	use remove_useless_eaf_flags.
	(modref_propagate_flags_in_scc): Update.
	* ipa-modref.h: Turn eaf_flags_t back to char.
	* tree-core.h (EAF_NOT_RETURNED): Fix.
	(EAF_NOREAD): New constant
	* tree-ssa-alias.c: (ref_maybe_used_by_call_p_1): Check for
	EAF_NOREAD.
	* tree-ssa-structalias.c (handle_rhs_call): Handle new flags.
	(handle_pure_call): Likewise.

gcc/testsuite/ChangeLog:

2021-08-12  Jan Hubicka  <hubicka@ucw.cz>

	* gcc.dg/tree-ssa/modref-6.c: Update.
This commit is contained in:
Jan Hubicka 2021-08-13 10:04:52 +02:00
parent e37ddb91a8
commit 4341b1b165
6 changed files with 131 additions and 63 deletions

View File

@ -158,6 +158,8 @@ dump_eaf_flags (FILE *out, int flags, bool newline = true)
fprintf (out, " unused");
if (flags & EAF_NOT_RETURNED)
fprintf (out, " not_returned");
if (flags & EAF_NOREAD)
fprintf (out, " noread");
if (newline)
fprintf (out, "\n");
}
@ -278,27 +280,46 @@ modref_summary::~modref_summary ()
ggc_delete (stores);
}
/* All flags that are implied by the ECF_CONST functions. */
const int implicit_const_eaf_flags = EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE
| EAF_NODIRECTESCAPE | EAF_NOREAD;
/* All flags that are implied by the ECF_PURE function. */
const int implicit_pure_eaf_flags = EAF_NOCLOBBER | EAF_NOESCAPE
| EAF_NODIRECTESCAPE;
/* All flags implied when we know we can ignore stores (i.e. when handling
call to noreturn). */
const int ignore_stores_eaf_flags = EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE
| EAF_NODIRECTESCAPE;
/* Remove all flags from EAF_FLAGS that are implied by ECF_FLAGS and not
useful to track. If returns_void is true moreover clear
EAF_NOT_RETURNED. */
static int
remove_useless_eaf_flags (int eaf_flags, int ecf_flags, bool returns_void)
{
if (ecf_flags & ECF_NOVOPS)
return 0;
if (ecf_flags & ECF_CONST)
eaf_flags &= ~implicit_const_eaf_flags;
else if (ecf_flags & ECF_PURE)
eaf_flags &= ~implicit_pure_eaf_flags;
else if ((ecf_flags & ECF_NORETURN) || returns_void)
eaf_flags &= ~EAF_NOT_RETURNED;
/* Only NOCLOBBER or DIRECT flags alone are not useful (see comments
in tree-ssa-alias.c). Give up earlier. */
if ((eaf_flags & ~(EAF_DIRECT | EAF_NOCLOBBER)) == 0)
return 0;
return eaf_flags;
}
/* Return true if FLAGS holds some useful information. */
static bool
eaf_flags_useful_p (vec <eaf_flags_t> &flags, int ecf_flags)
{
for (unsigned i = 0; i < flags.length (); i++)
if (ecf_flags & ECF_CONST)
{
if (flags[i] & (EAF_UNUSED | EAF_NOT_RETURNED))
return true;
}
else if (ecf_flags & ECF_PURE)
{
if (flags[i] & (EAF_UNUSED | EAF_DIRECT | EAF_NOT_RETURNED))
return true;
}
else
{
if (flags[i])
return true;
}
if (remove_useless_eaf_flags (flags[i], ecf_flags, false))
return true;
return false;
}
@ -1320,17 +1341,35 @@ static int
deref_flags (int flags, bool ignore_stores)
{
int ret = EAF_NODIRECTESCAPE;
/* If argument is unused just account for
the read involved in dereference. */
if (flags & EAF_UNUSED)
ret |= EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE;
ret |= EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE | EAF_NOT_RETURNED;
else
{
if ((flags & EAF_NOCLOBBER) || ignore_stores)
ret |= EAF_NOCLOBBER;
if ((flags & EAF_NOESCAPE) || ignore_stores)
ret |= EAF_NOESCAPE;
/* If the value dereferenced is not used for another load or store
we can still consider ARG as used only directly.
Consider
int
test (int *a)
{
return *a!=0;
}
*/
if ((flags & (EAF_NOREAD | EAF_NOT_RETURNED | EAF_NOESCAPE | EAF_DIRECT))
== (EAF_NOREAD | EAF_NOT_RETURNED | EAF_NOESCAPE | EAF_DIRECT)
&& ((flags & EAF_NOCLOBBER) || ignore_stores))
ret |= EAF_DIRECT;
if (flags & EAF_NOT_RETURNED)
ret |= EAF_NOT_RETURNED;
}
if (flags & EAF_NOT_RETURNED)
ret |= EAF_NOT_RETURNED;
return ret;
}
@ -1355,7 +1394,7 @@ class modref_lattice
{
public:
/* EAF flags of the SSA name. */
int flags;
eaf_flags_t flags;
/* DFS bookkkeeping: we don't do real dataflow yet. */
bool known;
bool open;
@ -1379,8 +1418,12 @@ public:
void
modref_lattice::init ()
{
flags = EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE | EAF_UNUSED
| EAF_NODIRECTESCAPE | EAF_NOT_RETURNED;
/* All flags we track. */
int f = EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE | EAF_UNUSED
| EAF_NODIRECTESCAPE | EAF_NOT_RETURNED | EAF_NOREAD;
flags = f;
/* Check that eaf_flags_t is wide enough to hold all flags. */
gcc_checking_assert (f == flags);
open = true;
known = false;
}
@ -1424,8 +1467,8 @@ modref_lattice::add_escape_point (gcall *call, int arg, int min_flags,
unsigned int i;
/* If we already determined flags to be bad enough,
* we do not need to record. */
if ((flags & min_flags) == flags)
we do not need to record. */
if ((flags & min_flags) == flags || (min_flags & EAF_UNUSED))
return false;
FOR_EACH_VEC_ELT (escape_points, i, ep)
@ -1455,13 +1498,18 @@ modref_lattice::merge (int f)
{
if (f & EAF_UNUSED)
return false;
/* Noescape implies that value also does not escape directly.
Fnspec machinery does set both so compensate for this. */
if (f & EAF_NOESCAPE)
f |= EAF_NODIRECTESCAPE;
if ((flags & f) != flags)
{
flags &= f;
/* Only NOCLOBBER or DIRECT flags alone are not useful (see comments
in tree-ssa-alias.c). Give up earlier. */
if ((flags & ~(EAF_DIRECT | EAF_NOCLOBBER)) == 0)
flags = 0;
/* Prune obvoiusly useless flags;
We do not have ECF_FLAGS handy which is not big problem since
we will do final flags cleanup before producing summary.
Merging should be fast so it can work well with dataflow. */
flags = remove_useless_eaf_flags (flags, 0, false);
if (!flags)
escape_points.release ();
return true;
@ -1509,7 +1557,7 @@ modref_lattice::merge_deref (const modref_lattice &with, bool ignore_stores)
if (with.escape_points[i].direct)
min_flags = deref_flags (min_flags, ignore_stores);
else if (ignore_stores)
min_flags |= EAF_NOCLOBBER | EAF_NOESCAPE | EAF_NODIRECTESCAPE;
min_flags |= ignore_stores_eaf_flags;
changed |= add_escape_point (with.escape_points[i].call,
with.escape_points[i].arg,
min_flags,
@ -1523,7 +1571,7 @@ modref_lattice::merge_deref (const modref_lattice &with, bool ignore_stores)
bool
modref_lattice::merge_direct_load ()
{
return merge (~EAF_UNUSED);
return merge (~(EAF_UNUSED | EAF_NOREAD));
}
/* Merge in flags for direct store. */
@ -1632,6 +1680,9 @@ analyze_ssa_name_flags (tree name, vec<modref_lattice> &lattice, int depth,
fprintf (dump_file, "%*s Analyzing stmt: ", depth * 4, "");
print_gimple_stmt (dump_file, use_stmt, 0);
}
/* If we see a direct non-debug use, clear unused bit.
All dereferneces should be accounted below using deref_flags. */
lattice[index].merge (~EAF_UNUSED);
/* Gimple return may load the return value.
Returning name counts as an use by tree-ssa-structalias.c */
@ -1642,7 +1693,7 @@ analyze_ssa_name_flags (tree name, vec<modref_lattice> &lattice, int depth,
else if (memory_access_to (gimple_return_retval (ret), name))
{
lattice[index].merge_direct_load ();
lattice[index].merge (~EAF_NOT_RETURNED);
lattice[index].merge (~(EAF_UNUSED | EAF_NOT_RETURNED));
}
}
/* Account for LHS store, arg loads and flags from callee function. */
@ -1697,8 +1748,7 @@ analyze_ssa_name_flags (tree name, vec<modref_lattice> &lattice, int depth,
int call_flags = gimple_call_arg_flags (call, i)
| EAF_NOT_RETURNED;
if (ignore_stores)
call_flags |= EAF_NOCLOBBER | EAF_NOESCAPE
| EAF_NODIRECTESCAPE;
call_flags |= ignore_stores_eaf_flags;
if (!record_ipa)
lattice[index].merge (call_flags);
@ -1890,14 +1940,12 @@ analyze_parms (modref_summary *summary, modref_summary_lto *summary_lto,
analyze_ssa_name_flags (name, lattice, 0, ipa);
int flags = lattice[SSA_NAME_VERSION (name)].flags;
/* For pure functions we have implicit NOCLOBBER
and NOESCAPE. */
if (ecf_flags & ECF_PURE)
flags &= (EAF_UNUSED | EAF_DIRECT | EAF_NOT_RETURNED);
/* Only useful flags for const function are EAF_NOT_RETURNED and
EAF_UNUSED. */
if (ecf_flags & ECF_CONST)
flags &= (EAF_UNUSED | EAF_NOT_RETURNED);
/* Eliminate useless flags so we do not end up storing unnecessary
summaries. */
flags = remove_useless_eaf_flags
(flags, ecf_flags,
VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
if (flags)
{
@ -3176,7 +3224,7 @@ ipa_merge_modref_summary_after_inlining (cgraph_edge *edge)
if (!ee->direct)
flags = deref_flags (flags, ignore_stores);
else if (ignore_stores)
flags |= EAF_NOCLOBBER | EAF_NOESCAPE | EAF_NODIRECTESCAPE;
flags |= ignore_stores_eaf_flags;
flags |= ee->min_flags;
to_info->arg_flags[ee->parm_index] &= flags;
if (to_info->arg_flags[ee->parm_index])
@ -3190,7 +3238,7 @@ ipa_merge_modref_summary_after_inlining (cgraph_edge *edge)
if (!ee->direct)
flags = deref_flags (flags, ignore_stores);
else if (ignore_stores)
flags |= EAF_NOCLOBBER | EAF_NOESCAPE | EAF_NODIRECTESCAPE;
flags |= ignore_stores_eaf_flags;
flags |= ee->min_flags;
to_info_lto->arg_flags[ee->parm_index] &= flags;
if (to_info_lto->arg_flags[ee->parm_index])
@ -3673,11 +3721,13 @@ modref_merge_call_site_flags (escape_summary *sum,
modref_summary_lto *cur_summary_lto,
modref_summary *summary,
modref_summary_lto *summary_lto,
bool ignore_stores)
tree caller,
int ecf_flags)
{
escape_entry *ee;
unsigned int i;
bool changed = false;
bool ignore_stores = ignore_stores_p (caller, ecf_flags);
/* If we have no useful info to propagate. */
if ((!cur_summary || !cur_summary->arg_flags.length ())
@ -3701,21 +3751,27 @@ modref_merge_call_site_flags (escape_summary *sum,
}
else if (ignore_stores)
{
flags |= EAF_NOESCAPE | EAF_NOCLOBBER | EAF_NODIRECTESCAPE;
flags_lto |= EAF_NOESCAPE | EAF_NOCLOBBER | EAF_NODIRECTESCAPE;
flags |= ignore_stores_eaf_flags;
flags_lto |= ignore_stores_eaf_flags;
}
/* Returning the value is already accounted to at local propagation. */
flags |= ee->min_flags | EAF_NOT_RETURNED;
flags_lto |= ee->min_flags | EAF_NOT_RETURNED;
/* Noescape implies that value also does not escape directly.
Fnspec machinery does set both so compensate for this. */
if (flags & EAF_NOESCAPE)
flags |= EAF_NODIRECTESCAPE;
if (flags_lto & EAF_NOESCAPE)
flags_lto |= EAF_NODIRECTESCAPE;
if (!(flags & EAF_UNUSED)
&& cur_summary && ee->parm_index < cur_summary->arg_flags.length ())
{
int f = cur_summary->arg_flags[ee->parm_index];
if ((f & flags) != f)
{
f = f & flags;
if ((f & ~(EAF_DIRECT | EAF_NOCLOBBER)) == 0)
f = 0;
f = remove_useless_eaf_flags
(f & flags, ecf_flags,
VOID_TYPE_P (TREE_TYPE (TREE_TYPE (caller))));
cur_summary->arg_flags[ee->parm_index] = f;
changed = true;
}
@ -3727,9 +3783,9 @@ modref_merge_call_site_flags (escape_summary *sum,
int f = cur_summary_lto->arg_flags[ee->parm_index];
if ((f & flags_lto) != f)
{
f = f & flags;
if ((f & ~(EAF_DIRECT | EAF_NOCLOBBER)) == 0)
f = 0;
f = remove_useless_eaf_flags
(f & flags_lto, ecf_flags,
VOID_TYPE_P (TREE_TYPE (TREE_TYPE (caller))));
cur_summary_lto->arg_flags[ee->parm_index] = f;
changed = true;
}
@ -3780,8 +3836,8 @@ modref_propagate_flags_in_scc (cgraph_node *component_node)
changed |= modref_merge_call_site_flags
(sum, cur_summary, cur_summary_lto,
NULL, NULL, ignore_stores_p (node->decl,
e->indirect_info->ecf_flags));
NULL, NULL,
node->decl, e->indirect_info->ecf_flags);
}
if (!cur_summary && !cur_summary_lto)
@ -3790,12 +3846,13 @@ modref_propagate_flags_in_scc (cgraph_node *component_node)
for (cgraph_edge *callee_edge = cur->callees; callee_edge;
callee_edge = callee_edge->next_callee)
{
int flags = flags_from_decl_or_type (callee_edge->callee->decl);
int ecf_flags = flags_from_decl_or_type
(callee_edge->callee->decl);
modref_summary *callee_summary = NULL;
modref_summary_lto *callee_summary_lto = NULL;
struct cgraph_node *callee;
if (flags & (ECF_CONST | ECF_NOVOPS)
if (ecf_flags & (ECF_CONST | ECF_NOVOPS)
|| !callee_edge->inline_failed)
continue;
/* Get the callee and its summary. */
@ -3832,7 +3889,7 @@ modref_propagate_flags_in_scc (cgraph_node *component_node)
changed |= modref_merge_call_site_flags
(sum, cur_summary, cur_summary_lto,
callee_summary, callee_summary_lto,
ignore_stores_p (node->decl, flags));
node->decl, ecf_flags);
if (dump_file && changed)
{
if (cur_summary)

View File

@ -21,7 +21,7 @@ along with GCC; see the file COPYING3. If not see
#define IPA_MODREF_H
typedef modref_tree <alias_set_type> modref_records;
typedef unsigned short eaf_flags_t;
typedef unsigned char eaf_flags_t;
/* Single function summary. */

View File

@ -32,6 +32,6 @@ int test2()
/* Flags for pure call. */
/* { dg-final { scan-tree-dump "parm 0 flags: direct not_returned" "modref1" } } */
/* Flags for const call. */
/* { dg-final { scan-tree-dump "parm 0 flags: unused not_returned" "modref1" } } */
/* { dg-final { scan-tree-dump "parm 0 flags: not_returned" "modref1" } } */
/* Overall we want to make "int a" non escaping. */
/* { dg-final { scan-tree-dump "return 42" "optimized" } } */

View File

@ -115,7 +115,10 @@ struct die_struct;
#define EAF_NODIRECTESCAPE (1 << 4)
/* Nonzero if the argument does not escape to return value. */
#define EAF_NOT_RETURNED (1 << 8)
#define EAF_NOT_RETURNED (1 << 5)
/* Nonzero if the argument is not read. */
#define EAF_NOREAD (1 << 6)
/* Call return flags. */
/* Mask for the argument number that is returned. Lower two bits of

View File

@ -2870,7 +2870,7 @@ process_args:
tree op = gimple_call_arg (call, i);
int flags = gimple_call_arg_flags (call, i);
if (flags & EAF_UNUSED)
if (flags & (EAF_UNUSED | EAF_NOREAD))
continue;
if (TREE_CODE (op) == WITH_SIZE_EXPR)

View File

@ -4063,8 +4063,14 @@ handle_rhs_call (gcall *stmt, vec<ce_s> *results)
tree arg = gimple_call_arg (stmt, i);
int flags = gimple_call_arg_flags (stmt, i);
/* If the argument is not used we can ignore it. */
if (flags & EAF_UNUSED)
/* If the argument is not used we can ignore it.
Similarly argument is invisile for us if it not clobbered, does not
escape, is not read and can not be returned. */
if ((flags & EAF_UNUSED)
|| ((flags & (EAF_NOCLOBBER | EAF_NOESCAPE | EAF_NOREAD
| EAF_NOT_RETURNED))
== (EAF_NOCLOBBER | EAF_NOESCAPE | EAF_NOREAD
| EAF_NOT_RETURNED)))
continue;
/* As we compute ESCAPED context-insensitive we do not gain
@ -4316,7 +4322,9 @@ handle_pure_call (gcall *stmt, vec<ce_s> *results)
int flags = gimple_call_arg_flags (stmt, i);
/* If the argument is not used we can ignore it. */
if (flags & EAF_UNUSED)
if ((flags & EAF_UNUSED)
|| (flags & (EAF_NOT_RETURNED | EAF_NOREAD))
== (EAF_NOT_RETURNED | EAF_NOREAD))
continue;
if (!uses)
{