summaryrefslogtreecommitdiff
path: root/gcc/tree-sra.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/tree-sra.c')
-rw-r--r--gcc/tree-sra.c178
1 files changed, 162 insertions, 16 deletions
diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c
index 5acb6125079..bf1a0f209f6 100644
--- a/gcc/tree-sra.c
+++ b/gcc/tree-sra.c
@@ -1,7 +1,7 @@
/* Scalar Replacement of Aggregates (SRA) converts some structure
references into scalar references, exposing them to the scalar
optimizers.
- Copyright (C) 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+ Copyright (C) 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
Contributed by Martin Jambor <mjambor@suse.cz>
This file is part of GCC.
@@ -227,6 +227,10 @@ struct access
/* Set when a scalar replacement should be created for this variable. */
unsigned grp_to_be_replaced : 1;
+ /* Set when we want a replacement for the sole purpose of having it in
+ generated debug statements. */
+ unsigned grp_to_be_debug_replaced : 1;
+
/* Should TREE_NO_WARNING of a replacement be set? */
unsigned grp_no_warning : 1;
@@ -390,7 +394,7 @@ dump_access (FILE *f, struct access *access, bool grp)
"grp_hint = %d, grp_covered = %d, "
"grp_unscalarizable_region = %d, grp_unscalarized_data = %d, "
"grp_partial_lhs = %d, grp_to_be_replaced = %d, "
- "grp_maybe_modified = %d, "
+ "grp_to_be_debug_replaced = %d, grp_maybe_modified = %d, "
"grp_not_necessarilly_dereferenced = %d\n",
access->grp_read, access->grp_write, access->grp_assignment_read,
access->grp_assignment_write, access->grp_scalar_read,
@@ -398,7 +402,7 @@ dump_access (FILE *f, struct access *access, bool grp)
access->grp_hint, access->grp_covered,
access->grp_unscalarizable_region, access->grp_unscalarized_data,
access->grp_partial_lhs, access->grp_to_be_replaced,
- access->grp_maybe_modified,
+ access->grp_to_be_debug_replaced, access->grp_maybe_modified,
access->grp_not_necessarilly_dereferenced);
else
fprintf (f, ", write = %d, grp_total_scalarization = %d, "
@@ -1528,6 +1532,43 @@ build_ref_for_model (location_t loc, tree base, HOST_WIDE_INT offset,
gsi, insert_after);
}
+/* Attempt to build a memory reference that we could but into a gimple
+ debug_bind statement. Similar to build_ref_for_model but punts if it has to
+ create statements and return s NULL instead. This function also ignores
+ alignment issues and so its results should never end up in non-debug
+ statements. */
+
+static tree
+build_debug_ref_for_model (location_t loc, tree base, HOST_WIDE_INT offset,
+ struct access *model)
+{
+ HOST_WIDE_INT base_offset;
+ tree off;
+
+ if (TREE_CODE (model->expr) == COMPONENT_REF
+ && DECL_BIT_FIELD (TREE_OPERAND (model->expr, 1)))
+ return NULL_TREE;
+
+ base = get_addr_base_and_unit_offset (base, &base_offset);
+ if (!base)
+ return NULL_TREE;
+ if (TREE_CODE (base) == MEM_REF)
+ {
+ off = build_int_cst (TREE_TYPE (TREE_OPERAND (base, 1)),
+ base_offset + offset / BITS_PER_UNIT);
+ off = int_const_binop (PLUS_EXPR, TREE_OPERAND (base, 1), off);
+ base = unshare_expr (TREE_OPERAND (base, 0));
+ }
+ else
+ {
+ off = build_int_cst (reference_alias_ptr_type (base),
+ base_offset + offset / BITS_PER_UNIT);
+ base = build_fold_addr_expr (unshare_expr (base));
+ }
+
+ return fold_build2_loc (loc, MEM_REF, model->type, base, off);
+}
+
/* Construct a memory reference consisting of component_refs and array_refs to
a part of an aggregate *RES (which is of type TYPE). The requested part
should have type EXP_TYPE at be the given OFFSET. This function might not
@@ -1861,7 +1902,13 @@ create_access_replacement (struct access *access)
{
tree repl;
- repl = create_tmp_var (access->type, "SR");
+ if (access->grp_to_be_debug_replaced)
+ {
+ repl = create_tmp_var_raw (access->type, NULL);
+ DECL_CONTEXT (repl) = current_function_decl;
+ }
+ else
+ repl = create_tmp_var (access->type, "SR");
if (TREE_CODE (access->type) == COMPLEX_TYPE
|| TREE_CODE (access->type) == VECTOR_TYPE)
{
@@ -1894,7 +1941,8 @@ create_access_replacement (struct access *access)
and that get_ref_base_and_extent works properly on the
expression. It cannot handle accesses at a non-constant offset
though, so just give up in those cases. */
- for (d = debug_expr; !fail && handled_component_p (d);
+ for (d = debug_expr;
+ !fail && (handled_component_p (d) || TREE_CODE (d) == MEM_REF);
d = TREE_OPERAND (d, 0))
switch (TREE_CODE (d))
{
@@ -1912,6 +1960,12 @@ create_access_replacement (struct access *access)
&& TREE_CODE (TREE_OPERAND (d, 2)) != INTEGER_CST)
fail = true;
break;
+ case MEM_REF:
+ if (TREE_CODE (TREE_OPERAND (d, 0)) != ADDR_EXPR)
+ fail = true;
+ else
+ d = TREE_OPERAND (d, 0);
+ break;
default:
break;
}
@@ -1930,12 +1984,22 @@ create_access_replacement (struct access *access)
if (dump_file)
{
- fprintf (dump_file, "Created a replacement for ");
- print_generic_expr (dump_file, access->base, 0);
- fprintf (dump_file, " offset: %u, size: %u: ",
- (unsigned) access->offset, (unsigned) access->size);
- print_generic_expr (dump_file, repl, 0);
- fprintf (dump_file, "\n");
+ if (access->grp_to_be_debug_replaced)
+ {
+ fprintf (dump_file, "Created a debug-only replacement for ");
+ print_generic_expr (dump_file, access->base, 0);
+ fprintf (dump_file, " offset: %u, size: %u\n",
+ (unsigned) access->offset, (unsigned) access->size);
+ }
+ else
+ {
+ fprintf (dump_file, "Created a replacement for ");
+ print_generic_expr (dump_file, access->base, 0);
+ fprintf (dump_file, " offset: %u, size: %u: ",
+ (unsigned) access->offset, (unsigned) access->size);
+ print_generic_expr (dump_file, repl, 0);
+ fprintf (dump_file, "\n");
+ }
}
sra_stats.replacements++;
@@ -2144,6 +2208,23 @@ analyze_access_subtree (struct access *root, struct access *parent,
}
else
{
+ if (MAY_HAVE_DEBUG_STMTS && allow_replacements
+ && scalar && !root->first_child
+ && (root->grp_scalar_write || root->grp_assignment_write))
+ {
+ gcc_checking_assert (!root->grp_scalar_read
+ && !root->grp_assignment_read);
+ root->grp_to_be_debug_replaced = 1;
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "Marking ");
+ print_generic_expr (dump_file, root->base, 0);
+ fprintf (dump_file, " offset: %u, size: %u ",
+ (unsigned) root->offset, (unsigned) root->size);
+ fprintf (dump_file, " to be replaced with debug statements.\n");
+ }
+ }
+
if (covered_to < limit)
hole = true;
if (scalar)
@@ -2504,6 +2585,22 @@ generate_subtree_copies (struct access *access, tree agg,
update_stmt (stmt);
sra_stats.subtree_copies++;
}
+ else if (write
+ && access->grp_to_be_debug_replaced
+ && (chunk_size == 0
+ || access->offset + access->size > start_offset))
+ {
+ gimple ds;
+ tree drhs = build_debug_ref_for_model (loc, agg,
+ access->offset - top_offset,
+ access);
+ ds = gimple_build_debug_bind (get_access_replacement (access),
+ drhs, gsi_stmt (*gsi));
+ if (insert_after)
+ gsi_insert_after (gsi, ds, GSI_NEW_STMT);
+ else
+ gsi_insert_before (gsi, ds, GSI_SAME_STMT);
+ }
if (access->first_child)
generate_subtree_copies (access->first_child, agg, top_offset,
@@ -2540,6 +2637,16 @@ init_subtree_with_zero (struct access *access, gimple_stmt_iterator *gsi,
update_stmt (stmt);
gimple_set_location (stmt, loc);
}
+ else if (access->grp_to_be_debug_replaced)
+ {
+ gimple ds = gimple_build_debug_bind (get_access_replacement (access),
+ build_zero_cst (access->type),
+ gsi_stmt (*gsi));
+ if (insert_after)
+ gsi_insert_after (gsi, ds, GSI_NEW_STMT);
+ else
+ gsi_insert_before (gsi, ds, GSI_SAME_STMT);
+ }
for (child = access->first_child; child; child = child->next_sibling)
init_subtree_with_zero (child, gsi, insert_after, loc);
@@ -2646,6 +2753,13 @@ sra_modify_expr (tree *expr, gimple_stmt_iterator *gsi, bool write)
*expr = repl;
sra_stats.exprs++;
}
+ else if (write && access->grp_to_be_debug_replaced)
+ {
+ gimple ds = gimple_build_debug_bind (get_access_replacement (access),
+ NULL_TREE,
+ gsi_stmt (*gsi));
+ gsi_insert_after (gsi, ds, GSI_NEW_STMT);
+ }
if (access->first_child)
{
@@ -2721,10 +2835,11 @@ load_assign_lhs_subreplacements (struct access *lacc, struct access *top_racc,
location_t loc = gimple_location (gsi_stmt (*old_gsi));
for (lacc = lacc->first_child; lacc; lacc = lacc->next_sibling)
{
+ HOST_WIDE_INT offset = lacc->offset - left_offset + top_racc->offset;
+
if (lacc->grp_to_be_replaced)
{
struct access *racc;
- HOST_WIDE_INT offset = lacc->offset - left_offset + top_racc->offset;
gimple stmt;
tree rhs;
@@ -2764,10 +2879,34 @@ load_assign_lhs_subreplacements (struct access *lacc, struct access *top_racc,
update_stmt (stmt);
sra_stats.subreplacements++;
}
- else if (*refreshed == SRA_UDH_NONE
- && lacc->grp_read && !lacc->grp_covered)
- *refreshed = handle_unscalarized_data_in_subtree (top_racc,
- old_gsi);
+ else
+ {
+ if (*refreshed == SRA_UDH_NONE
+ && lacc->grp_read && !lacc->grp_covered)
+ *refreshed = handle_unscalarized_data_in_subtree (top_racc,
+ old_gsi);
+ if (lacc && lacc->grp_to_be_debug_replaced)
+ {
+ gimple ds;
+ tree drhs;
+ struct access *racc = find_access_in_subtree (top_racc, offset,
+ lacc->size);
+
+ if (racc && racc->grp_to_be_replaced)
+ drhs = get_access_replacement (racc);
+ else if (*refreshed == SRA_UDH_LEFT)
+ drhs = build_debug_ref_for_model (loc, lacc->base, lacc->offset,
+ lacc);
+ else if (*refreshed == SRA_UDH_RIGHT)
+ drhs = build_debug_ref_for_model (loc, top_racc->base, offset,
+ lacc);
+ else
+ drhs = NULL_TREE;
+ ds = gimple_build_debug_bind (get_access_replacement (lacc),
+ drhs, gsi_stmt (*old_gsi));
+ gsi_insert_after (new_gsi, ds, GSI_NEW_STMT);
+ }
+ }
if (lacc->first_child)
load_assign_lhs_subreplacements (lacc, top_racc, left_offset,
@@ -2982,6 +3121,13 @@ sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi)
}
}
+ if (lacc && lacc->grp_to_be_debug_replaced)
+ {
+ gimple ds = gimple_build_debug_bind (get_access_replacement (lacc),
+ unshare_expr (rhs), *stmt);
+ gsi_insert_before (gsi, ds, GSI_SAME_STMT);
+ }
+
/* From this point on, the function deals with assignments in between
aggregates when at least one has scalar reductions of some of its
components. There are three possible scenarios: Both the LHS and RHS have