New modref/ipa_modref optimization passes

2020-09-19  David Cepelik  <d@dcepelik.cz>
	    Jan Hubicka  <hubicka@ucw.cz>

	* Makefile.in: Add ipa-modref.c and ipa-modref-tree.c.
	* alias.c: (reference_alias_ptr_type_1): Export.
	* alias.h (reference_alias_ptr_type_1): Declare.
	* common.opt (fipa-modref): New.
	* gengtype.c (open_base_files): Add ipa-modref-tree.h and ipa-modref.h
	* ipa-modref-tree.c: New file.
	* ipa-modref-tree.h: New file.
	* ipa-modref.c: New file.
	* ipa-modref.h: New file.
	* lto-section-in.c (lto_section_name): Add ipa_modref.
	* lto-streamer.h (enum lto_section_type): Add LTO_section_ipa_modref.
	* opts.c (default_options_table): Enable ipa-modref at -O1+.
	* params.opt (-param=modref-max-bases, -param=modref-max-refs,
	-param=modref-max-tests): New params.
	* passes.def: Schedule pass_modref and pass_ipa_modref.
	* timevar.def (TV_IPA_MODREF): New timevar.
	(TV_TREE_MODREF): New timevar.
	* tree-pass.h (make_pass_modref): Declare.
	(make_pass_ipa_modref): Declare.
	* tree-ssa-alias.c (dump_alias_stats): Include ipa-modref-tree.h
	and ipa-modref.h
	(alias_stats): Add modref_use_may_alias, modref_use_no_alias,
	modref_clobber_may_alias, modref_clobber_no_alias, modref_tests.
	(dump_alias_stats): Dump new stats.
	(nonoverlapping_array_refs_p): Fix formating.
	(modref_may_conflict): New function.
	(ref_maybe_used_by_call_p_1): Use it.
	(call_may_clobber_ref_p_1): Use it.
	(call_may_clobber_ref_p): Update.
	(stmt_may_clobber_ref_p_1): Update.
	* tree-ssa-alias.h (call_may_clobber_ref_p_1): Update.
This commit is contained in:
Jan Hubicka 2020-09-20 07:25:16 +02:00
parent 2fe5b7d1f6
commit d119f34c95
18 changed files with 2108 additions and 16 deletions

View File

@ -1419,6 +1419,8 @@ OBJS = \
ipa-visibility.o \
ipa-inline-analysis.o \
ipa-inline-transform.o \
ipa-modref.o \
ipa-modref-tree.o \
ipa-predicate.o \
ipa-profile.o \
ipa-prop.o \
@ -2587,6 +2589,8 @@ GTFILES = $(CPPLIB_H) $(srcdir)/input.h $(srcdir)/coretypes.h \
$(srcdir)/alias.c $(srcdir)/bitmap.c $(srcdir)/cselib.c $(srcdir)/cgraph.c \
$(srcdir)/ipa-prop.c $(srcdir)/ipa-cp.c $(srcdir)/ipa-utils.h \
$(srcdir)/ipa-param-manipulation.h $(srcdir)/ipa-sra.c $(srcdir)/dbxout.c \
$(srcdir)/ipa-modref.h $(srcdir)/ipa-modref.c \
$(srcdir)/ipa-modref-tree.h \
$(srcdir)/signop.h \
$(srcdir)/dwarf2out.h \
$(srcdir)/dwarf2asm.c \

View File

@ -737,7 +737,7 @@ get_deref_alias_set (tree t)
adjusted to point to the outermost component reference that
can be used for assigning an alias set. */
static tree
tree
reference_alias_ptr_type_1 (tree *t)
{
tree inner;

View File

@ -36,6 +36,7 @@ extern int objects_must_conflict_p (tree, tree);
extern int nonoverlapping_memrefs_p (const_rtx, const_rtx, bool);
extern void dump_alias_stats_in_alias_c (FILE *s);
tree reference_alias_ptr_type (tree);
tree reference_alias_ptr_type_1 (tree *);
bool alias_ptr_types_compatible_p (tree, tree);
int compare_base_decls (tree, tree);
bool refs_same_for_tbaa_p (tree, tree);

View File

@ -1825,6 +1825,10 @@ fipa-bit-cp
Common Report Var(flag_ipa_bit_cp) Optimization
Perform interprocedural bitwise constant propagation.
fipa-modref
Common Report Var(flag_ipa_modref) Optimization
Perform interprocedural modref analysis
fipa-profile
Common Report Var(flag_ipa_profile) Init(0) Optimization
Perform interprocedural profile propagation.

View File

@ -1726,7 +1726,7 @@ open_base_files (void)
"except.h", "output.h", "cfgloop.h", "target.h", "lto-streamer.h",
"target-globals.h", "ipa-ref.h", "cgraph.h", "symbol-summary.h",
"ipa-prop.h", "ipa-fnsummary.h", "dwarf2out.h", "omp-general.h",
"omp-offload.h", NULL
"omp-offload.h", "ipa-modref-tree.h", "ipa-modref.h", NULL
};
const char *const *ifp;
outf_p gtype_desc_c;

236
gcc/ipa-modref-tree.c Normal file
View File

@ -0,0 +1,236 @@
/* Data structure for the modref pass.
Copyright (C) 2020 Free Software Foundation, Inc.
Contributed by David Cepelik and Jan Hubicka
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "backend.h"
#include "tree.h"
#include "ipa-modref-tree.h"
#include "selftest.h"
#if CHECKING_P
static void
test_insert_search_collapse ()
{
modref_base_node<alias_set_type> *base_node;
modref_ref_node<alias_set_type> *ref_node;
modref_tree<alias_set_type> *t = new modref_tree<alias_set_type>(1, 2);
ASSERT_FALSE (t->every_base);
/* Insert into an empty tree. */
t->insert (1, 2);
ASSERT_NE (t->bases, NULL);
ASSERT_EQ (t->bases->length (), 1);
ASSERT_FALSE (t->every_base);
ASSERT_EQ (t->search (2), NULL);
base_node = t->search (1);
ASSERT_NE (base_node, NULL);
ASSERT_EQ (base_node->base, 1);
ASSERT_NE (base_node->refs, NULL);
ASSERT_EQ (base_node->refs->length (), 1);
ASSERT_EQ (base_node->search (1), NULL);
ref_node = base_node->search (2);
ASSERT_NE (ref_node, NULL);
ASSERT_EQ (ref_node->ref, 2);
/* Insert when base exists but ref does not. */
t->insert (1, 3);
ASSERT_NE (t->bases, NULL);
ASSERT_EQ (t->bases->length (), 1);
ASSERT_EQ (t->search (1), base_node);
ASSERT_EQ (t->search (2), NULL);
ASSERT_NE (base_node->refs, NULL);
ASSERT_EQ (base_node->refs->length (), 2);
ref_node = base_node->search (3);
ASSERT_NE (ref_node, NULL);
/* Insert when base and ref exist, but access is not dominated by nor
dominates other accesses. */
t->insert (1, 2);
ASSERT_EQ (t->bases->length (), 1);
ASSERT_EQ (t->search (1), base_node);
ref_node = base_node->search (2);
ASSERT_NE (ref_node, NULL);
/* Insert when base and ref exist and access is dominated. */
t->insert (1, 2);
ASSERT_EQ (t->search (1), base_node);
ASSERT_EQ (base_node->search (2), ref_node);
/* Insert ref to trigger ref list collapse for base 1. */
t->insert (1, 4);
ASSERT_EQ (t->search (1), base_node);
ASSERT_EQ (base_node->refs, NULL);
ASSERT_EQ (base_node->search (2), NULL);
ASSERT_EQ (base_node->search (3), NULL);
ASSERT_TRUE (base_node->every_ref);
/* Further inserts to collapsed ref list are ignored. */
t->insert (1, 5);
ASSERT_EQ (t->search (1), base_node);
ASSERT_EQ (base_node->refs, NULL);
ASSERT_EQ (base_node->search (2), NULL);
ASSERT_EQ (base_node->search (3), NULL);
ASSERT_TRUE (base_node->every_ref);
/* Insert base to trigger base list collapse. */
t->insert (5, 6);
ASSERT_TRUE (t->every_base);
ASSERT_EQ (t->bases, NULL);
ASSERT_EQ (t->search (1), NULL);
/* Further inserts to collapsed base list are ignored. */
t->insert (7, 8);
ASSERT_TRUE (t->every_base);
ASSERT_EQ (t->bases, NULL);
ASSERT_EQ (t->search (1), NULL);
}
static void
test_merge ()
{
modref_tree<alias_set_type> *t1, *t2;
modref_base_node<alias_set_type> *base_node;
t1 = new modref_tree<alias_set_type>(3, 4);
t1->insert (1, 1);
t1->insert (1, 2);
t1->insert (1, 3);
t1->insert (2, 1);
t1->insert (3, 1);
t2 = new modref_tree<alias_set_type>(10, 10);
t2->insert (1, 2);
t2->insert (1, 3);
t2->insert (1, 4);
t2->insert (3, 2);
t2->insert (3, 3);
t2->insert (3, 4);
t2->insert (3, 5);
t1->merge (t2);
ASSERT_FALSE (t1->every_base);
ASSERT_NE (t1->bases, NULL);
ASSERT_EQ (t1->bases->length (), 3);
base_node = t1->search (1);
ASSERT_NE (base_node->refs, NULL);
ASSERT_FALSE (base_node->every_ref);
ASSERT_EQ (base_node->refs->length (), 4);
base_node = t1->search (2);
ASSERT_NE (base_node->refs, NULL);
ASSERT_FALSE (base_node->every_ref);
ASSERT_EQ (base_node->refs->length (), 1);
base_node = t1->search (3);
ASSERT_EQ (base_node->refs, NULL);
ASSERT_TRUE (base_node->every_ref);
}
void
modref_tree_c_tests ()
{
test_insert_search_collapse ();
test_merge ();
}
#endif
void
gt_ggc_mx (modref_tree < int >*const &tt)
{
if (tt->bases)
{
ggc_test_and_set_mark (tt->bases);
gt_ggc_mx (tt->bases);
}
}
void
gt_ggc_mx (modref_tree < tree_node * >*const &tt)
{
if (tt->bases)
{
ggc_test_and_set_mark (tt->bases);
gt_ggc_mx (tt->bases);
}
}
void gt_pch_nx (modref_tree<int>* const&) {}
void gt_pch_nx (modref_tree<tree_node*>* const&) {}
void gt_pch_nx (modref_tree<int>* const&, gt_pointer_operator, void *) {}
void gt_pch_nx (modref_tree<tree_node*>* const&, gt_pointer_operator, void *) {}
void gt_ggc_mx (modref_base_node<int>* &b)
{
ggc_test_and_set_mark (b);
if (b->refs)
{
ggc_test_and_set_mark (b->refs);
gt_ggc_mx (b->refs);
}
}
void gt_ggc_mx (modref_base_node<tree_node*>* &b)
{
ggc_test_and_set_mark (b);
if (b->refs)
{
ggc_test_and_set_mark (b->refs);
gt_ggc_mx (b->refs);
}
if (b->base)
gt_ggc_mx (b->base);
}
void gt_pch_nx (modref_base_node<int>*) {}
void gt_pch_nx (modref_base_node<tree_node*>*) {}
void gt_pch_nx (modref_base_node<int>*, gt_pointer_operator, void *) {}
void gt_pch_nx (modref_base_node<tree_node*>*, gt_pointer_operator, void *) {}
void gt_ggc_mx (modref_ref_node<int>* &r)
{
ggc_test_and_set_mark (r);
}
void gt_ggc_mx (modref_ref_node<tree_node*>* &r)
{
ggc_test_and_set_mark (r);
if (r->ref)
gt_ggc_mx (r->ref);
}
void gt_pch_nx (modref_ref_node<int>* ) {}
void gt_pch_nx (modref_ref_node<tree_node*>*) {}
void gt_pch_nx (modref_ref_node<int>*, gt_pointer_operator, void *) {}
void gt_pch_nx (modref_ref_node<tree_node*>*, gt_pointer_operator, void *) {}

253
gcc/ipa-modref-tree.h Normal file
View File

@ -0,0 +1,253 @@
/* Data structure for the modref pass.
Copyright (C) 2020 Free Software Foundation, Inc.
Contributed by David Cepelik and Jan Hubicka
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#ifndef GCC_MODREF_TREE_H
#define GCC_MODREF_TREE_H
struct ipa_modref_summary;
template <typename T>
struct GTY((user)) modref_ref_node
{
T ref;
modref_ref_node (T ref):
ref (ref)
{}
};
/* Base of an access. */
template <typename T>
struct GTY((user)) modref_base_node
{
T base;
vec <modref_ref_node <T> *, va_gc> *refs;
bool every_ref;
modref_base_node (T base):
base (base),
refs (NULL),
every_ref (false) {}
/* Search REF; return NULL if failed. */
modref_ref_node <T> *search (T ref)
{
size_t i;
modref_ref_node <T> *n;
FOR_EACH_VEC_SAFE_ELT (refs, i, n)
if (n->ref == ref)
return n;
return NULL;
}
/* Insert REF; collapse tree if there are more than MAX_REFS. */
modref_ref_node <T> *insert_ref (T ref, size_t max_refs)
{
modref_ref_node <T> *ref_node;
/* If the node is collapsed, don't do anything. */
if (every_ref)
return NULL;
if (!ref)
{
collapse ();
return NULL;
}
/* Otherwise, insert a node for the ref of the access under the base. */
ref_node = search (ref);
if (ref_node)
return ref_node;
/* Collapse the node if too full already. */
if (refs && refs->length () >= max_refs)
{
if (dump_file)
fprintf (dump_file, "--param param=modref-max-refs limit reached\n");
collapse ();
return NULL;
}
ref_node = new (ggc_alloc <modref_ref_node <T> > ())modref_ref_node <T>
(ref);
vec_safe_push (refs, ref_node);
return ref_node;
}
void collapse ()
{
vec_free (refs);
refs = NULL;
every_ref = true;
}
};
/* Access tree for a single function. */
template <typename T>
struct GTY((user)) modref_tree
{
vec <modref_base_node <T> *, va_gc> *bases;
size_t max_bases;
size_t max_refs;
bool every_base;
modref_tree (size_t max_bases, size_t max_refs):
bases (NULL),
max_bases (max_bases),
max_refs (max_refs),
every_base (false) {}
modref_base_node <T> *insert_base (T base)
{
modref_base_node <T> *base_node;
/* If the node is collapsed, don't do anything. */
if (every_base)
return NULL;
/* Otherwise, insert a node for the base of the access into the tree. */
base_node = search (base);
if (base_node)
return base_node;
/* Collapse the node if too full already. */
if (bases && bases->length () >= max_bases)
{
if (dump_file)
fprintf (dump_file, "--param param=modref-max-bases limit reached\n");
collapse ();
return NULL;
}
base_node = new (ggc_alloc <modref_base_node <T> > ())
modref_base_node <T> (base);
vec_safe_push (bases, base_node);
return base_node;
}
/* Insert memory access to the tree. */
void insert (T base, T ref)
{
modref_base_node <T> *base_node;
base_node = insert_base (base);
if (!base && !ref)
{
collapse ();
return;
}
if (!base_node)
return;
gcc_assert (search (base) != NULL);
base_node->insert_ref (ref, max_refs);
if (!base && base_node->every_ref)
{
collapse ();
return;
}
}
/* Merge OTHER into the tree. */
void merge (modref_tree <T> *other)
{
if (!other)
return;
if (other->every_base)
{
collapse ();
return;
}
size_t i, j;
modref_base_node <T> *base_node, *my_base_node;
modref_ref_node <T> *ref_node, *my_ref_node;
FOR_EACH_VEC_SAFE_ELT (other->bases, i, base_node)
{
my_base_node = insert_base (base_node->base);
if (!my_base_node)
continue;
if (base_node->every_ref)
{
my_base_node->collapse ();
continue;
}
FOR_EACH_VEC_SAFE_ELT (base_node->refs, j, ref_node)
{
my_ref_node = my_base_node->insert_ref (ref_node->ref, max_refs);
if (!my_ref_node)
continue;
}
}
}
/* Search BASE in tree; return NULL if failed. */
modref_base_node <T> *search (T base)
{
size_t i;
modref_base_node <T> *n;
FOR_EACH_VEC_SAFE_ELT (bases, i, n)
if (n->base == base)
return n;
return NULL;
}
void collapse ()
{
vec_free (bases);
bases = NULL;
every_base = true;
}
};
void modref_c_tests ();
void gt_ggc_mx (modref_tree <int>* const&);
void gt_ggc_mx (modref_tree <tree_node*>* const&);
void gt_pch_nx (modref_tree <int>* const&);
void gt_pch_nx (modref_tree <tree_node*>* const&);
void gt_pch_nx (modref_tree <int>* const&, gt_pointer_operator op, void *cookie);
void gt_pch_nx (modref_tree <tree_node*>* const&, gt_pointer_operator op,
void *cookie);
void gt_ggc_mx (modref_base_node <int>*);
void gt_ggc_mx (modref_base_node <tree_node*>* &);
void gt_pch_nx (modref_base_node <int>* const&);
void gt_pch_nx (modref_base_node <tree_node*>* const&);
void gt_pch_nx (modref_base_node <int>* const&, gt_pointer_operator op,
void *cookie);
void gt_pch_nx (modref_base_node <tree_node*>* const&, gt_pointer_operator op,
void *cookie);
void gt_ggc_mx (modref_ref_node <int>*);
void gt_ggc_mx (modref_ref_node <tree_node*>* &);
void gt_pch_nx (modref_ref_node <int>* const&);
void gt_pch_nx (modref_ref_node <tree_node*>* const&);
void gt_pch_nx (modref_ref_node <int>* const&, gt_pointer_operator op,
void *cookie);
void gt_pch_nx (modref_ref_node <tree_node*>* const&, gt_pointer_operator op,
void *cookie);
#endif

