#include "gimple.h"
#include "tree-flow.h"
#include "diagnostic.h"
+#include "statistics.h"
#include "tree-dump.h"
#include "timevar.h"
#include "params.h"
representative fields are dumped, otherwise those which only describe the
individual access are. */
+static struct
+{
+ /* Number of created scalar replacements. */
+ int replacements;
+
+ /* Number of times sra_modify_expr or sra_modify_assign themselves changed an
+ expression. */
+ int exprs;
+
+ /* Number of statements created by generate_subtree_copies. */
+ int subtree_copies;
+
+ /* Number of statements created by load_assign_lhs_subreplacements. */
+ int subreplacements;
+
+ /* Number of times sra_modify_assign has deleted a statement. */
+ int deleted;
+
+ /* Number of times sra_modify_assign has to deal with subaccesses of LHS and
+ RHS reparately due to type conversions or nonexistent matching
+ references. */
+ int separate_lhs_rhs_handling;
+
+ /* Number of processed aggregates is readily available in
+ analyze_all_variable_accesses and so is not stored here. */
+} sra_stats;
+
static void
dump_access (FILE *f, struct access *access, bool grp)
{
access_pool = create_alloc_pool ("SRA accesses", sizeof (struct access), 16);
link_pool = create_alloc_pool ("SRA links", sizeof (struct assign_link), 16);
base_access_vec = pointer_map_create ();
+ memset (&sra_stats, 0, sizeof (sra_stats));
}
/* Hook fed to pointer_map_traverse, deallocate stored vectors. */
HOST_WIDE_INT el_size;
if (offset == 0 && exp_type
- && useless_type_conversion_p (exp_type, type))
+ && types_compatible_p (exp_type, type))
return true;
switch (TREE_CODE (type))
print_generic_expr (dump_file, repl, 0);
fprintf (dump_file, "\n");
}
+ sra_stats.replacements++;
return repl;
}
{
gcc_assert (access->grp_to_be_replaced);
- if (access->replacement_decl)
- return access->replacement_decl;
-
- access->replacement_decl = create_access_replacement (access);
+ if (!access->replacement_decl)
+ access->replacement_decl = create_access_replacement (access);
return access->replacement_decl;
}
continue;
}
- /* If a (part of) a union field in on the RHS of an assignment, it can
+ /* If a (part of) a union field is on the RHS of an assignment, it can
have sub-accesses which do not make sense on the LHS (PR 40351).
Check that this is not the case. */
if (!build_ref_for_offset (NULL, TREE_TYPE (lacc->base), norm_offset,
{
tree var;
referenced_var_iterator rvi;
- bool res = false;
+ int res = 0;
FOR_EACH_REFERENCED_VAR (var, rvi)
if (bitmap_bit_p (candidate_bitmap, DECL_UID (var)))
if (analyze_access_trees (access))
{
- res = true;
+ res++;
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "\nAccess trees for ");
disqualify_candidate (var, "No scalar replacements to be created.");
}
- return res;
+ if (res)
+ {
+ statistics_counter_event (cfun, "Scalarized aggregates", res);
+ return true;
+ }
+ else
+ return false;
}
/* Return true iff a reference statement into aggregate AGG can be built for
else
gsi_insert_before (gsi, stmt, GSI_SAME_STMT);
update_stmt (stmt);
+ sra_stats.subtree_copies++;
}
if (access->first_child)
gcc_assert (useless_type_conversion_p (type, access->type));
*expr = repl;
}
+ sra_stats.exprs++;
}
if (access->first_child)
&& host_integerp (TREE_OPERAND (bfr, 1), 1)
&& host_integerp (TREE_OPERAND (bfr, 2), 1))
{
- start_offset = tree_low_cst (TREE_OPERAND (bfr, 1), 1);
- chunk_size = tree_low_cst (TREE_OPERAND (bfr, 2), 1);
+ chunk_size = tree_low_cst (TREE_OPERAND (bfr, 1), 1);
+ start_offset = access->offset
+ + tree_low_cst (TREE_OPERAND (bfr, 2), 1);
}
else
start_offset = chunk_size = 0;
return true;
}
+/* Where scalar replacements of the RHS have been written to when a replacement
+ of a LHS of an assigments cannot be direclty loaded from a replacement of
+ the RHS. */
+enum unscalarized_data_handling { SRA_UDH_NONE, /* Nothing done so far. */
+ SRA_UDH_RIGHT, /* Data flushed to the RHS. */
+ SRA_UDH_LEFT }; /* Data flushed to the LHS. */
+
/* Store all replacements in the access tree rooted in TOP_RACC either to their
base aggregate if there are unscalarized data or directly to LHS
otherwise. */
-static void
+static enum unscalarized_data_handling
handle_unscalarized_data_in_subtree (struct access *top_racc, tree lhs,
gimple_stmt_iterator *gsi)
{
if (top_racc->grp_unscalarized_data)
- generate_subtree_copies (top_racc->first_child, top_racc->base, 0, 0, 0,
- gsi, false, false);
+ {
+ generate_subtree_copies (top_racc->first_child, top_racc->base, 0, 0, 0,
+ gsi, false, false);
+ return SRA_UDH_RIGHT;
+ }
else
- generate_subtree_copies (top_racc->first_child, lhs, top_racc->offset,
- 0, 0, gsi, false, false);
+ {
+ generate_subtree_copies (top_racc->first_child, lhs, top_racc->offset,
+ 0, 0, gsi, false, false);
+ return SRA_UDH_LEFT;
+ }
}
HOST_WIDE_INT right_offset,
gimple_stmt_iterator *old_gsi,
gimple_stmt_iterator *new_gsi,
- bool *refreshed, tree lhs)
+ enum unscalarized_data_handling *refreshed,
+ tree lhs)
{
do
{
/* No suitable access on the right hand side, need to load from
the aggregate. See if we have to update it first... */
- if (!*refreshed)
+ if (*refreshed == SRA_UDH_NONE)
+ *refreshed = handle_unscalarized_data_in_subtree (top_racc,
+ lhs, old_gsi);
+
+ if (*refreshed == SRA_UDH_LEFT)
+ rhs = unshare_expr (lacc->expr);
+ else
{
- gcc_assert (top_racc->first_child);
- handle_unscalarized_data_in_subtree (top_racc, lhs, old_gsi);
- *refreshed = true;
+ rhs = unshare_expr (top_racc->base);
+ repl_found = build_ref_for_offset (&rhs,
+ TREE_TYPE (top_racc->base),
+ offset, lacc->type, false);
+ gcc_assert (repl_found);
}
-
- rhs = unshare_expr (top_racc->base);
- repl_found = build_ref_for_offset (&rhs,
- TREE_TYPE (top_racc->base),
- lacc->offset - left_offset,
- lacc->type, false);
- gcc_assert (repl_found);
}
stmt = gimple_build_assign (get_access_replacement (lacc), rhs);
gsi_insert_after (new_gsi, stmt, GSI_NEW_STMT);
update_stmt (stmt);
+ sra_stats.subreplacements++;
}
- else if (lacc->grp_read && !lacc->grp_covered && !*refreshed)
- {
- handle_unscalarized_data_in_subtree (top_racc, lhs, old_gsi);
- *refreshed = true;
- }
+ else if (*refreshed == SRA_UDH_NONE
+ && lacc->grp_read && !lacc->grp_covered)
+ *refreshed = handle_unscalarized_data_in_subtree (top_racc, lhs,
+ old_gsi);
if (lacc->first_child)
load_assign_lhs_subreplacements (lacc->first_child, top_racc,
modify_this_stmt = true;
if (lacc->grp_partial_lhs)
force_gimple_rhs = true;
+ sra_stats.exprs++;
}
if (racc && racc->grp_to_be_replaced)
modify_this_stmt = true;
if (racc->grp_partial_lhs)
force_gimple_rhs = true;
+ sra_stats.exprs++;
}
if (modify_this_stmt)
&& !access_has_children_p (lacc))
{
tree expr = unshare_expr (lhs);
- if (build_ref_for_offset (&expr, TREE_TYPE (lhs), racc->offset,
+ if (build_ref_for_offset (&expr, TREE_TYPE (lhs), 0,
TREE_TYPE (rhs), false))
{
lhs = expr;
&& !access_has_children_p (racc))
{
tree expr = unshare_expr (rhs);
- if (build_ref_for_offset (&expr, TREE_TYPE (rhs), lacc->offset,
+ if (build_ref_for_offset (&expr, TREE_TYPE (rhs), 0,
TREE_TYPE (lhs), false))
rhs = expr;
}
if (!useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (rhs)))
- rhs = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (lhs), rhs);
+ {
+ rhs = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (lhs), rhs);
+ if (!is_gimple_reg (lhs))
+ force_gimple_rhs = true;
+ }
}
if (force_gimple_rhs)
if (access_has_children_p (lacc))
generate_subtree_copies (lacc->first_child, lacc->base, 0, 0, 0,
gsi, true, true);
+ sra_stats.separate_lhs_rhs_handling++;
}
else
{
if (access_has_children_p (lacc) && access_has_children_p (racc))
{
gimple_stmt_iterator orig_gsi = *gsi;
- bool refreshed;
+ enum unscalarized_data_handling refreshed;
if (lacc->grp_read && !lacc->grp_covered)
- {
- handle_unscalarized_data_in_subtree (racc, lhs, gsi);
- refreshed = true;
- }
+ refreshed = handle_unscalarized_data_in_subtree (racc, lhs, gsi);
else
- refreshed = false;
+ refreshed = SRA_UDH_NONE;
load_assign_lhs_subreplacements (lacc->first_child, racc,
lacc->offset, racc->offset,
&orig_gsi, gsi, &refreshed, lhs);
- if (!refreshed || !racc->grp_unscalarized_data)
+ if (refreshed != SRA_UDH_RIGHT)
{
if (*stmt == gsi_stmt (*gsi))
gsi_next (gsi);
unlink_stmt_vdef (*stmt);
gsi_remove (&orig_gsi, true);
+ sra_stats.deleted++;
return SRA_SA_REMOVED;
}
}
gcc_assert (*stmt == gsi_stmt (*gsi));
unlink_stmt_vdef (*stmt);
gsi_remove (gsi, true);
+ sra_stats.deleted++;
return SRA_SA_REMOVED;
}
else
scan_function (sra_modify_expr, sra_modify_assign, NULL,
false, NULL);
initialize_parameter_reductions ();
+
+ statistics_counter_event (cfun, "Scalar replacements created",
+ sra_stats.replacements);
+ statistics_counter_event (cfun, "Modified expressions", sra_stats.exprs);
+ statistics_counter_event (cfun, "Subtree copy stmts",
+ sra_stats.subtree_copies);
+ statistics_counter_event (cfun, "Subreplacement stmts",
+ sra_stats.subreplacements);
+ statistics_counter_event (cfun, "Deleted stmts", sra_stats.deleted);
+ statistics_counter_event (cfun, "Separate LHS and RHS handling",
+ sra_stats.separate_lhs_rhs_handling);
+
ret = TODO_update_ssa;
out: