tree-sra.c (sra_modify_expr): Generate new memory accesses with same alias type as the original statement.

2014-04-28  Martin Jambor  <mjambor@suse.cz>

	* tree-sra.c (sra_modify_expr): Generate new memory accesses with
	same alias type as the original statement.
	(subreplacement_assignment_data): New type.
	(handle_unscalarized_data_in_subtree): New type of parameter,
	generate new memory accesses with same alias type as the original
	statement.
	(load_assign_lhs_subreplacements): Likewise.
	(sra_modify_constructor_assign): Generate new memory accesses with
	same alias type as the original statement.

testsuite/
        * gcc.dg/tree-ssa/sra-14.c: New test.

From-SVN: r209868
This commit is contained in:
Martin Jambor 2014-04-28 18:55:40 +02:00 committed by Martin Jambor
parent 9358288555
commit 28151221b5
4 changed files with 187 additions and 76 deletions

View file

@ -1,3 +1,15 @@
2014-04-28 Martin Jambor <mjambor@suse.cz>
* tree-sra.c (sra_modify_expr): Generate new memory accesses with
same alias type as the original statement.
(subreplacement_assignment_data): New type.
(handle_unscalarized_data_in_subtree): New type of parameter,
generate new memory accesses with same alias type as the original
statement.
(load_assign_lhs_subreplacements): Likewise.
(sra_modify_constructor_assign): Generate new memory accesses with
same alias type as the original statement.
2014-04-28 Richard Biener <rguenther@suse.de> 2014-04-28 Richard Biener <rguenther@suse.de>
* tree-pass.h (TODO_verify_il): Define. * tree-pass.h (TODO_verify_il): Define.

View file

@ -1,3 +1,7 @@
2014-04-28 Martin Jambor <mjambor@suse.cz>
* gcc.dg/tree-ssa/sra-14.c: New test.
2014-04-28 Richard Biener <rguenther@suse.de> 2014-04-28 Richard Biener <rguenther@suse.de>
PR middle-end/60092 PR middle-end/60092

View file

@ -0,0 +1,70 @@
/* { dg-do run } */
/* { dg-options "-O1" } */
struct S
{
int i, j;
};
struct Z
{
struct S d, s;
};
struct S __attribute__ ((noinline, noclone))
get_s (void)
{
struct S s;
s.i = 5;
s.j = 6;
return s;
}
struct S __attribute__ ((noinline, noclone))
get_d (void)
{
struct S d;
d.i = 0;
d.j = 0;
return d;
}
int __attribute__ ((noinline, noclone))
get_c (void)
{
return 1;
}
int __attribute__ ((noinline, noclone))
my_nop (int i)
{
return i;
}
int __attribute__ ((noinline, noclone))
foo (void)
{
struct Z z;
int i, c = get_c ();
z.d = get_d ();
z.s = get_s ();
for (i = 0; i < c; i++)
{
z.s.i = my_nop (z.s.i);
z.s.j = my_nop (z.s.j);
}
return z.s.i + z.s.j;
}
int main (int argc, char *argv[])
{
if (foo () != 11)
__builtin_abort ();
return 0;
}

View file

@ -2769,7 +2769,7 @@ sra_modify_expr (tree *expr, gimple_stmt_iterator *gsi, bool write)
{ {
location_t loc; location_t loc;
struct access *access; struct access *access;
tree type, bfr; tree type, bfr, orig_expr;
if (TREE_CODE (*expr) == BIT_FIELD_REF) if (TREE_CODE (*expr) == BIT_FIELD_REF)
{ {
@ -2785,6 +2785,7 @@ sra_modify_expr (tree *expr, gimple_stmt_iterator *gsi, bool write)
if (!access) if (!access)
return false; return false;
type = TREE_TYPE (*expr); type = TREE_TYPE (*expr);
orig_expr = *expr;
loc = gimple_location (gsi_stmt (*gsi)); loc = gimple_location (gsi_stmt (*gsi));
gimple_stmt_iterator alt_gsi = gsi_none (); gimple_stmt_iterator alt_gsi = gsi_none ();
@ -2811,8 +2812,7 @@ sra_modify_expr (tree *expr, gimple_stmt_iterator *gsi, bool write)
{ {
tree ref; tree ref;
ref = build_ref_for_model (loc, access->base, access->offset, access, ref = build_ref_for_model (loc, orig_expr, 0, access, NULL, false);
NULL, false);
if (write) if (write)
{ {
@ -2863,7 +2863,7 @@ sra_modify_expr (tree *expr, gimple_stmt_iterator *gsi, bool write)
else else
start_offset = chunk_size = 0; start_offset = chunk_size = 0;
generate_subtree_copies (access->first_child, access->base, 0, generate_subtree_copies (access->first_child, orig_expr, access->offset,
start_offset, chunk_size, gsi, write, write, start_offset, chunk_size, gsi, write, write,
loc); loc);
} }
@ -2877,53 +2877,70 @@ enum unscalarized_data_handling { SRA_UDH_NONE, /* Nothing done so far. */
SRA_UDH_RIGHT, /* Data flushed to the RHS. */ SRA_UDH_RIGHT, /* Data flushed to the RHS. */
SRA_UDH_LEFT }; /* Data flushed to the LHS. */ SRA_UDH_LEFT }; /* Data flushed to the LHS. */
struct subreplacement_assignment_data
{
/* Offset of the access representing the lhs of the assignment. */
HOST_WIDE_INT left_offset;
/* LHS and RHS of the original assignment. */
tree assignment_lhs, assignment_rhs;
/* Access representing the rhs of the whole assignment. */
struct access *top_racc;
/* Stmt iterator used for statement insertions after the original assignment.
It points to the main GSI used to traverse a BB during function body
modification. */
gimple_stmt_iterator *new_gsi;
/* Stmt iterator used for statement insertions before the original
assignment. Keeps on pointing to the original statement. */
gimple_stmt_iterator old_gsi;
/* Location of the assignment. */
location_t loc;
/* Keeps the information whether we have needed to refresh replacements of
the LHS and from which side of the assignments this takes place. */
enum unscalarized_data_handling refreshed;
};
/* Store all replacements in the access tree rooted in TOP_RACC either to their /* 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 of the base aggregate if there are unscalarized data or directly to LHS of the
statement that is pointed to by GSI otherwise. */ statement that is pointed to by GSI otherwise. */
static enum unscalarized_data_handling static void
handle_unscalarized_data_in_subtree (struct access *top_racc, handle_unscalarized_data_in_subtree (struct subreplacement_assignment_data *sad)
gimple_stmt_iterator *gsi)
{ {
if (top_racc->grp_unscalarized_data) tree src;
if (sad->top_racc->grp_unscalarized_data)
{ {
generate_subtree_copies (top_racc->first_child, top_racc->base, 0, 0, 0, src = sad->assignment_rhs;
gsi, false, false, sad->refreshed = SRA_UDH_RIGHT;
gimple_location (gsi_stmt (*gsi)));
return SRA_UDH_RIGHT;
} }
else else
{ {
tree lhs = gimple_assign_lhs (gsi_stmt (*gsi)); src = sad->assignment_lhs;
generate_subtree_copies (top_racc->first_child, lhs, top_racc->offset, sad->refreshed = SRA_UDH_LEFT;
0, 0, gsi, false, false,
gimple_location (gsi_stmt (*gsi)));
return SRA_UDH_LEFT;
} }
generate_subtree_copies (sad->top_racc->first_child, src,
sad->top_racc->offset, 0, 0,
&sad->old_gsi, false, false, sad->loc);
} }
/* Try to generate statements to load all sub-replacements in an access subtree /* Try to generate statements to load all sub-replacements in an access subtree
formed by children of LACC from scalar replacements in the TOP_RACC subtree. formed by children of LACC from scalar replacements in the SAD->top_racc
If that is not possible, refresh the TOP_RACC base aggregate and load the subtree. If that is not possible, refresh the SAD->top_racc base aggregate
accesses from it. LEFT_OFFSET is the offset of the left whole subtree being and load the accesses from it. */
copied. NEW_GSI is stmt iterator used for statement insertions after the
original assignment, OLD_GSI is used to insert statements before the
assignment. *REFRESHED keeps the information whether we have needed to
refresh replacements of the LHS and from which side of the assignments this
takes place. */
static void static void
load_assign_lhs_subreplacements (struct access *lacc, struct access *top_racc, load_assign_lhs_subreplacements (struct access *lacc,
HOST_WIDE_INT left_offset, struct subreplacement_assignment_data *sad)
gimple_stmt_iterator *old_gsi,
gimple_stmt_iterator *new_gsi,
enum unscalarized_data_handling *refreshed)
{ {
location_t loc = gimple_location (gsi_stmt (*old_gsi));
for (lacc = lacc->first_child; lacc; lacc = lacc->next_sibling) for (lacc = lacc->first_child; lacc; lacc = lacc->next_sibling)
{ {
HOST_WIDE_INT offset = lacc->offset - left_offset + top_racc->offset; HOST_WIDE_INT offset;
offset = lacc->offset - sad->left_offset + sad->top_racc->offset;
if (lacc->grp_to_be_replaced) if (lacc->grp_to_be_replaced)
{ {
@ -2931,53 +2948,57 @@ load_assign_lhs_subreplacements (struct access *lacc, struct access *top_racc,
gimple stmt; gimple stmt;
tree rhs; tree rhs;
racc = find_access_in_subtree (top_racc, offset, lacc->size); racc = find_access_in_subtree (sad->top_racc, offset, lacc->size);
if (racc && racc->grp_to_be_replaced) if (racc && racc->grp_to_be_replaced)
{ {
rhs = get_access_replacement (racc); rhs = get_access_replacement (racc);
if (!useless_type_conversion_p (lacc->type, racc->type)) if (!useless_type_conversion_p (lacc->type, racc->type))
rhs = fold_build1_loc (loc, VIEW_CONVERT_EXPR, lacc->type, rhs); rhs = fold_build1_loc (sad->loc, VIEW_CONVERT_EXPR,
lacc->type, rhs);
if (racc->grp_partial_lhs && lacc->grp_partial_lhs) if (racc->grp_partial_lhs && lacc->grp_partial_lhs)
rhs = force_gimple_operand_gsi (old_gsi, rhs, true, NULL_TREE, rhs = force_gimple_operand_gsi (&sad->old_gsi, rhs, true,
true, GSI_SAME_STMT); NULL_TREE, true, GSI_SAME_STMT);
} }
else else
{ {
/* No suitable access on the right hand side, need to load from /* No suitable access on the right hand side, need to load from
the aggregate. See if we have to update it first... */ the aggregate. See if we have to update it first... */
if (*refreshed == SRA_UDH_NONE) if (sad->refreshed == SRA_UDH_NONE)
*refreshed = handle_unscalarized_data_in_subtree (top_racc, handle_unscalarized_data_in_subtree (sad);
old_gsi);
if (*refreshed == SRA_UDH_LEFT) if (sad->refreshed == SRA_UDH_LEFT)
rhs = build_ref_for_model (loc, lacc->base, lacc->offset, lacc, rhs = build_ref_for_model (sad->loc, sad->assignment_lhs,
new_gsi, true); lacc->offset - sad->left_offset,
lacc, sad->new_gsi, true);
else else
rhs = build_ref_for_model (loc, top_racc->base, offset, lacc, rhs = build_ref_for_model (sad->loc, sad->assignment_rhs,
new_gsi, true); lacc->offset - sad->left_offset,
lacc, sad->new_gsi, true);
if (lacc->grp_partial_lhs) if (lacc->grp_partial_lhs)
rhs = force_gimple_operand_gsi (new_gsi, rhs, true, NULL_TREE, rhs = force_gimple_operand_gsi (sad->new_gsi,
rhs, true, NULL_TREE,
false, GSI_NEW_STMT); false, GSI_NEW_STMT);
} }
stmt = gimple_build_assign (get_access_replacement (lacc), rhs); stmt = gimple_build_assign (get_access_replacement (lacc), rhs);
gsi_insert_after (new_gsi, stmt, GSI_NEW_STMT); gsi_insert_after (sad->new_gsi, stmt, GSI_NEW_STMT);
gimple_set_location (stmt, loc); gimple_set_location (stmt, sad->loc);
update_stmt (stmt); update_stmt (stmt);
sra_stats.subreplacements++; sra_stats.subreplacements++;
} }
else else
{ {
if (*refreshed == SRA_UDH_NONE if (sad->refreshed == SRA_UDH_NONE
&& lacc->grp_read && !lacc->grp_covered) && lacc->grp_read && !lacc->grp_covered)
*refreshed = handle_unscalarized_data_in_subtree (top_racc, handle_unscalarized_data_in_subtree (sad);
old_gsi);
if (lacc && lacc->grp_to_be_debug_replaced) if (lacc && lacc->grp_to_be_debug_replaced)
{ {
gimple ds; gimple ds;
tree drhs; tree drhs;
struct access *racc = find_access_in_subtree (top_racc, offset, struct access *racc = find_access_in_subtree (sad->top_racc,
offset,
lacc->size); lacc->size);
if (racc && racc->grp_to_be_replaced) if (racc && racc->grp_to_be_replaced)
@ -2987,27 +3008,26 @@ load_assign_lhs_subreplacements (struct access *lacc, struct access *top_racc,
else else
drhs = NULL; drhs = NULL;
} }
else if (*refreshed == SRA_UDH_LEFT) else if (sad->refreshed == SRA_UDH_LEFT)
drhs = build_debug_ref_for_model (loc, lacc->base, lacc->offset, drhs = build_debug_ref_for_model (sad->loc, lacc->base,
lacc); lacc->offset, lacc);
else if (*refreshed == SRA_UDH_RIGHT) else if (sad->refreshed == SRA_UDH_RIGHT)
drhs = build_debug_ref_for_model (loc, top_racc->base, offset, drhs = build_debug_ref_for_model (sad->loc, sad->top_racc->base,
lacc); offset, lacc);
else else
drhs = NULL_TREE; drhs = NULL_TREE;
if (drhs if (drhs
&& !useless_type_conversion_p (lacc->type, TREE_TYPE (drhs))) && !useless_type_conversion_p (lacc->type, TREE_TYPE (drhs)))
drhs = fold_build1_loc (loc, VIEW_CONVERT_EXPR, drhs = fold_build1_loc (sad->loc, VIEW_CONVERT_EXPR,
lacc->type, drhs); lacc->type, drhs);
ds = gimple_build_debug_bind (get_access_replacement (lacc), ds = gimple_build_debug_bind (get_access_replacement (lacc),
drhs, gsi_stmt (*old_gsi)); drhs, gsi_stmt (sad->old_gsi));
gsi_insert_after (new_gsi, ds, GSI_NEW_STMT); gsi_insert_after (sad->new_gsi, ds, GSI_NEW_STMT);
} }
} }
if (lacc->first_child) if (lacc->first_child)
load_assign_lhs_subreplacements (lacc, top_racc, left_offset, load_assign_lhs_subreplacements (lacc, sad);
old_gsi, new_gsi, refreshed);
} }
} }
@ -3053,7 +3073,7 @@ sra_modify_constructor_assign (gimple *stmt, gimple_stmt_iterator *gsi)
/* I have never seen this code path trigger but if it can happen the /* I have never seen this code path trigger but if it can happen the
following should handle it gracefully. */ following should handle it gracefully. */
if (access_has_children_p (acc)) if (access_has_children_p (acc))
generate_subtree_copies (acc->first_child, acc->base, 0, 0, 0, gsi, generate_subtree_copies (acc->first_child, lhs, acc->offset, 0, 0, gsi,
true, true, loc); true, true, loc);
return SRA_AM_MODIFIED; return SRA_AM_MODIFIED;
} }
@ -3261,7 +3281,7 @@ sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi)
|| stmt_ends_bb_p (*stmt)) || stmt_ends_bb_p (*stmt))
{ {
if (access_has_children_p (racc)) if (access_has_children_p (racc))
generate_subtree_copies (racc->first_child, racc->base, 0, 0, 0, generate_subtree_copies (racc->first_child, rhs, racc->offset, 0, 0,
gsi, false, false, loc); gsi, false, false, loc);
if (access_has_children_p (lacc)) if (access_has_children_p (lacc))
{ {
@ -3271,7 +3291,7 @@ sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi)
alt_gsi = gsi_start_edge (single_non_eh_succ (gsi_bb (*gsi))); alt_gsi = gsi_start_edge (single_non_eh_succ (gsi_bb (*gsi)));
gsi = &alt_gsi; gsi = &alt_gsi;
} }
generate_subtree_copies (lacc->first_child, lacc->base, 0, 0, 0, generate_subtree_copies (lacc->first_child, lhs, lacc->offset, 0, 0,
gsi, true, true, loc); gsi, true, true, loc);
} }
sra_stats.separate_lhs_rhs_handling++; sra_stats.separate_lhs_rhs_handling++;
@ -3301,21 +3321,26 @@ sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi)
&& !lacc->grp_unscalarizable_region && !lacc->grp_unscalarizable_region
&& !racc->grp_unscalarizable_region) && !racc->grp_unscalarizable_region)
{ {
gimple_stmt_iterator orig_gsi = *gsi; struct subreplacement_assignment_data sad;
enum unscalarized_data_handling refreshed;
sad.left_offset = lacc->offset;
sad.assignment_lhs = lhs;
sad.assignment_rhs = rhs;
sad.top_racc = racc;
sad.old_gsi = *gsi;
sad.new_gsi = gsi;
sad.loc = gimple_location (*stmt);
sad.refreshed = SRA_UDH_NONE;
if (lacc->grp_read && !lacc->grp_covered) if (lacc->grp_read && !lacc->grp_covered)
refreshed = handle_unscalarized_data_in_subtree (racc, gsi); handle_unscalarized_data_in_subtree (&sad);
else
refreshed = SRA_UDH_NONE;
load_assign_lhs_subreplacements (lacc, racc, lacc->offset, load_assign_lhs_subreplacements (lacc, &sad);
&orig_gsi, gsi, &refreshed); if (sad.refreshed != SRA_UDH_RIGHT)
if (refreshed != SRA_UDH_RIGHT)
{ {
gsi_next (gsi); gsi_next (gsi);
unlink_stmt_vdef (*stmt); unlink_stmt_vdef (*stmt);
gsi_remove (&orig_gsi, true); gsi_remove (&sad.old_gsi, true);
release_defs (*stmt); release_defs (*stmt);
sra_stats.deleted++; sra_stats.deleted++;
return SRA_AM_REMOVED; return SRA_AM_REMOVED;
@ -3344,7 +3369,7 @@ sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi)
/* Restore the aggregate RHS from its components so the /* Restore the aggregate RHS from its components so the
prevailing aggregate copy does the right thing. */ prevailing aggregate copy does the right thing. */
if (access_has_children_p (racc)) if (access_has_children_p (racc))
generate_subtree_copies (racc->first_child, racc->base, 0, 0, 0, generate_subtree_copies (racc->first_child, rhs, racc->offset, 0, 0,
gsi, false, false, loc); gsi, false, false, loc);
/* Re-load the components of the aggregate copy destination. /* Re-load the components of the aggregate copy destination.
But use the RHS aggregate to load from to expose more But use the RHS aggregate to load from to expose more