1376
gcc/ipa-modref.c Normal file

File diff suppressed because it is too large Load Diff

48
gcc/ipa-modref.h Normal file
View File

@ -0,0 +1,48 @@
/* Search for references that a functions loads or stores.
Copyright (C) 2019 Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#ifndef IPA_MODREF_H
#define IPA_MODREF_H
typedef modref_tree <alias_set_type> modref_records;
typedef modref_tree <tree> modref_records_lto;
/* Single function summary. */
struct GTY(()) modref_summary
{
/* Load and stores in function (transitively closed to all callees) */
modref_records *loads;
modref_records *stores;
/* The same but using tree types rather than alias sets. This is necessary
to make the information streamable for LTO but is also more verbose
and thus more likely to hit the limits. */
modref_records_lto *loads_lto;
modref_records_lto *stores_lto;
bool finished;
modref_summary ();
~modref_summary ();
void dump (FILE *);
};
modref_summary *get_modref_function_summary (cgraph_node *func);
#endif

View File

@ -56,6 +56,7 @@ const char *lto_section_name[LTO_N_SECTION_TYPES] =
"lto",
"ipa_sra",
"odr_types",
"ipa_modref",
};
/* Hooks so that the ipa passes can call into the lto front end to get

View File

@ -227,6 +227,7 @@ enum lto_section_type
LTO_section_lto,
LTO_section_ipa_sra,
LTO_section_odr_types,
LTO_section_ipa_modref,
LTO_N_SECTION_TYPES /* Must be last. */
};

View File

@ -466,6 +466,7 @@ static const struct default_options default_options_table[] =
{ OPT_LEVELS_1_PLUS_NOT_DEBUG, OPT_finline_functions_called_once, NULL, 1 },
{ OPT_LEVELS_1_PLUS_NOT_DEBUG, OPT_fmove_loop_invariants, NULL, 1 },
{ OPT_LEVELS_1_PLUS_NOT_DEBUG, OPT_fssa_phiopt, NULL, 1 },
{ OPT_LEVELS_1_PLUS_NOT_DEBUG, OPT_fipa_modref, NULL, 1 },
{ OPT_LEVELS_1_PLUS_NOT_DEBUG, OPT_ftree_bit_ccp, NULL, 1 },
{ OPT_LEVELS_1_PLUS_NOT_DEBUG, OPT_ftree_dse, NULL, 1 },
{ OPT_LEVELS_1_PLUS_NOT_DEBUG, OPT_ftree_pta, NULL, 1 },

View File

@ -872,6 +872,18 @@ Maximum size of a single store merging region in bytes.
Common Joined UInteger Var(param_switch_conversion_branch_ratio) Init(8) IntegerRange(1, 65536) Param Optimization
The maximum ratio between array size and switch branches for a switch conversion to take place.
-param=modref-max-bases=
Common Joined UInteger Var(param_modref_max_bases) Init(32)
Maximum number of bases stored in each modref tree.
-param=modref-max-refs=
Common Joined UInteger Var(param_modref_max_refs) Init(16)
Maximum number of refs stored in each modref tree.
-param=modref-max-tests=
Common Joined UInteger Var(param_modref_max_tests) Init(64)
Maximum number of tests perofmed by modref query
-param=tm-max-aggregate-size=
Common Joined UInteger Var(param_tm_max_aggregate_size) Init(9) Param Optimization
Size in bytes after which thread-local aggregates should be instrumented with the logging functions instead of save/restore pairs.

View File

