re PR tree-optimization/30735 (50% slow down due to mem-ssa merge)
PR 30735 PR 31090 * doc/invoke.texi: Document --params max-aliased-vops and avg-aliased-vops. * tree-ssa-operands.h (get_mpt_for, dump_memory_partitions, debug_memory_partitions): Move to tree-flow.h * params.h (AVG_ALIASED_VOPS): Define. * tree-ssa-alias.c (struct mp_info_def): Remove. Update all users. (mp_info_t): Likewise. (get_mem_sym_stats_for): New. (set_memory_partition): Move from tree-flow-inline.h. (mark_non_addressable): Only clear the set of symbols for the partition if it exists. (dump_memory_partitions): Move from tree-ssa-operands.c (debug_memory_partitions): Likewise. (need_to_partition_p): New. (dump_mem_ref_stats): New. (debug_mem_ref_stats): New. (dump_mem_sym_stats): New. (debug_mem_sym_stats): New. (update_mem_sym_stats_from_stmt): New. (compare_mp_info_entries): New. (mp_info_cmp): Call it. (sort_mp_info): Change argument to a list of mem_sym_stats_t objects. (get_mpt_for): Move from tree-ssa-operands.c. (find_partition_for): New. (create_partition_for): Remove. (estimate_vop_reduction): New. (update_reference_counts): New. (build_mp_info): New. (compute_memory_partitions): Refactor. Document new heuristic. Call build_mp_info, update_reference_counts, find_partition_for and estimate_vop_reduction. (compute_may_aliases): Populate virtual operands before calling debugging dumps. (delete_mem_sym_stats): New. (delete_mem_ref_stats): New. (init_mem_ref_stats): New. (init_alias_info): Call it. (maybe_create_global_var): Remove alias_info argument. Get number of call sites and number of pure/const call sites from gimple_mem_ref_stats(). (dump_alias_info): Call dump_memory_partitions first. (dump_points_to_info_for): Show how many times a pointer has been dereferenced. * opts.c (decode_options): For -O2 set --param max-aliased-vops to 500. For -O3 set --param max-aliased-vops to 1000 and --param avg-aliased-vops to 3. * fortran/options.c (gfc_init_options): Remove assignment to MAX_ALIASED_VOPS. * tree-flow-inline.h (gimple_mem_ref_stats): New. * tree-dfa.c (dump_variable): Dump memory reference statistics. Dump NO_ALIAS* settings. (referenced_var_lookup): Tidy. (mem_sym_stats): New. * tree-ssa-copy.c (may_propagate_copy): Return true if DEST and ORIG are different SSA names for a memory partition. * tree-ssa.c (delete_tree_ssa): Call delete_mem_ref_stats. * tree-flow.h (struct mem_sym_stats_d): Define. (mem_sym_stats_t): Define. (struct mem_ref_stats_d): Define. (struct gimple_df): Add field mem_ref_stats. (enum noalias_state): Define. (struct var_ann_d): Add bitfield noalias_state. (mem_sym_stats, delete_mem_ref_stats, dump_mem_ref_stats, debug_mem_ref_stats, debug_memory_partitions, debug_mem_sym_stats): Declare. * tree-ssa-structalias.c (update_alias_info): Update call sites, pure/const call sites and asm sites in structure returned by gimple_mem_ref_stats. Remove local variable IS_POTENTIAL_DEREF. Increase NUM_DEREFS if the memory expression is a potential dereference. Call update_mem_sym_stats_from_stmt. If the memory references memory, call update_mem_sym_stats_from_stmt for all the direct memory symbol references found. (intra_create_variable_infos): Set noalias_state field for pointer arguments according to the value of flag_argument_noalias. * tree-ssa-structalias.h (struct alias_info): Remove fields num_calls_found and num_pure_const_calls_found. (update_mem_sym_stats_from_stmt): Declare. * params.def (PARAM_MAX_ALIASED_VOPS): Change description. Set default value to 100. (PARAM_AVG_ALIASED_VOPS): Define. From-SVN: r123719
This commit is contained in:
parent
574e75f5fb
commit
e9e0aa2c96
|
@ -1,3 +1,97 @@
|
||||||
|
2007-04-11 Diego Novillo <dnovillo@redhat.com>
|
||||||
|
|
||||||
|
PR 30735
|
||||||
|
PR 31090
|
||||||
|
* doc/invoke.texi: Document --params max-aliased-vops and
|
||||||
|
avg-aliased-vops.
|
||||||
|
* tree-ssa-operands.h (get_mpt_for, dump_memory_partitions,
|
||||||
|
debug_memory_partitions): Move to tree-flow.h
|
||||||
|
* params.h (AVG_ALIASED_VOPS): Define.
|
||||||
|
* tree-ssa-alias.c (struct mp_info_def): Remove. Update all
|
||||||
|
users.
|
||||||
|
(mp_info_t): Likewise.
|
||||||
|
(get_mem_sym_stats_for): New.
|
||||||
|
(set_memory_partition): Move from tree-flow-inline.h.
|
||||||
|
(mark_non_addressable): Only clear the set of symbols for the
|
||||||
|
partition if it exists.
|
||||||
|
(dump_memory_partitions): Move from tree-ssa-operands.c
|
||||||
|
(debug_memory_partitions): Likewise.
|
||||||
|
(need_to_partition_p): New.
|
||||||
|
(dump_mem_ref_stats): New.
|
||||||
|
(debug_mem_ref_stats): New.
|
||||||
|
(dump_mem_sym_stats): New.
|
||||||
|
(debug_mem_sym_stats): New.
|
||||||
|
(update_mem_sym_stats_from_stmt): New.
|
||||||
|
(compare_mp_info_entries): New.
|
||||||
|
(mp_info_cmp): Call it.
|
||||||
|
(sort_mp_info): Change argument to a list of mem_sym_stats_t
|
||||||
|
objects.
|
||||||
|
(get_mpt_for): Move from tree-ssa-operands.c.
|
||||||
|
(find_partition_for): New.
|
||||||
|
(create_partition_for): Remove.
|
||||||
|
(estimate_vop_reduction): New.
|
||||||
|
(update_reference_counts): New.
|
||||||
|
(build_mp_info): New.
|
||||||
|
(compute_memory_partitions): Refactor.
|
||||||
|
Document new heuristic.
|
||||||
|
Call build_mp_info, update_reference_counts,
|
||||||
|
find_partition_for and estimate_vop_reduction.
|
||||||
|
(compute_may_aliases): Populate virtual operands before
|
||||||
|
calling debugging dumps.
|
||||||
|
(delete_mem_sym_stats): New.
|
||||||
|
(delete_mem_ref_stats): New.
|
||||||
|
(init_mem_ref_stats): New.
|
||||||
|
(init_alias_info): Call it.
|
||||||
|
(maybe_create_global_var): Remove alias_info argument.
|
||||||
|
Get number of call sites and number of pure/const call sites
|
||||||
|
from gimple_mem_ref_stats().
|
||||||
|
(dump_alias_info): Call dump_memory_partitions first.
|
||||||
|
(dump_points_to_info_for): Show how many times a pointer has
|
||||||
|
been dereferenced.
|
||||||
|
* opts.c (decode_options): For -O2 set --param
|
||||||
|
max-aliased-vops to 500.
|
||||||
|
For -O3 set --param max-aliased-vops to 1000 and --param
|
||||||
|
avg-aliased-vops to 3.
|
||||||
|
* fortran/options.c (gfc_init_options): Remove assignment to
|
||||||
|
MAX_ALIASED_VOPS.
|
||||||
|
* tree-flow-inline.h (gimple_mem_ref_stats): New.
|
||||||
|
* tree-dfa.c (dump_variable): Dump memory reference
|
||||||
|
statistics.
|
||||||
|
Dump NO_ALIAS* settings.
|
||||||
|
(referenced_var_lookup): Tidy.
|
||||||
|
(mem_sym_stats): New.
|
||||||
|
* tree-ssa-copy.c (may_propagate_copy): Return true if DEST
|
||||||
|
and ORIG are different SSA names for a memory partition.
|
||||||
|
* tree-ssa.c (delete_tree_ssa): Call delete_mem_ref_stats.
|
||||||
|
* tree-flow.h (struct mem_sym_stats_d): Define.
|
||||||
|
(mem_sym_stats_t): Define.
|
||||||
|
(struct mem_ref_stats_d): Define.
|
||||||
|
(struct gimple_df): Add field mem_ref_stats.
|
||||||
|
(enum noalias_state): Define.
|
||||||
|
(struct var_ann_d): Add bitfield noalias_state.
|
||||||
|
(mem_sym_stats, delete_mem_ref_stats, dump_mem_ref_stats,
|
||||||
|
debug_mem_ref_stats, debug_memory_partitions,
|
||||||
|
debug_mem_sym_stats): Declare.
|
||||||
|
* tree-ssa-structalias.c (update_alias_info): Update call
|
||||||
|
sites, pure/const call sites and asm sites in structure
|
||||||
|
returned by gimple_mem_ref_stats.
|
||||||
|
Remove local variable IS_POTENTIAL_DEREF.
|
||||||
|
Increase NUM_DEREFS if the memory expression is a potential
|
||||||
|
dereference.
|
||||||
|
Call update_mem_sym_stats_from_stmt.
|
||||||
|
If the memory references memory, call
|
||||||
|
update_mem_sym_stats_from_stmt for all the direct memory
|
||||||
|
symbol references found.
|
||||||
|
(intra_create_variable_infos): Set noalias_state field for
|
||||||
|
pointer arguments according to the value of
|
||||||
|
flag_argument_noalias.
|
||||||
|
* tree-ssa-structalias.h (struct alias_info): Remove fields
|
||||||
|
num_calls_found and num_pure_const_calls_found.
|
||||||
|
(update_mem_sym_stats_from_stmt): Declare.
|
||||||
|
* params.def (PARAM_MAX_ALIASED_VOPS): Change description.
|
||||||
|
Set default value to 100.
|
||||||
|
(PARAM_AVG_ALIASED_VOPS): Define.
|
||||||
|
|
||||||
2007-04-11 Richard Guenther <rguenther@suse.de>
|
2007-04-11 Richard Guenther <rguenther@suse.de>
|
||||||
|
|
||||||
PR middle-end/31530
|
PR middle-end/31530
|
||||||
|
|
|
@ -6588,10 +6588,29 @@ The maximum instructions CSE process before flushing. The default is 1000.
|
||||||
|
|
||||||
@item max-aliased-vops
|
@item max-aliased-vops
|
||||||
|
|
||||||
Maximum number of virtual operands per statement allowed to represent
|
Maximum number of virtual operands per function allowed to represent
|
||||||
aliases before triggering the alias grouping heuristic. Alias
|
aliases before triggering the alias partitioning heuristic. Alias
|
||||||
grouping reduces compile times and memory consumption needed for
|
partitioning reduces compile times and memory consumption needed for
|
||||||
aliasing at the expense of precision loss in alias information.
|
aliasing at the expense of precision loss in alias information. The
|
||||||
|
default value for this parameter is 100 for -O1, 500 for -O2 and 1000
|
||||||
|
for -O3.
|
||||||
|
|
||||||
|
Notice that if a function contains more memory statements than the
|
||||||
|
value of this parameter, it is not really possible to achieve this
|
||||||
|
reduction. In this case, the compiler will use the number of memory
|
||||||
|
statements as the value for @option{max-aliased-vops}.
|
||||||
|
|
||||||
|
@item avg-aliased-vops
|
||||||
|
|
||||||
|
Average number of virtual operands per statement allowed to represent
|
||||||
|
aliases before triggering the alias partitioning heuristic. This
|
||||||
|
works in conjunction with @option{max-aliased-vops}. If a function
|
||||||
|
contains more than @option{max-aliased-vops} virtual operators, then
|
||||||
|
memory symbols will be grouped into memory partitions until either the
|
||||||
|
total number of virtual operators is below @option{max-aliased-vops}
|
||||||
|
or the average number of virtual operators per memory statement is
|
||||||
|
below @option{avg-aliased-vops}. The default value for this parameter
|
||||||
|
is 1 for -O1 and -O2, and 3 for -O3.
|
||||||
|
|
||||||
@item ggc-min-expand
|
@item ggc-min-expand
|
||||||
|
|
||||||
|
|
|
@ -117,10 +117,6 @@ gfc_init_options (unsigned int argc ATTRIBUTE_UNUSED,
|
||||||
/* -fshort-enums can be default on some targets. */
|
/* -fshort-enums can be default on some targets. */
|
||||||
gfc_option.fshort_enums = targetm.default_short_enums ();
|
gfc_option.fshort_enums = targetm.default_short_enums ();
|
||||||
|
|
||||||
/* Increase MAX_ALIASED_VOPS to account for different characteristics
|
|
||||||
of Fortran regarding VOPs. */
|
|
||||||
MAX_ALIASED_VOPS = 50;
|
|
||||||
|
|
||||||
return CL_Fortran;
|
return CL_Fortran;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -506,6 +506,9 @@ decode_options (unsigned int argc, const char **argv)
|
||||||
/* PRE tends to generate bigger code. */
|
/* PRE tends to generate bigger code. */
|
||||||
flag_tree_pre = 1;
|
flag_tree_pre = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Allow more virtual operators to increase alias precision. */
|
||||||
|
set_param_value ("max-aliased-vops", 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (optimize >= 3)
|
if (optimize >= 3)
|
||||||
|
@ -513,6 +516,10 @@ decode_options (unsigned int argc, const char **argv)
|
||||||
flag_inline_functions = 1;
|
flag_inline_functions = 1;
|
||||||
flag_unswitch_loops = 1;
|
flag_unswitch_loops = 1;
|
||||||
flag_gcse_after_reload = 1;
|
flag_gcse_after_reload = 1;
|
||||||
|
|
||||||
|
/* Allow even more virtual operators. */
|
||||||
|
set_param_value ("max-aliased-vops", 1000);
|
||||||
|
set_param_value ("avg-aliased-vops", 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (optimize < 2 || optimize_size)
|
if (optimize < 2 || optimize_size)
|
||||||
|
|
|
@ -530,8 +530,13 @@ DEFPARAM(PARAM_MAX_RELOAD_SEARCH_INSNS,
|
||||||
|
|
||||||
DEFPARAM(PARAM_MAX_ALIASED_VOPS,
|
DEFPARAM(PARAM_MAX_ALIASED_VOPS,
|
||||||
"max-aliased-vops",
|
"max-aliased-vops",
|
||||||
"The maximum number of virtual operators per statement allowed to represent aliases before triggering alias grouping",
|
"The maximum number of virtual operators that a function is allowed to have before triggering memory partitioning heuristics",
|
||||||
10, 0, 0)
|
100, 0, 0)
|
||||||
|
|
||||||
|
DEFPARAM(PARAM_AVG_ALIASED_VOPS,
|
||||||
|
"avg-aliased-vops",
|
||||||
|
"The average number of virtual operators that memory statements are allowed to have before triggering memory partitioning heuristics",
|
||||||
|
1, 0, 0)
|
||||||
|
|
||||||
DEFPARAM(PARAM_MAX_SCHED_REGION_BLOCKS,
|
DEFPARAM(PARAM_MAX_SCHED_REGION_BLOCKS,
|
||||||
"max-sched-region-blocks",
|
"max-sched-region-blocks",
|
||||||
|
|
|
@ -146,6 +146,8 @@ typedef enum compiler_param
|
||||||
PARAM_VALUE (PARAM_SMS_LOOP_AVERAGE_COUNT_THRESHOLD)
|
PARAM_VALUE (PARAM_SMS_LOOP_AVERAGE_COUNT_THRESHOLD)
|
||||||
#define MAX_ALIASED_VOPS \
|
#define MAX_ALIASED_VOPS \
|
||||||
PARAM_VALUE (PARAM_MAX_ALIASED_VOPS)
|
PARAM_VALUE (PARAM_MAX_ALIASED_VOPS)
|
||||||
|
#define AVG_ALIASED_VOPS \
|
||||||
|
PARAM_VALUE (PARAM_AVG_ALIASED_VOPS)
|
||||||
#define INTEGER_SHARE_LIMIT \
|
#define INTEGER_SHARE_LIMIT \
|
||||||
PARAM_VALUE (PARAM_INTEGER_SHARE_LIMIT)
|
PARAM_VALUE (PARAM_INTEGER_SHARE_LIMIT)
|
||||||
#define MAX_LAST_VALUE_RTL \
|
#define MAX_LAST_VALUE_RTL \
|
||||||
|
|
|
@ -346,34 +346,54 @@ dump_variable (FILE *file, tree var)
|
||||||
if (TREE_THIS_VOLATILE (var))
|
if (TREE_THIS_VOLATILE (var))
|
||||||
fprintf (file, ", is volatile");
|
fprintf (file, ", is volatile");
|
||||||
|
|
||||||
|
if (mem_sym_stats (cfun, var))
|
||||||
|
{
|
||||||
|
mem_sym_stats_t stats = mem_sym_stats (cfun, var);
|
||||||
|
fprintf (file, ", direct reads: %ld", stats->num_direct_reads);
|
||||||
|
fprintf (file, ", direct writes: %ld", stats->num_direct_writes);
|
||||||
|
fprintf (file, ", indirect reads: %ld", stats->num_indirect_reads);
|
||||||
|
fprintf (file, ", indirect writes: %ld", stats->num_indirect_writes);
|
||||||
|
fprintf (file, ", read frequency: %ld", stats->frequency_reads);
|
||||||
|
fprintf (file, ", write frequency: %ld", stats->frequency_writes);
|
||||||
|
}
|
||||||
|
|
||||||
if (is_call_clobbered (var))
|
if (is_call_clobbered (var))
|
||||||
{
|
{
|
||||||
|
const char *s = "";
|
||||||
var_ann_t va = var_ann (var);
|
var_ann_t va = var_ann (var);
|
||||||
unsigned int escape_mask = va->escape_mask;
|
unsigned int escape_mask = va->escape_mask;
|
||||||
|
|
||||||
fprintf (file, ", call clobbered");
|
fprintf (file, ", call clobbered");
|
||||||
fprintf (file, " (");
|
fprintf (file, " (");
|
||||||
if (escape_mask & ESCAPE_STORED_IN_GLOBAL)
|
if (escape_mask & ESCAPE_STORED_IN_GLOBAL)
|
||||||
fprintf (file, ", stored in global");
|
{ fprintf (file, "%sstored in global", s); s = ", "; }
|
||||||
if (escape_mask & ESCAPE_TO_ASM)
|
if (escape_mask & ESCAPE_TO_ASM)
|
||||||
fprintf (file, ", goes through ASM");
|
{ fprintf (file, "%sgoes through ASM", s); s = ", "; }
|
||||||
if (escape_mask & ESCAPE_TO_CALL)
|
if (escape_mask & ESCAPE_TO_CALL)
|
||||||
fprintf (file, ", passed to call");
|
{ fprintf (file, "%spassed to call", s); s = ", "; }
|
||||||
if (escape_mask & ESCAPE_BAD_CAST)
|
if (escape_mask & ESCAPE_BAD_CAST)
|
||||||
fprintf (file, ", bad cast");
|
{ fprintf (file, "%sbad cast", s); s = ", "; }
|
||||||
if (escape_mask & ESCAPE_TO_RETURN)
|
if (escape_mask & ESCAPE_TO_RETURN)
|
||||||
fprintf (file, ", returned from func");
|
{ fprintf (file, "%sreturned from func", s); s = ", "; }
|
||||||
if (escape_mask & ESCAPE_TO_PURE_CONST)
|
if (escape_mask & ESCAPE_TO_PURE_CONST)
|
||||||
fprintf (file, ", passed to pure/const");
|
{ fprintf (file, "%spassed to pure/const", s); s = ", "; }
|
||||||
if (escape_mask & ESCAPE_IS_GLOBAL)
|
if (escape_mask & ESCAPE_IS_GLOBAL)
|
||||||
fprintf (file, ", is global var");
|
{ fprintf (file, "%sis global var", s); s = ", "; }
|
||||||
if (escape_mask & ESCAPE_IS_PARM)
|
if (escape_mask & ESCAPE_IS_PARM)
|
||||||
fprintf (file, ", is incoming pointer");
|
{ fprintf (file, "%sis incoming pointer", s); s = ", "; }
|
||||||
if (escape_mask & ESCAPE_UNKNOWN)
|
if (escape_mask & ESCAPE_UNKNOWN)
|
||||||
fprintf (file, ", unknown escape");
|
{ fprintf (file, "%sunknown escape", s); s = ", "; }
|
||||||
fprintf (file, " )");
|
fprintf (file, ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ann->noalias_state == NO_ALIAS)
|
||||||
|
fprintf (file, ", NO_ALIAS (does not alias other NO_ALIAS symbols)");
|
||||||
|
else if (ann->noalias_state == NO_ALIAS_GLOBAL)
|
||||||
|
fprintf (file, ", NO_ALIAS_GLOBAL (does not alias other NO_ALIAS symbols"
|
||||||
|
" and global vars)");
|
||||||
|
else if (ann->noalias_state == NO_ALIAS_ANYTHING)
|
||||||
|
fprintf (file, ", NO_ALIAS_ANYTHING (does not alias any other symbols)");
|
||||||
|
|
||||||
if (gimple_default_def (cfun, var))
|
if (gimple_default_def (cfun, var))
|
||||||
{
|
{
|
||||||
fprintf (file, ", default def: ");
|
fprintf (file, ", default def: ");
|
||||||
|
@ -618,8 +638,8 @@ referenced_var_lookup (unsigned int uid)
|
||||||
{
|
{
|
||||||
struct int_tree_map *h, in;
|
struct int_tree_map *h, in;
|
||||||
in.uid = uid;
|
in.uid = uid;
|
||||||
h = (struct int_tree_map *) htab_find_with_hash (gimple_referenced_vars (cfun),
|
h = (struct int_tree_map *)
|
||||||
&in, uid);
|
htab_find_with_hash (gimple_referenced_vars (cfun), &in, uid);
|
||||||
gcc_assert (h || uid == 0);
|
gcc_assert (h || uid == 0);
|
||||||
if (h)
|
if (h)
|
||||||
return h->to;
|
return h->to;
|
||||||
|
@ -1011,3 +1031,26 @@ get_ref_base_and_extent (tree exp, HOST_WIDE_INT *poffset,
|
||||||
|
|
||||||
return exp;
|
return exp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return memory reference statistics for variable VAR in function FN.
|
||||||
|
This is computed by alias analysis, but it is not kept
|
||||||
|
incrementally up-to-date. So, these stats are only accurate if
|
||||||
|
pass_may_alias has been run recently. If no alias information
|
||||||
|
exists, this function returns NULL. */
|
||||||
|
|
||||||
|
mem_sym_stats_t
|
||||||
|
mem_sym_stats (struct function *fn, tree var)
|
||||||
|
{
|
||||||
|
void **slot;
|
||||||
|
struct pointer_map_t *stats_map = gimple_mem_ref_stats (fn)->mem_sym_stats;
|
||||||
|
|
||||||
|
if (stats_map == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
slot = pointer_map_contains (stats_map, var);
|
||||||
|
if (slot == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return (mem_sym_stats_t) *slot;
|
||||||
|
}
|
||||||
|
|
|
@ -871,31 +871,6 @@ memory_partition (tree sym)
|
||||||
return tag;
|
return tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Set MPT to be the memory partition associated with symbol SYM. */
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
set_memory_partition (tree sym, tree mpt)
|
|
||||||
{
|
|
||||||
#if defined ENABLE_CHECKING
|
|
||||||
if (mpt)
|
|
||||||
gcc_assert (TREE_CODE (mpt) == MEMORY_PARTITION_TAG
|
|
||||||
&& !is_gimple_reg (sym));
|
|
||||||
#endif
|
|
||||||
var_ann (sym)->mpt = mpt;
|
|
||||||
if (mpt)
|
|
||||||
{
|
|
||||||
bitmap_set_bit (MPT_SYMBOLS (mpt), DECL_UID (sym));
|
|
||||||
|
|
||||||
/* MPT inherits the call-clobbering attributes from SYM. */
|
|
||||||
if (is_call_clobbered (sym))
|
|
||||||
{
|
|
||||||
MTAG_GLOBAL (mpt) = 1;
|
|
||||||
mark_call_clobbered (mpt, ESCAPE_IS_GLOBAL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return true if NAME is a memory factoring SSA name (i.e., an SSA
|
/* Return true if NAME is a memory factoring SSA name (i.e., an SSA
|
||||||
name for a memory partition. */
|
name for a memory partition. */
|
||||||
|
|
||||||
|
@ -1810,4 +1785,11 @@ gimple_ssa_operands (struct function *fun)
|
||||||
{
|
{
|
||||||
return &fun->gimple_df->ssa_operands;
|
return &fun->gimple_df->ssa_operands;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Map describing reference statistics for function FN. */
|
||||||
|
static inline struct mem_ref_stats_d *
|
||||||
|
gimple_mem_ref_stats (struct function *fn)
|
||||||
|
{
|
||||||
|
return &fn->gimple_df->mem_ref_stats;
|
||||||
|
}
|
||||||
#endif /* _TREE_FLOW_INLINE_H */
|
#endif /* _TREE_FLOW_INLINE_H */
|
||||||
|
|
125
gcc/tree-flow.h
125
gcc/tree-flow.h
|
@ -41,10 +41,85 @@ typedef struct basic_block_def *basic_block;
|
||||||
#endif
|
#endif
|
||||||
struct static_var_ann_d;
|
struct static_var_ann_d;
|
||||||
|
|
||||||
|
/* Memory reference statistics for individual memory symbols,
|
||||||
|
collected during alias analysis. */
|
||||||
|
struct mem_sym_stats_d GTY(())
|
||||||
|
{
|
||||||
|
/* Memory symbol. */
|
||||||
|
tree var;
|
||||||
|
|
||||||
|
/* Nonzero if this entry has been assigned a partition. */
|
||||||
|
unsigned int partitioned_p : 1;
|
||||||
|
|
||||||
|
/* Nonzero if VAR is a memory partition tag that already contains
|
||||||
|
call-clobbered variables in its partition set. */
|
||||||
|
unsigned int has_call_clobbered_vars : 1;
|
||||||
|
|
||||||
|
/* Number of direct reference sites. A direct reference to VAR is any
|
||||||
|
reference of the form 'VAR = ' or ' = VAR'. For GIMPLE reg
|
||||||
|
pointers, this is the number of sites where the pointer is
|
||||||
|
dereferenced. */
|
||||||
|
long num_direct_writes;
|
||||||
|
long num_direct_reads;
|
||||||
|
|
||||||
|
/* Number of indirect reference sites. An indirect reference to VAR
|
||||||
|
is any reference via a pointer that contains VAR in its points-to
|
||||||
|
set or, in the case of call-clobbered symbols, a function call. */
|
||||||
|
long num_indirect_writes;
|
||||||
|
long num_indirect_reads;
|
||||||
|
|
||||||
|
/* Execution frequency. This is the sum of the execution
|
||||||
|
frequencies of all the statements that reference this object
|
||||||
|
weighted by the number of references in each statement. This is
|
||||||
|
the main key used to sort the list of symbols to partition.
|
||||||
|
Symbols with high execution frequencies are put at the bottom of
|
||||||
|
the work list (ie, they are partitioned last).
|
||||||
|
Execution frequencies are taken directly from each basic block,
|
||||||
|
so compiling with PGO enabled will increase the precision of this
|
||||||
|
estimate. */
|
||||||
|
long frequency_reads;
|
||||||
|
long frequency_writes;
|
||||||
|
|
||||||
|
/* Set of memory tags that contain VAR in their alias set. */
|
||||||
|
bitmap parent_tags;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct mem_sym_stats_d *mem_sym_stats_t;
|
||||||
|
DEF_VEC_P(mem_sym_stats_t);
|
||||||
|
DEF_VEC_ALLOC_P(mem_sym_stats_t, heap);
|
||||||
|
|
||||||
|
/* Memory reference statistics collected during alias analysis. */
|
||||||
|
struct mem_ref_stats_d GTY(())
|
||||||
|
{
|
||||||
|
/* Number of statements that make memory references. */
|
||||||
|
long num_mem_stmts;
|
||||||
|
|
||||||
|
/* Number of statements that make function calls. */
|
||||||
|
long num_call_sites;
|
||||||
|
|
||||||
|
/* Number of statements that make calls to pure/const functions. */
|
||||||
|
long num_pure_const_call_sites;
|
||||||
|
|
||||||
|
/* Number of ASM statements. */
|
||||||
|
long num_asm_sites;
|
||||||
|
|
||||||
|
/* Estimated number of virtual operands needed as computed by
|
||||||
|
compute_memory_partitions. */
|
||||||
|
long num_vuses;
|
||||||
|
long num_vdefs;
|
||||||
|
|
||||||
|
/* This maps every symbol used to make "memory" references
|
||||||
|
(pointers, arrays, structures, etc) to an instance of struct
|
||||||
|
mem_sym_stats_d describing reference statistics for the symbol. */
|
||||||
|
struct pointer_map_t * GTY((skip)) mem_sym_stats;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/* Gimple dataflow datastructure. All publicly available fields shall have
|
/* Gimple dataflow datastructure. All publicly available fields shall have
|
||||||
gimple_ accessor defined in tree-flow-inline.h, all publicly modifiable
|
gimple_ accessor defined in tree-flow-inline.h, all publicly modifiable
|
||||||
fields should have gimple_set accessor. */
|
fields should have gimple_set accessor. */
|
||||||
struct gimple_df GTY(()) {
|
struct gimple_df GTY(())
|
||||||
|
{
|
||||||
/* Array of all variables referenced in the function. */
|
/* Array of all variables referenced in the function. */
|
||||||
htab_t GTY((param_is (struct int_tree_map))) referenced_vars;
|
htab_t GTY((param_is (struct int_tree_map))) referenced_vars;
|
||||||
|
|
||||||
|
@ -98,6 +173,11 @@ struct gimple_df GTY(()) {
|
||||||
/* Hashtable of variables annotations. Used for static variables only;
|
/* Hashtable of variables annotations. Used for static variables only;
|
||||||
local variables have direct pointer in the tree node. */
|
local variables have direct pointer in the tree node. */
|
||||||
htab_t GTY((param_is (struct static_var_ann_d))) var_anns;
|
htab_t GTY((param_is (struct static_var_ann_d))) var_anns;
|
||||||
|
|
||||||
|
/* Memory reference statistics collected during alias analysis.
|
||||||
|
This information is used to drive the memory partitioning
|
||||||
|
heuristics in compute_memory_partitions. */
|
||||||
|
struct mem_ref_stats_d mem_ref_stats;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Accessors for internal use only. Generic code should use abstraction
|
/* Accessors for internal use only. Generic code should use abstraction
|
||||||
|
@ -205,6 +285,30 @@ enum need_phi_state {
|
||||||
NEED_PHI_STATE_MAYBE
|
NEED_PHI_STATE_MAYBE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* The "no alias" attribute allows alias analysis to make more
|
||||||
|
aggressive assumptions when assigning alias sets, computing
|
||||||
|
points-to information and memory partitions. These attributes
|
||||||
|
are the result of user annotations or flags (e.g.,
|
||||||
|
-fargument-noalias). */
|
||||||
|
enum noalias_state {
|
||||||
|
/* Default state. No special assumptions can be made about this
|
||||||
|
symbol. */
|
||||||
|
MAY_ALIAS = 0,
|
||||||
|
|
||||||
|
/* The symbol does not alias with other symbols that have a
|
||||||
|
NO_ALIAS* attribute. */
|
||||||
|
NO_ALIAS,
|
||||||
|
|
||||||
|
/* The symbol does not alias with other symbols that have a
|
||||||
|
NO_ALIAS*, and it may not alias with global symbols. */
|
||||||
|
NO_ALIAS_GLOBAL,
|
||||||
|
|
||||||
|
/* The symbol does not alias with any other symbols. */
|
||||||
|
NO_ALIAS_ANYTHING
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
struct subvar;
|
struct subvar;
|
||||||
typedef struct subvar *subvar_t;
|
typedef struct subvar *subvar_t;
|
||||||
|
|
||||||
|
@ -246,12 +350,18 @@ struct var_ann_d GTY(())
|
||||||
in the VDEF list. */
|
in the VDEF list. */
|
||||||
unsigned in_vdef_list : 1;
|
unsigned in_vdef_list : 1;
|
||||||
|
|
||||||
/* True for HEAP and PARM_NOALIAS artificial variables. */
|
/* True for HEAP artificial variables. These variables represent
|
||||||
|
the memory area allocated by a call to malloc. */
|
||||||
unsigned is_heapvar : 1;
|
unsigned is_heapvar : 1;
|
||||||
|
|
||||||
/* True if the variable is call clobbered. */
|
/* True if the variable is call clobbered. */
|
||||||
unsigned int call_clobbered : 1;
|
unsigned int call_clobbered : 1;
|
||||||
|
|
||||||
|
/* This field describes several "no alias" attributes that some
|
||||||
|
symbols are known to have. See the enum's definition for more
|
||||||
|
information on each attribute. */
|
||||||
|
ENUM_BITFIELD (noalias_state) noalias_state : 2;
|
||||||
|
|
||||||
/* Memory partition tag assigned to this symbol. */
|
/* Memory partition tag assigned to this symbol. */
|
||||||
tree mpt;
|
tree mpt;
|
||||||
|
|
||||||
|
@ -694,10 +804,10 @@ extern void add_referenced_var (tree);
|
||||||
extern void remove_referenced_var (tree);
|
extern void remove_referenced_var (tree);
|
||||||
extern void mark_symbols_for_renaming (tree);
|
extern void mark_symbols_for_renaming (tree);
|
||||||
extern void find_new_referenced_vars (tree *);
|
extern void find_new_referenced_vars (tree *);
|
||||||
|
|
||||||
extern tree make_rename_temp (tree, const char *);
|
extern tree make_rename_temp (tree, const char *);
|
||||||
extern void set_default_def (tree, tree);
|
extern void set_default_def (tree, tree);
|
||||||
extern tree gimple_default_def (struct function *, tree);
|
extern tree gimple_default_def (struct function *, tree);
|
||||||
|
extern struct mem_sym_stats_d *mem_sym_stats (struct function *, tree);
|
||||||
|
|
||||||
/* In tree-phinodes.c */
|
/* In tree-phinodes.c */
|
||||||
extern void reserve_phi_args_for_new_edge (basic_block);
|
extern void reserve_phi_args_for_new_edge (basic_block);
|
||||||
|
@ -725,7 +835,8 @@ extern bool may_be_aliased (tree);
|
||||||
extern bool is_aliased_with (tree, tree);
|
extern bool is_aliased_with (tree, tree);
|
||||||
extern struct ptr_info_def *get_ptr_info (tree);
|
extern struct ptr_info_def *get_ptr_info (tree);
|
||||||
extern void new_type_alias (tree, tree, tree);
|
extern void new_type_alias (tree, tree, tree);
|
||||||
extern void count_uses_and_derefs (tree, tree, unsigned *, unsigned *, bool *);
|
extern void count_uses_and_derefs (tree, tree, unsigned *, unsigned *,
|
||||||
|
unsigned *);
|
||||||
static inline subvar_t get_subvars_for_var (tree);
|
static inline subvar_t get_subvars_for_var (tree);
|
||||||
static inline tree get_subvar_at (tree, unsigned HOST_WIDE_INT);
|
static inline tree get_subvar_at (tree, unsigned HOST_WIDE_INT);
|
||||||
static inline bool ref_contains_array_ref (tree);
|
static inline bool ref_contains_array_ref (tree);
|
||||||
|
@ -737,6 +848,12 @@ static inline bool overlap_subvar (unsigned HOST_WIDE_INT,
|
||||||
unsigned HOST_WIDE_INT,
|
unsigned HOST_WIDE_INT,
|
||||||
tree, bool *);
|
tree, bool *);
|
||||||
extern tree create_tag_raw (enum tree_code, tree, const char *);
|
extern tree create_tag_raw (enum tree_code, tree, const char *);
|
||||||
|
extern void delete_mem_ref_stats (struct function *);
|
||||||
|
extern void dump_mem_ref_stats (FILE *);
|
||||||
|
extern void debug_mem_ref_stats (void);
|
||||||
|
extern void debug_memory_partitions (void);
|
||||||
|
extern void debug_mem_sym_stats (tree var);
|
||||||
|
extern void debug_all_mem_sym_stats (void);
|
||||||
|
|
||||||
/* Call-back function for walk_use_def_chains(). At each reaching
|
/* Call-back function for walk_use_def_chains(). At each reaching
|
||||||
definition, a function with this prototype is called. */
|
definition, a function with this prototype is called. */
|
||||||
|
|
1285
gcc/tree-ssa-alias.c
1285
gcc/tree-ssa-alias.c
File diff suppressed because it is too large
Load Diff
|
@ -69,17 +69,17 @@ may_propagate_copy (tree dest, tree orig)
|
||||||
&& TREE_CODE (SSA_NAME_VAR (dest)) == MEMORY_PARTITION_TAG)
|
&& TREE_CODE (SSA_NAME_VAR (dest)) == MEMORY_PARTITION_TAG)
|
||||||
return (TREE_CODE (orig) == SSA_NAME
|
return (TREE_CODE (orig) == SSA_NAME
|
||||||
&& !is_gimple_reg (orig)
|
&& !is_gimple_reg (orig)
|
||||||
&& (bitmap_bit_p (MPT_SYMBOLS (SSA_NAME_VAR (dest)),
|
&& (SSA_NAME_VAR (dest) == SSA_NAME_VAR (orig)
|
||||||
DECL_UID (SSA_NAME_VAR (orig)))
|
|| bitmap_bit_p (MPT_SYMBOLS (SSA_NAME_VAR (dest)),
|
||||||
|| SSA_NAME_VAR (dest) == SSA_NAME_VAR (orig)));
|
DECL_UID (SSA_NAME_VAR (orig)))));
|
||||||
|
|
||||||
if (TREE_CODE (orig) == SSA_NAME
|
if (TREE_CODE (orig) == SSA_NAME
|
||||||
&& TREE_CODE (SSA_NAME_VAR (orig)) == MEMORY_PARTITION_TAG)
|
&& TREE_CODE (SSA_NAME_VAR (orig)) == MEMORY_PARTITION_TAG)
|
||||||
return (TREE_CODE (dest) == SSA_NAME
|
return (TREE_CODE (dest) == SSA_NAME
|
||||||
&& !is_gimple_reg (dest)
|
&& !is_gimple_reg (dest)
|
||||||
&& (bitmap_bit_p (MPT_SYMBOLS (SSA_NAME_VAR (orig)),
|
&& (SSA_NAME_VAR (dest) == SSA_NAME_VAR (orig)
|
||||||
DECL_UID (SSA_NAME_VAR (dest)))
|
|| bitmap_bit_p (MPT_SYMBOLS (SSA_NAME_VAR (orig)),
|
||||||
|| SSA_NAME_VAR (dest) == SSA_NAME_VAR (orig)));
|
DECL_UID (SSA_NAME_VAR (dest)))));
|
||||||
|
|
||||||
/* Do not copy between types for which we *do* need a conversion. */
|
/* Do not copy between types for which we *do* need a conversion. */
|
||||||
if (!tree_ssa_useless_type_conversion_1 (type_d, type_o))
|
if (!tree_ssa_useless_type_conversion_1 (type_d, type_o))
|
||||||
|
|
|
@ -2980,89 +2980,3 @@ stmt_references_memory_p (tree stmt)
|
||||||
|
|
||||||
return stmt_ann (stmt)->references_memory;
|
return stmt_ann (stmt)->references_memory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Return the memory partition tag (MPT) associated with memory
|
|
||||||
symbol SYM. From a correctness standpoint, memory partitions can
|
|
||||||
be assigned in any arbitrary fashion as long as this rule is
|
|
||||||
observed: Given two memory partitions MPT.i and MPT.j, they must
|
|
||||||
not contain symbols in common.
|
|
||||||
|
|
||||||
Memory partitions are used when putting the program into Memory-SSA
|
|
||||||
form. In particular, in Memory-SSA PHI nodes are not computed for
|
|
||||||
individual memory symbols. They are computed for memory
|
|
||||||
partitions. This reduces the amount of PHI nodes in the SSA graph
|
|
||||||
at the expense of precision (i.e., it makes unrelated stores affect
|
|
||||||
each other).
|
|
||||||
|
|
||||||
However, it is possible to increase precision by changing this
|
|
||||||
partitioning scheme. For instance, if the partitioning scheme is
|
|
||||||
such that get_mpt_for is the identity function (that is,
|
|
||||||
get_mpt_for (s) = s), this will result in ultimate precision at the
|
|
||||||
expense of huge SSA webs.
|
|
||||||
|
|
||||||
At the other extreme, a partitioning scheme that groups all the
|
|
||||||
symbols in the same set results in minimal SSA webs and almost
|
|
||||||
total loss of precision. */
|
|
||||||
|
|
||||||
tree
|
|
||||||
get_mpt_for (tree sym)
|
|
||||||
{
|
|
||||||
tree mpt;
|
|
||||||
|
|
||||||
/* Don't create a new tag unnecessarily. */
|
|
||||||
mpt = memory_partition (sym);
|
|
||||||
if (mpt == NULL_TREE)
|
|
||||||
{
|
|
||||||
mpt = create_tag_raw (MEMORY_PARTITION_TAG, TREE_TYPE (sym), "MPT");
|
|
||||||
TREE_ADDRESSABLE (mpt) = 0;
|
|
||||||
MTAG_GLOBAL (mpt) = 1;
|
|
||||||
add_referenced_var (mpt);
|
|
||||||
VEC_safe_push (tree, heap, gimple_ssa_operands (cfun)->mpt_table, mpt);
|
|
||||||
MPT_SYMBOLS (mpt) = BITMAP_ALLOC (&operands_bitmap_obstack);
|
|
||||||
set_memory_partition (sym, mpt);
|
|
||||||
}
|
|
||||||
|
|
||||||
return mpt;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Dump memory partition information to FILE. */
|
|
||||||
|
|
||||||
void
|
|
||||||
dump_memory_partitions (FILE *file)
|
|
||||||
{
|
|
||||||
unsigned i, npart;
|
|
||||||
unsigned long nsyms;
|
|
||||||
tree mpt;
|
|
||||||
|
|
||||||
fprintf (file, "\nMemory partitions\n\n");
|
|
||||||
for (i = 0, npart = 0, nsyms = 0;
|
|
||||||
VEC_iterate (tree, gimple_ssa_operands (cfun)->mpt_table, i, mpt);
|
|
||||||
i++)
|
|
||||||
{
|
|
||||||
if (mpt)
|
|
||||||
{
|
|
||||||
bitmap syms = MPT_SYMBOLS (mpt);
|
|
||||||
unsigned long n = bitmap_count_bits (syms);
|
|
||||||
|
|
||||||
fprintf (file, "#%u: ", i);
|
|
||||||
print_generic_expr (file, mpt, 0);
|
|
||||||
fprintf (file, ": %lu elements: ", n);
|
|
||||||
dump_decl_set (file, syms);
|
|
||||||
npart++;
|
|
||||||
nsyms += n;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf (file, "\n%u memory partitions holding %lu symbols\n", npart, nsyms);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Dump memory partition information to stderr. */
|
|
||||||
|
|
||||||
void
|
|
||||||
debug_memory_partitions (void)
|
|
||||||
{
|
|
||||||
dump_memory_partitions (stderr);
|
|
||||||
}
|
|
||||||
|
|
|
@ -357,8 +357,4 @@ typedef struct ssa_operand_iterator_d
|
||||||
/* This macro counts the number of operands in STMT matching FLAGS. */
|
/* This macro counts the number of operands in STMT matching FLAGS. */
|
||||||
#define NUM_SSA_OPERANDS(STMT, FLAGS) num_ssa_operands (STMT, FLAGS)
|
#define NUM_SSA_OPERANDS(STMT, FLAGS) num_ssa_operands (STMT, FLAGS)
|
||||||
|
|
||||||
extern tree get_mpt_for (tree);
|
|
||||||
extern void dump_memory_partitions (FILE *);
|
|
||||||
extern void debug_memory_partitions (void);
|
|
||||||
|
|
||||||
#endif /* GCC_TREE_SSA_OPERANDS_H */
|
#endif /* GCC_TREE_SSA_OPERANDS_H */
|
||||||
|
|
|
@ -3011,15 +3011,21 @@ update_alias_info (tree stmt, struct alias_info *ai)
|
||||||
bitmap addr_taken;
|
bitmap addr_taken;
|
||||||
use_operand_p use_p;
|
use_operand_p use_p;
|
||||||
ssa_op_iter iter;
|
ssa_op_iter iter;
|
||||||
|
bool stmt_dereferences_ptr_p;
|
||||||
enum escape_type stmt_escape_type = is_escape_site (stmt);
|
enum escape_type stmt_escape_type = is_escape_site (stmt);
|
||||||
|
struct mem_ref_stats_d *mem_ref_stats = gimple_mem_ref_stats (cfun);
|
||||||
|
|
||||||
|
stmt_dereferences_ptr_p = false;
|
||||||
|
|
||||||
if (stmt_escape_type == ESCAPE_TO_CALL
|
if (stmt_escape_type == ESCAPE_TO_CALL
|
||||||
|| stmt_escape_type == ESCAPE_TO_PURE_CONST)
|
|| stmt_escape_type == ESCAPE_TO_PURE_CONST)
|
||||||
{
|
{
|
||||||
ai->num_calls_found++;
|
mem_ref_stats->num_call_sites++;
|
||||||
if (stmt_escape_type == ESCAPE_TO_PURE_CONST)
|
if (stmt_escape_type == ESCAPE_TO_PURE_CONST)
|
||||||
ai->num_pure_const_calls_found++;
|
mem_ref_stats->num_pure_const_call_sites++;
|
||||||
}
|
}
|
||||||
|
else if (stmt_escape_type == ESCAPE_TO_ASM)
|
||||||
|
mem_ref_stats->num_asm_sites++;
|
||||||
|
|
||||||
/* Mark all the variables whose address are taken by the statement. */
|
/* Mark all the variables whose address are taken by the statement. */
|
||||||
addr_taken = addresses_taken (stmt);
|
addr_taken = addresses_taken (stmt);
|
||||||
|
@ -3043,17 +3049,15 @@ update_alias_info (tree stmt, struct alias_info *ai)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Process each operand use. If an operand may be aliased, keep
|
/* Process each operand use. For pointers, determine whether they
|
||||||
track of how many times it's being used. For pointers, determine
|
are dereferenced by the statement, or whether their value
|
||||||
whether they are dereferenced by the statement, or whether their
|
escapes, etc. */
|
||||||
value escapes, etc. */
|
|
||||||
FOR_EACH_PHI_OR_STMT_USE (use_p, stmt, iter, SSA_OP_USE)
|
FOR_EACH_PHI_OR_STMT_USE (use_p, stmt, iter, SSA_OP_USE)
|
||||||
{
|
{
|
||||||
tree op, var;
|
tree op, var;
|
||||||
var_ann_t v_ann;
|
var_ann_t v_ann;
|
||||||
struct ptr_info_def *pi;
|
struct ptr_info_def *pi;
|
||||||
bool is_store, is_potential_deref;
|
unsigned num_uses, num_loads, num_stores;
|
||||||
unsigned num_uses, num_derefs;
|
|
||||||
|
|
||||||
op = USE_FROM_PTR (use_p);
|
op = USE_FROM_PTR (use_p);
|
||||||
|
|
||||||
|
@ -3073,12 +3077,11 @@ update_alias_info (tree stmt, struct alias_info *ai)
|
||||||
so that they can be treated like regular statements?
|
so that they can be treated like regular statements?
|
||||||
Currently, they are treated as second-class
|
Currently, they are treated as second-class
|
||||||
statements. */
|
statements. */
|
||||||
add_to_addressable_set (TREE_OPERAND (op, 0),
|
add_to_addressable_set (TREE_OPERAND (op, 0), &addressable_vars);
|
||||||
&addressable_vars);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ignore constants. */
|
/* Ignore constants (they may occur in PHI node arguments). */
|
||||||
if (TREE_CODE (op) != SSA_NAME)
|
if (TREE_CODE (op) != SSA_NAME)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -3109,7 +3112,7 @@ update_alias_info (tree stmt, struct alias_info *ai)
|
||||||
|
|
||||||
/* Determine whether OP is a dereferenced pointer, and if STMT
|
/* Determine whether OP is a dereferenced pointer, and if STMT
|
||||||
is an escape point, whether OP escapes. */
|
is an escape point, whether OP escapes. */
|
||||||
count_uses_and_derefs (op, stmt, &num_uses, &num_derefs, &is_store);
|
count_uses_and_derefs (op, stmt, &num_uses, &num_loads, &num_stores);
|
||||||
|
|
||||||
/* Handle a corner case involving address expressions of the
|
/* Handle a corner case involving address expressions of the
|
||||||
form '&PTR->FLD'. The problem with these expressions is that
|
form '&PTR->FLD'. The problem with these expressions is that
|
||||||
|
@ -3132,7 +3135,6 @@ update_alias_info (tree stmt, struct alias_info *ai)
|
||||||
are not GIMPLE invariants), they can only appear on the RHS
|
are not GIMPLE invariants), they can only appear on the RHS
|
||||||
of an assignment and their base address is always an
|
of an assignment and their base address is always an
|
||||||
INDIRECT_REF expression. */
|
INDIRECT_REF expression. */
|
||||||
is_potential_deref = false;
|
|
||||||
if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT
|
if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT
|
||||||
&& TREE_CODE (GIMPLE_STMT_OPERAND (stmt, 1)) == ADDR_EXPR
|
&& TREE_CODE (GIMPLE_STMT_OPERAND (stmt, 1)) == ADDR_EXPR
|
||||||
&& !is_gimple_val (GIMPLE_STMT_OPERAND (stmt, 1)))
|
&& !is_gimple_val (GIMPLE_STMT_OPERAND (stmt, 1)))
|
||||||
|
@ -3143,10 +3145,10 @@ update_alias_info (tree stmt, struct alias_info *ai)
|
||||||
tree base = get_base_address (TREE_OPERAND (rhs, 0));
|
tree base = get_base_address (TREE_OPERAND (rhs, 0));
|
||||||
if (TREE_CODE (base) == INDIRECT_REF
|
if (TREE_CODE (base) == INDIRECT_REF
|
||||||
&& TREE_OPERAND (base, 0) == op)
|
&& TREE_OPERAND (base, 0) == op)
|
||||||
is_potential_deref = true;
|
num_loads++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (num_derefs > 0 || is_potential_deref)
|
if (num_loads + num_stores > 0)
|
||||||
{
|
{
|
||||||
/* Mark OP as dereferenced. In a subsequent pass,
|
/* Mark OP as dereferenced. In a subsequent pass,
|
||||||
dereferenced pointers that point to a set of
|
dereferenced pointers that point to a set of
|
||||||
|
@ -3157,13 +3159,20 @@ update_alias_info (tree stmt, struct alias_info *ai)
|
||||||
/* If this is a store operation, mark OP as being
|
/* If this is a store operation, mark OP as being
|
||||||
dereferenced to store, otherwise mark it as being
|
dereferenced to store, otherwise mark it as being
|
||||||
dereferenced to load. */
|
dereferenced to load. */
|
||||||
if (is_store)
|
if (num_stores > 0)
|
||||||
pointer_set_insert (ai->dereferenced_ptrs_store, var);
|
pointer_set_insert (ai->dereferenced_ptrs_store, var);
|
||||||
else
|
else
|
||||||
pointer_set_insert (ai->dereferenced_ptrs_load, var);
|
pointer_set_insert (ai->dereferenced_ptrs_load, var);
|
||||||
|
|
||||||
|
/* Update the frequency estimate for all the dereferences of
|
||||||
|
pointer OP. */
|
||||||
|
update_mem_sym_stats_from_stmt (op, stmt, num_loads, num_stores);
|
||||||
|
|
||||||
|
/* Indicate that STMT contains pointer dereferences. */
|
||||||
|
stmt_dereferences_ptr_p = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stmt_escape_type != NO_ESCAPE && num_derefs < num_uses)
|
if (stmt_escape_type != NO_ESCAPE && num_loads + num_stores < num_uses)
|
||||||
{
|
{
|
||||||
/* If STMT is an escape point and STMT contains at
|
/* If STMT is an escape point and STMT contains at
|
||||||
least one direct use of OP, then the value of OP
|
least one direct use of OP, then the value of OP
|
||||||
|
@ -3188,13 +3197,55 @@ update_alias_info (tree stmt, struct alias_info *ai)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Mark stored variables in STMT as being written to and update the
|
/* Mark stored variables in STMT as being written to and update the
|
||||||
reference counter for potentially aliased symbols in STMT. */
|
memory reference stats for all memory symbols referenced by STMT. */
|
||||||
if (stmt_references_memory_p (stmt) && STORED_SYMS (stmt))
|
if (stmt_references_memory_p (stmt))
|
||||||
{
|
{
|
||||||
unsigned i;
|
unsigned i;
|
||||||
bitmap_iterator bi;
|
bitmap_iterator bi;
|
||||||
EXECUTE_IF_SET_IN_BITMAP (STORED_SYMS (stmt), 0, i, bi)
|
|
||||||
pointer_set_insert (ai->written_vars, referenced_var (i));
|
mem_ref_stats->num_mem_stmts++;
|
||||||
|
|
||||||
|
/* Notice that we only update memory reference stats for symbols
|
||||||
|
loaded and stored by the statement if the statement does not
|
||||||
|
contain pointer dereferences and it is not a call/asm site.
|
||||||
|
This is to avoid double accounting problems when creating
|
||||||
|
memory partitions. After computing points-to information,
|
||||||
|
pointer dereference statistics are used to update the
|
||||||
|
reference stats of the pointed-to variables, so here we
|
||||||
|
should only update direct references to symbols.
|
||||||
|
|
||||||
|
Indirect references are not updated here for two reasons: (1)
|
||||||
|
The first time we compute alias information, the sets
|
||||||
|
LOADED/STORED are empty for pointer dereferences, (2) After
|
||||||
|
partitioning, LOADED/STORED may have references to
|
||||||
|
partitions, not the original pointed-to variables. So, if we
|
||||||
|
always counted LOADED/STORED here and during partitioning, we
|
||||||
|
would count many symbols more than once.
|
||||||
|
|
||||||
|
This does cause some imprecision when a statement has a
|
||||||
|
combination of direct symbol references and pointer
|
||||||
|
dereferences (e.g., MEMORY_VAR = *PTR) or if a call site has
|
||||||
|
memory symbols in its argument list, but these cases do not
|
||||||
|
occur so frequently as to constitue a serious problem. */
|
||||||
|
if (STORED_SYMS (stmt))
|
||||||
|
EXECUTE_IF_SET_IN_BITMAP (STORED_SYMS (stmt), 0, i, bi)
|
||||||
|
{
|
||||||
|
tree sym = referenced_var (i);
|
||||||
|
pointer_set_insert (ai->written_vars, sym);
|
||||||
|
if (!stmt_dereferences_ptr_p
|
||||||
|
&& stmt_escape_type != ESCAPE_TO_CALL
|
||||||
|
&& stmt_escape_type != ESCAPE_TO_PURE_CONST
|
||||||
|
&& stmt_escape_type != ESCAPE_TO_ASM)
|
||||||
|
update_mem_sym_stats_from_stmt (sym, stmt, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!stmt_dereferences_ptr_p
|
||||||
|
&& LOADED_SYMS (stmt)
|
||||||
|
&& stmt_escape_type != ESCAPE_TO_CALL
|
||||||
|
&& stmt_escape_type != ESCAPE_TO_PURE_CONST
|
||||||
|
&& stmt_escape_type != ESCAPE_TO_ASM)
|
||||||
|
EXECUTE_IF_SET_IN_BITMAP (LOADED_SYMS (stmt), 0, i, bi)
|
||||||
|
update_mem_sym_stats_from_stmt (referenced_var (i), stmt, 1, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4108,11 +4159,11 @@ intra_create_variable_infos (void)
|
||||||
if (!could_have_pointers (t))
|
if (!could_have_pointers (t))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* With flag_argument_noalias greater than two means that the incoming
|
/* If flag_argument_noalias is set, then function pointer
|
||||||
argument cannot alias anything except for itself so create a HEAP
|
arguments are guaranteed not to point to each other. In that
|
||||||
variable. */
|
case, create an artificial variable PARM_NOALIAS and the
|
||||||
if (POINTER_TYPE_P (TREE_TYPE (t))
|
constraint ARG = &PARM_NOALIAS. */
|
||||||
&& flag_argument_noalias > 2)
|
if (POINTER_TYPE_P (TREE_TYPE (t)) && flag_argument_noalias > 0)
|
||||||
{
|
{
|
||||||
varinfo_t vi;
|
varinfo_t vi;
|
||||||
tree heapvar = heapvar_lookup (t);
|
tree heapvar = heapvar_lookup (t);
|
||||||
|
@ -4123,14 +4174,26 @@ intra_create_variable_infos (void)
|
||||||
|
|
||||||
if (heapvar == NULL_TREE)
|
if (heapvar == NULL_TREE)
|
||||||
{
|
{
|
||||||
|
var_ann_t ann;
|
||||||
heapvar = create_tmp_var_raw (TREE_TYPE (TREE_TYPE (t)),
|
heapvar = create_tmp_var_raw (TREE_TYPE (TREE_TYPE (t)),
|
||||||
"PARM_NOALIAS");
|
"PARM_NOALIAS");
|
||||||
get_var_ann (heapvar)->is_heapvar = 1;
|
|
||||||
DECL_EXTERNAL (heapvar) = 1;
|
DECL_EXTERNAL (heapvar) = 1;
|
||||||
if (gimple_referenced_vars (cfun))
|
if (gimple_referenced_vars (cfun))
|
||||||
add_referenced_var (heapvar);
|
add_referenced_var (heapvar);
|
||||||
|
|
||||||
heapvar_insert (t, heapvar);
|
heapvar_insert (t, heapvar);
|
||||||
|
|
||||||
|
ann = get_var_ann (heapvar);
|
||||||
|
if (flag_argument_noalias == 1)
|
||||||
|
ann->noalias_state = NO_ALIAS;
|
||||||
|
else if (flag_argument_noalias == 2)
|
||||||
|
ann->noalias_state = NO_ALIAS_GLOBAL;
|
||||||
|
else if (flag_argument_noalias == 3)
|
||||||
|
ann->noalias_state = NO_ALIAS_ANYTHING;
|
||||||
|
else
|
||||||
|
gcc_unreachable ();
|
||||||
}
|
}
|
||||||
|
|
||||||
vi = get_vi_for_tree (heapvar);
|
vi = get_vi_for_tree (heapvar);
|
||||||
vi->is_artificial_var = 1;
|
vi->is_artificial_var = 1;
|
||||||
vi->is_heap_var = 1;
|
vi->is_heap_var = 1;
|
||||||
|
|
|
@ -49,12 +49,6 @@ struct alias_info
|
||||||
struct alias_map_d **pointers;
|
struct alias_map_d **pointers;
|
||||||
size_t num_pointers;
|
size_t num_pointers;
|
||||||
|
|
||||||
/* Number of function calls found in the program. */
|
|
||||||
size_t num_calls_found;
|
|
||||||
|
|
||||||
/* Number of const/pure function calls found in the program. */
|
|
||||||
size_t num_pure_const_calls_found;
|
|
||||||
|
|
||||||
/* Variables that have been written to directly (i.e., not through a
|
/* Variables that have been written to directly (i.e., not through a
|
||||||
pointer dereference). */
|
pointer dereference). */
|
||||||
struct pointer_set_t *written_vars;
|
struct pointer_set_t *written_vars;
|
||||||
|
@ -71,6 +65,7 @@ struct alias_info
|
||||||
|
|
||||||
/* In tree-ssa-alias.c. */
|
/* In tree-ssa-alias.c. */
|
||||||
enum escape_type is_escape_site (tree);
|
enum escape_type is_escape_site (tree);
|
||||||
|
void update_mem_sym_stats_from_stmt (tree, tree, long, long);
|
||||||
|
|
||||||
/* In tree-ssa-structalias.c. */
|
/* In tree-ssa-structalias.c. */
|
||||||
extern void compute_points_to_sets (struct alias_info *);
|
extern void compute_points_to_sets (struct alias_info *);
|
||||||
|
|
|
@ -538,6 +538,51 @@ verify_call_clobbering (void)
|
||||||
internal_error ("verify_call_clobbering failed");
|
internal_error ("verify_call_clobbering failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Verify invariants in memory partitions. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
verify_memory_partitions (void)
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
tree mpt;
|
||||||
|
VEC(tree,heap) *mpt_table = gimple_ssa_operands (cfun)->mpt_table;
|
||||||
|
struct pointer_set_t *partitioned_syms = pointer_set_create ();
|
||||||
|
|
||||||
|
for (i = 0; VEC_iterate (tree, mpt_table, i, mpt); i++)
|
||||||
|
{
|
||||||
|
unsigned j;
|
||||||
|
bitmap_iterator bj;
|
||||||
|
|
||||||
|
if (MPT_SYMBOLS (mpt) == NULL)
|
||||||
|
{
|
||||||
|
error ("Memory partitions should have at least one symbol");
|
||||||
|
debug_variable (mpt);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXECUTE_IF_SET_IN_BITMAP (MPT_SYMBOLS (mpt), 0, j, bj)
|
||||||
|
{
|
||||||
|
tree var = referenced_var (j);
|
||||||
|
if (pointer_set_insert (partitioned_syms, var))
|
||||||
|
{
|
||||||
|
error ("Partitioned symbols should belong to exactly one "
|
||||||
|
"partition");
|
||||||
|
debug_variable (var);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pointer_set_destroy (partitioned_syms);
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
err:
|
||||||
|
internal_error ("verify_memory_partitions failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Verify the consistency of aliasing information. */
|
/* Verify the consistency of aliasing information. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -546,6 +591,7 @@ verify_alias_info (void)
|
||||||
verify_flow_sensitive_alias_info ();
|
verify_flow_sensitive_alias_info ();
|
||||||
verify_call_clobbering ();
|
verify_call_clobbering ();
|
||||||
verify_flow_insensitive_alias_info ();
|
verify_flow_insensitive_alias_info ();
|
||||||
|
verify_memory_partitions ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -835,6 +881,7 @@ delete_tree_ssa (void)
|
||||||
gcc_assert (!need_ssa_update_p ());
|
gcc_assert (!need_ssa_update_p ());
|
||||||
}
|
}
|
||||||
cfun->gimple_df->aliases_computed_p = false;
|
cfun->gimple_df->aliases_computed_p = false;
|
||||||
|
delete_mem_ref_stats (cfun);
|
||||||
|
|
||||||
cfun->gimple_df = NULL;
|
cfun->gimple_df = NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3121,11 +3121,10 @@ infer_value_range (tree stmt, tree op, enum tree_code *comp_code_p, tree *val_p)
|
||||||
non-NULL if -fdelete-null-pointer-checks is enabled. */
|
non-NULL if -fdelete-null-pointer-checks is enabled. */
|
||||||
if (flag_delete_null_pointer_checks && POINTER_TYPE_P (TREE_TYPE (op)))
|
if (flag_delete_null_pointer_checks && POINTER_TYPE_P (TREE_TYPE (op)))
|
||||||
{
|
{
|
||||||
bool is_store;
|
unsigned num_uses, num_loads, num_stores;
|
||||||
unsigned num_uses, num_derefs;
|
|
||||||
|
|
||||||
count_uses_and_derefs (op, stmt, &num_uses, &num_derefs, &is_store);
|
count_uses_and_derefs (op, stmt, &num_uses, &num_loads, &num_stores);
|
||||||
if (num_derefs > 0)
|
if (num_loads + num_stores > 0)
|
||||||
{
|
{
|
||||||
*val_p = build_int_cst (TREE_TYPE (op), 0);
|
*val_p = build_int_cst (TREE_TYPE (op), 0);
|
||||||
*comp_code_p = NE_EXPR;
|
*comp_code_p = NE_EXPR;
|
||||||
|
|
Loading…
Reference in New Issue