@ -91,6 +91,7 @@ along with GCC; see the file COPYING3. If not see
NEXT_PASS (pass_dse);
NEXT_PASS (pass_cd_dce);
NEXT_PASS (pass_phiopt, true /* early_p */);
NEXT_PASS (pass_modref);
NEXT_PASS (pass_tail_recursion);
NEXT_PASS (pass_convert_switch);
NEXT_PASS (pass_cleanup_eh);
@ -156,6 +157,7 @@ along with GCC; see the file COPYING3. If not see
NEXT_PASS (pass_ipa_fn_summary);
NEXT_PASS (pass_ipa_inline);
NEXT_PASS (pass_ipa_pure_const);
NEXT_PASS (pass_ipa_modref);
NEXT_PASS (pass_ipa_free_fn_summary, false /* small_p */);
NEXT_PASS (pass_ipa_reference);
/* This pass needs to be scheduled after any IP code duplication. */
@ -346,6 +348,7 @@ along with GCC; see the file COPYING3. If not see
NEXT_PASS (pass_late_warn_uninitialized);
NEXT_PASS (pass_uncprop);
NEXT_PASS (pass_local_pure_const);
NEXT_PASS (pass_modref);
POP_INSERT_PASSES ()
NEXT_PASS (pass_all_optimizations_g);
PUSH_INSERT_PASSES_WITHIN (pass_all_optimizations_g)
@ -378,6 +381,7 @@ along with GCC; see the file COPYING3. If not see
NEXT_PASS (pass_late_warn_uninitialized);
NEXT_PASS (pass_uncprop);
NEXT_PASS (pass_local_pure_const);
NEXT_PASS (pass_modref);
POP_INSERT_PASSES ()
NEXT_PASS (pass_tm_init);
PUSH_INSERT_PASSES_WITHIN (pass_tm_init)

View File

@ -107,6 +107,7 @@ DEFTIMEVAR (TV_IPA_PTA , "ipa points-to")
DEFTIMEVAR (TV_IPA_SRA , "ipa SRA")
DEFTIMEVAR (TV_IPA_FREE_LANG_DATA , "ipa free lang data")
DEFTIMEVAR (TV_IPA_FREE_INLINE_SUMMARY, "ipa free inline summary")
DEFTIMEVAR (TV_IPA_MODREF , "ipa modref")
/* Time spent by constructing CFG. */
DEFTIMEVAR (TV_CFG , "cfg construction")
/* Time spent by cleaning up CFG. */
@ -218,6 +219,7 @@ DEFTIMEVAR (TV_TREE_SINCOS , "gimple CSE sin/cos")
DEFTIMEVAR (TV_TREE_WIDEN_MUL , "gimple widening/fma detection")
DEFTIMEVAR (TV_TRANS_MEM , "transactional memory")
DEFTIMEVAR (TV_TREE_STRLEN , "tree strlen optimization")
DEFTIMEVAR (TV_TREE_MODREF , "tree modref")
DEFTIMEVAR (TV_CGRAPH_VERIFY , "callgraph verifier")
DEFTIMEVAR (TV_DOM_FRONTIERS , "dominance frontiers")
DEFTIMEVAR (TV_DOMINANCE , "dominance computation")

View File

@ -477,6 +477,7 @@ extern simple_ipa_opt_pass *make_pass_ipa_oacc_kernels (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_warn_nonnull_compare (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_sprintf_length (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_walloca (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_modref (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_coroutine_lower_builtins (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_coroutine_early_expand_ifns (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_adjust_alignment (gcc::context *ctxt);
@ -517,6 +518,7 @@ extern ipa_opt_pass_d *make_pass_ipa_profile (gcc::context *ctxt);
extern ipa_opt_pass_d *make_pass_ipa_cdtor_merge (gcc::context *ctxt);
extern ipa_opt_pass_d *make_pass_ipa_single_use (gcc::context *ctxt);
extern ipa_opt_pass_d *make_pass_ipa_comdats (gcc::context *ctxt);
extern ipa_opt_pass_d *make_pass_ipa_modref (gcc::context *ctxt);
extern simple_ipa_opt_pass *make_pass_materialize_all_clones (gcc::context *
ctxt);

View File

@ -38,6 +38,8 @@ along with GCC; see the file COPYING3. If not see
#include "tree-dfa.h"
#include "ipa-reference.h"
#include "varasm.h"
#include "ipa-modref-tree.h"
#include "ipa-modref.h"
/* Broad overview of how alias analysis on gimple works:
@ -107,6 +109,11 @@ static struct {
unsigned HOST_WIDE_INT nonoverlapping_refs_since_match_p_may_alias;
unsigned HOST_WIDE_INT nonoverlapping_refs_since_match_p_must_overlap;
unsigned HOST_WIDE_INT nonoverlapping_refs_since_match_p_no_alias;
unsigned HOST_WIDE_INT modref_use_may_alias;
unsigned HOST_WIDE_INT modref_use_no_alias;
unsigned HOST_WIDE_INT modref_clobber_may_alias;
unsigned HOST_WIDE_INT modref_clobber_no_alias;
unsigned HOST_WIDE_INT modref_tests;
} alias_stats;
void
@ -153,6 +160,24 @@ dump_alias_stats (FILE *s)
alias_stats.aliasing_component_refs_p_no_alias
+ alias_stats.aliasing_component_refs_p_may_alias);
dump_alias_stats_in_alias_c (s);
fprintf (s, "\nModref stats:\n");
fprintf (s, " modref use: "
HOST_WIDE_INT_PRINT_DEC" disambiguations, "
HOST_WIDE_INT_PRINT_DEC" queries\n",
alias_stats.modref_use_no_alias,
alias_stats.modref_use_no_alias
+ alias_stats.modref_use_may_alias);
fprintf (s, " modref clobber: "
HOST_WIDE_INT_PRINT_DEC" disambiguations, "
HOST_WIDE_INT_PRINT_DEC" queries\n "
HOST_WIDE_INT_PRINT_DEC" tbaa querries (%f per modref querry)\n",
alias_stats.modref_clobber_no_alias,
alias_stats.modref_clobber_no_alias
+ alias_stats.modref_clobber_may_alias,
alias_stats.modref_tests,
((double)alias_stats.modref_tests)
/ (alias_stats.modref_clobber_no_alias
+ alias_stats.modref_clobber_may_alias));
}
@ -1341,8 +1366,8 @@ nonoverlapping_array_refs_p (tree ref1, tree ref2)
{
tree index1 = TREE_OPERAND (ref1, 1);
tree index2 = TREE_OPERAND (ref2, 1);
tree low_bound1 = cheap_array_ref_low_bound(ref1);
tree low_bound2 = cheap_array_ref_low_bound(ref2);
tree low_bound1 = cheap_array_ref_low_bound (ref1);
tree low_bound2 = cheap_array_ref_low_bound (ref2);
/* Handle zero offsets first: we do not need to match type size in this
case. */
@ -2394,6 +2419,63 @@ refs_output_dependent_p (tree store1, tree store2)
return refs_may_alias_p_1 (&r1, &r2, false);
}
/* Returns true if and only if REF may alias any access stored in TT.
IF TBAA_P is true, use TBAA oracle. */
static bool
modref_may_conflict (modref_tree <alias_set_type> *tt, ao_ref *ref, bool tbaa_p)
{
alias_set_type base_set, ref_set;
modref_base_node <alias_set_type> *base_node;
modref_ref_node <alias_set_type> *ref_node;
size_t i, j;
if (tt->every_base)
return true;
base_set = ao_ref_base_alias_set (ref);
ref_set = ao_ref_alias_set (ref);
int num_tests = 0, max_tests = param_modref_max_tests;
FOR_EACH_VEC_SAFE_ELT (tt->bases, i, base_node)
{
if (base_node->every_ref)
return true;
if (!base_node->base)
return true;
if (tbaa_p && flag_strict_aliasing)
{
if (!alias_sets_conflict_p (base_set, base_node->base))
continue;
alias_stats.modref_tests++;
num_tests++;
}
else
return true;
if (num_tests >= max_tests)
return true;
FOR_EACH_VEC_SAFE_ELT (base_node->refs, j, ref_node)
{
/* Do not repeat same test as before. */
if (ref_set == base_set && base_node->base == ref_node->ref)
return true;
if (!flag_strict_aliasing)
return true;
if (alias_sets_conflict_p (ref_set, ref_node->ref))
return true;
alias_stats.modref_tests++;
num_tests++;
if (num_tests >= max_tests)
return true;
}
}
return false;
}
/* If the call CALL may use the memory reference REF return true,
otherwise return false. */
@ -2409,15 +2491,51 @@ ref_maybe_used_by_call_p_1 (gcall *call, ao_ref *ref, bool tbaa_p)
&& (flags & (ECF_CONST|ECF_NOVOPS)))
goto process_args;
base = ao_ref_base (ref);
if (!base)
return true;
/* A call that is not without side-effects might involve volatile
accesses and thus conflicts with all other volatile accesses. */
if (ref->volatile_p)
return true;
callee = gimple_call_fndecl (call);
if (!gimple_call_chain (call) && callee != NULL_TREE)
{
struct cgraph_node *node = cgraph_node::get (callee);
/* We can not safely optimize based on summary of calle if it does
not always bind to current def: it is possible that memory load
was optimized out earlier and the interposed variant may not be
optimized this way. */
if (node && node->binds_to_current_def_p ())
{
modref_summary *summary = get_modref_function_summary (node);
if (summary)
{
if (!modref_may_conflict (summary->loads, ref, tbaa_p))
{
alias_stats.modref_use_no_alias++;
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "ipa-modref: in %s,"
" call to %s does not use ",
cgraph_node::get
(current_function_decl)->dump_name (),
node->dump_name ());
print_generic_expr (dump_file, ref->ref);
fprintf (dump_file, " %i->%i\n",
ao_ref_base_alias_set (ref),
ao_ref_alias_set (ref));
}
goto process_args;
}
alias_stats.modref_use_may_alias++;
}
}
}
base = ao_ref_base (ref);
if (!base)
return true;
/* If the reference is based on a decl that is not aliased the call
cannot possibly use it. */
if (DECL_P (base)
@ -2426,8 +2544,6 @@ ref_maybe_used_by_call_p_1 (gcall *call, ao_ref *ref, bool tbaa_p)
&& !is_global_var (base))
goto process_args;
callee = gimple_call_fndecl (call);
/* Handle those builtin functions explicitly that do not act as
escape points. See tree-ssa-structalias.c:find_func_aliases
for the list of builtins we might need to handle here. */
@ -2781,7 +2897,7 @@ ref_maybe_used_by_stmt_p (gimple *stmt, tree ref, bool tbaa_p)
return true, otherwise return false. */
bool
call_may_clobber_ref_p_1 (gcall *call, ao_ref *ref)
call_may_clobber_ref_p_1 (gcall *call, ao_ref *ref, bool tbaa_p)
{
tree base;
tree callee;
@ -2808,6 +2924,39 @@ call_may_clobber_ref_p_1 (gcall *call, ao_ref *ref)
break;
}
callee = gimple_call_fndecl (call);
if (callee != NULL_TREE && !ref->volatile_p)
{
struct cgraph_node *node = cgraph_node::get (callee);
if (node)
{
modref_summary *summary = get_modref_function_summary (node);
if (summary)
{
if (!modref_may_conflict (summary->stores, ref, tbaa_p))
{
alias_stats.modref_clobber_no_alias++;
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file,
"ipa-modref: in %s, "
"call to %s does not clobber ",
cgraph_node::get
(current_function_decl)->dump_name (),
node->dump_name ());
print_generic_expr (dump_file, ref->ref);
fprintf (dump_file, " %i->%i\n",
ao_ref_base_alias_set (ref),
ao_ref_alias_set (ref));
}
return false;
}
alias_stats.modref_clobber_may_alias++;
}
}
}
base = ao_ref_base (ref);
if (!base)
return true;
@ -2840,8 +2989,6 @@ call_may_clobber_ref_p_1 (gcall *call, ao_ref *ref)
&& SSA_NAME_POINTS_TO_READONLY_MEMORY (TREE_OPERAND (base, 0)))
return false;
callee = gimple_call_fndecl (call);
/* Handle those builtin functions explicitly that do not act as
escape points. See tree-ssa-structalias.c:find_func_aliases
for the list of builtins we might need to handle here. */
@ -3083,7 +3230,7 @@ call_may_clobber_ref_p (gcall *call, tree ref)
bool res;
ao_ref r;
ao_ref_init (&r, ref);
res = call_may_clobber_ref_p_1 (call, &r);
res = call_may_clobber_ref_p_1 (call, &r, true);
if (res)
++alias_stats.call_may_clobber_ref_p_may_alias;
else
@ -3110,7 +3257,7 @@ stmt_may_clobber_ref_p_1 (gimple *stmt, ao_ref *ref, bool tbaa_p)
return true;
}
return call_may_clobber_ref_p_1 (as_a <gcall *> (stmt), ref);
return call_may_clobber_ref_p_1 (as_a <gcall *> (stmt), ref, tbaa_p);
}
else if (gimple_assign_single_p (stmt))
{

View File

@ -129,7 +129,7 @@ extern bool stmt_may_clobber_global_p (gimple *);
extern bool stmt_may_clobber_ref_p (gimple *, tree, bool = true);
extern bool stmt_may_clobber_ref_p_1 (gimple *, ao_ref *, bool = true);
extern bool call_may_clobber_ref_p (gcall *, tree);
extern bool call_may_clobber_ref_p_1 (gcall *, ao_ref *);
extern bool call_may_clobber_ref_p_1 (gcall *, ao_ref *, bool = true);
extern bool stmt_kills_ref_p (gimple *, tree);
extern bool stmt_kills_ref_p (gimple *, ao_ref *);
enum translate_flags